Skip to content

Commit facd5a0

Browse files
authored
implement messages based on private mssqldb (#41)
* implement messages based on private mssqldb * switch back to the primary driver source
1 parent cff4987 commit facd5a0

File tree

9 files changed

+134
-32
lines changed

9 files changed

+134
-32
lines changed

.vscode/launch.json

+8
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,13 @@
2626
"program": "${workspaceFolder}/cmd/sqlcmd",
2727
"args" : ["-Q", "EXIT(select 100 as Count)"],
2828
},
29+
{
30+
"name" : "Run file query",
31+
"type" : "go",
32+
"request": "launch",
33+
"mode" : "auto",
34+
"program": "${workspaceFolder}/cmd/sqlcmd",
35+
"args" : ["-i", "testdata\\select100.sql"],
36+
},
2937
]
3038
}

cmd/sqlcmd/main_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"github.com/stretchr/testify/require"
1414
)
1515

16+
const oneRowAffected = "(1 row affected)"
17+
1618
func newKong(t *testing.T, cli interface{}, options ...kong.Option) *kong.Kong {
1719
t.Helper()
1820
options = append([]kong.Option{
@@ -122,7 +124,7 @@ func TestRunInputFiles(t *testing.T) {
122124
assert.Equal(t, 0, exitCode, "exitCode")
123125
bytes, err := os.ReadFile(o.Name())
124126
if assert.NoError(t, err, "os.ReadFile") {
125-
assert.Equal(t, "100"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol+"100"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
127+
assert.Equal(t, "100"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol+oneRowAffected+sqlcmd.SqlcmdEol+"100"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol+oneRowAffected+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
126128
}
127129
}
128130

@@ -148,7 +150,7 @@ func TestQueryAndExit(t *testing.T) {
148150
assert.Equal(t, 0, exitCode, "exitCode")
149151
bytes, err := os.ReadFile(o.Name())
150152
if assert.NoError(t, err, "os.ReadFile") {
151-
assert.Equal(t, "100 val2"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
153+
assert.Equal(t, "100 val2"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol+oneRowAffected+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
152154
}
153155
}
154156

@@ -174,7 +176,7 @@ func TestAzureAuth(t *testing.T) {
174176
assert.Equal(t, 0, exitCode, "exitCode")
175177
bytes, err := os.ReadFile(o.Name())
176178
if assert.NoError(t, err, "os.ReadFile") {
177-
assert.Equal(t, "AZURE"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
179+
assert.Equal(t, "AZURE"+sqlcmd.SqlcmdEol+sqlcmd.SqlcmdEol+oneRowAffected+sqlcmd.SqlcmdEol, string(bytes), "Incorrect output from run")
178180
}
179181
}
180182

cmd/sqlcmd/testdata/create100db.sql

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
create database db100
2+
go
3+
4+
create database db101
5+
go
6+
7+
create database db102
8+
go
9+
create database db103
10+
go
11+
create database db104
12+
go
13+
create database db105
14+
go
15+
create database db106
16+
go
17+
create database db107
18+
go
19+
create database db108
20+
go
21+
create database db109
22+
go
23+
create database db110
24+
go
25+
create database db111
26+
go
27+
create database db112
28+
go
29+
create database db113
30+
go

cmd/sqlcmd/testdata/drop100db.txt

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
drop database db100
2+
go
3+
4+
drop database db101
5+
go
6+
7+
drop database db102
8+
go
9+
drop database db103
10+
go
11+
drop database db104
12+
go
13+
drop database db105
14+
go
15+
drop database db106
16+
go
17+
drop database db107
18+
go
19+
drop database db108
20+
go
21+
drop database db109
22+
go
23+
drop database db110
24+
go
25+
drop database db111
26+
go
27+
drop database db112
28+
go
29+
drop database db113
30+
go

go.mod

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ require (
88
github.com/alecthomas/kong v0.2.18-0.20210621093454-54558f65e86f
99
github.com/chzyer/logex v1.1.10 // indirect
1010
github.com/chzyer/test v0.0.0-20210722231415-061457976a23 // indirect
11-
github.com/denisenkom/go-mssqldb v0.10.0
11+
github.com/denisenkom/go-mssqldb v0.12.0
1212
github.com/gohxs/readline v0.0.0-20171011095936-a780388e6e7c
13+
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188
1314
github.com/google/uuid v1.2.0
1415
github.com/stretchr/testify v1.7.0
1516
)
17+

go.sum

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0 h1:OYa9vmRX2XC5GXRAzegg
44
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
55
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0 h1:v9p9TfTbf7AwNb5NYQt7hI41IfPoLFiFkLtb+bmGjT0=
66
github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
7-
github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0=
8-
github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
97
github.com/alecthomas/kong v0.2.18-0.20210621093454-54558f65e86f h1:VgRM6/wqZIB1D9W3XMllm/wplTmPgI5yvCHUXEsmKps=
108
github.com/alecthomas/kong v0.2.18-0.20210621093454-54558f65e86f/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
119
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
@@ -15,13 +13,15 @@ github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMn
1513
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1614
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1715
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
18-
github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8=
19-
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
16+
github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA=
17+
github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
2018
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
2119
github.com/gohxs/readline v0.0.0-20171011095936-a780388e6e7c h1:yE35fKFwcelIte3q5q1/cPiY7pI7vvf5/j/0ddxNCKs=
2220
github.com/gohxs/readline v0.0.0-20171011095936-a780388e6e7c/go.mod h1:9S/fKAutQ6wVHqm1jnp9D9sc5hu689s9AaTWFS92LaU=
2321
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
2422
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
23+
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4=
24+
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
2525
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
2626
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
2727
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
@@ -35,7 +35,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
3535
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
3636
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
3737
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
38-
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
3938
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E=
4039
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
4140
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=

pkg/sqlcmd/format.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,9 @@ func (f *sqlCmdFormatterType) AddRow(row *sql.Rows) string {
166166
}
167167

168168
// Writes a non-error message to the designated message writer
169-
func (f *sqlCmdFormatterType) AddMessage(string) {}
169+
func (f *sqlCmdFormatterType) AddMessage(msg string) {
170+
f.mustWriteOut(msg + SqlcmdEol)
171+
}
170172

171173
// Writes an error to the designated err Writer
172174
func (f *sqlCmdFormatterType) AddError(err error) {
@@ -273,7 +275,9 @@ func calcColumnDetails(cols []*sql.ColumnType, fixed int64, variable int64) (col
273275
} else {
274276
columnDetails[i].displayWidth = length
275277
}
276-
switch c.DatabaseTypeName() {
278+
typeName := c.DatabaseTypeName()
279+
280+
switch typeName {
277281
// Types with 0 size from sql.ColumnType
278282
case "BIT":
279283
columnDetails[i].leftJustify = false

pkg/sqlcmd/sqlcmd.go

+42-17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package sqlcmd
55

66
import (
77
"bufio"
8+
"context"
89
"database/sql"
910
"database/sql/driver"
1011
"errors"
@@ -20,6 +21,7 @@ import (
2021

2122
mssql "github.com/denisenkom/go-mssqldb"
2223
"github.com/gohxs/readline"
24+
"github.com/golang-sql/sqlexp"
2325
)
2426

2527
var (
@@ -450,33 +452,61 @@ func (s *Sqlcmd) sqlAuthentication() bool {
450452
func (s *Sqlcmd) runQuery(query string) int {
451453
retcode := -101
452454
s.Format.BeginBatch(query, s.vars, s.GetOutput(), s.GetError())
453-
rows, qe := s.db.Query(query)
455+
ctx := context.Background()
456+
retmsg := &sqlexp.ReturnMessage{}
457+
rows, qe := s.db.QueryContext(ctx, query, retmsg)
454458
if qe != nil {
455459
s.Format.AddError(qe)
456460
}
457461
var err error
458462
var cols []*sql.ColumnType
459463
results := true
464+
first := true
460465
for qe == nil && results {
461-
cols, err = rows.ColumnTypes()
462-
if err != nil {
463-
retcode = -100
464-
s.Format.AddError(err)
465-
} else {
466-
s.Format.BeginResultSet(cols)
467-
active := rows.Next()
468-
for active {
466+
msg := retmsg.Message(ctx)
467+
switch m := msg.(type) {
468+
case sqlexp.MsgNotice:
469+
s.Format.AddMessage(m.Message)
470+
case sqlexp.MsgError:
471+
s.Format.AddError(m.Error)
472+
case sqlexp.MsgRowsAffected:
473+
if m.Count == 1 {
474+
s.Format.AddMessage("(1 row affected)")
475+
} else {
476+
s.Format.AddMessage(fmt.Sprintf("(%d rows affected)", m.Count))
477+
}
478+
case sqlexp.MsgNextResultSet:
479+
results = rows.NextResultSet()
480+
if err = rows.Err(); err != nil {
481+
retcode = -100
482+
s.Format.AddError(err)
483+
}
484+
if results {
485+
first = true
486+
}
487+
case sqlexp.MsgNext:
488+
inresult := rows.Next()
489+
for inresult {
490+
if first {
491+
first = false
492+
cols, err = rows.ColumnTypes()
493+
if err != nil {
494+
retcode = -100
495+
s.Format.AddError(err)
496+
} else {
497+
s.Format.BeginResultSet(cols)
498+
}
499+
}
469500
col1 := s.Format.AddRow(rows)
470-
active = rows.Next()
471-
if !active {
501+
inresult = rows.Next()
502+
if !inresult {
472503
if col1 == "" {
473504
retcode = 0
474505
} else if _, cerr := fmt.Sscanf(col1, "%d", &retcode); cerr != nil {
475506
retcode = -102
476507
}
477508
}
478509
}
479-
480510
if retcode != -102 {
481511
if err = rows.Err(); err != nil {
482512
retcode = -100
@@ -485,11 +515,6 @@ func (s *Sqlcmd) runQuery(query string) int {
485515
}
486516
s.Format.EndResultSet()
487517
}
488-
results = rows.NextResultSet()
489-
if err = rows.Err(); err != nil {
490-
retcode = -100
491-
s.Format.AddError(err)
492-
}
493518
}
494519
s.Format.EndBatch()
495520
return retcode

pkg/sqlcmd/sqlcmd_test.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"github.com/stretchr/testify/assert"
1717
)
1818

19+
const oneRowAffected = "(1 row affected)"
20+
1921
func TestConnectionStringFromSqlCmd(t *testing.T) {
2022
type connectionStringTest struct {
2123
settings *ConnectSettings
@@ -159,7 +161,7 @@ func TestIncludeFileNoExecutions(t *testing.T) {
159161
assert.Equal(t, "select 'string' as title", s.batch.String(), "s.batch.String() after IncludeFile twobatchnoendinggo.sql false")
160162
bytes, err := os.ReadFile(file.Name())
161163
if assert.NoError(t, err, "os.ReadFile") {
162-
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol+"100"+SqlcmdEol+SqlcmdEol, string(bytes), "Incorrect output from Run")
164+
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol+"100"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol, string(bytes), "Incorrect output from Run")
163165
}
164166
}
165167
}
@@ -177,7 +179,7 @@ func TestIncludeFileProcessAll(t *testing.T) {
177179
assert.Equal(t, "", s.batch.String(), "s.batch.String() after IncludeFile twobatchwithgo.sql true")
178180
bytes, err := os.ReadFile(file.Name())
179181
if assert.NoError(t, err, "os.ReadFile") {
180-
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol, string(bytes), "Incorrect output from Run")
182+
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol, string(bytes), "Incorrect output from Run")
181183
}
182184
file, err = os.CreateTemp("", "sqlcmdout")
183185
defer os.Remove(file.Name())
@@ -189,7 +191,7 @@ func TestIncludeFileProcessAll(t *testing.T) {
189191
assert.Equal(t, "", s.batch.String(), "s.batch.String() after IncludeFile twobatchnoendinggo.sql true")
190192
bytes, err := os.ReadFile(file.Name())
191193
if assert.NoError(t, err, "os.ReadFile") {
192-
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol, string(bytes), "Incorrect output from Run")
194+
assert.Equal(t, "100"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol+"string"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol, string(bytes), "Incorrect output from Run")
193195
}
194196
}
195197
}
@@ -232,7 +234,7 @@ func TestExitInitialQuery(t *testing.T) {
232234
if assert.NoError(t, err, "s.Run(once = true)") {
233235
s.SetOutput(nil)
234236
o := buf.buf.String()
235-
assert.Equal(t, "1200 2100"+SqlcmdEol+SqlcmdEol, o, "Output")
237+
assert.Equal(t, "1200 2100"+SqlcmdEol+SqlcmdEol+oneRowAffected+SqlcmdEol, o, "Output")
236238
assert.Equal(t, 1200, s.Exitcode, "ExitCode")
237239
}
238240

0 commit comments

Comments
 (0)