From dad23d2a2b931673360a00d3810ceaea061fb4b0 Mon Sep 17 00:00:00 2001 From: David Shiflet Date: Wed, 4 Dec 2024 20:34:15 -0600 Subject: [PATCH] Feat: Add tracing data to prelogin and login7 packets (#228) * add traceid field to prelogin * add clientid and pid to login7 * add logging of conn id to tdsSession * fix go mod * fix test * update min Go to 118 Fixes #226 --- appveyor.yml | 2 +- bulkcopy.go | 2 +- go.mod | 4 +- go.sum | 90 ------------------------------------- msdsn/conn_str.go | 21 +++++++++ msdsn/conn_str_test.go | 6 ++- mssql.go | 44 +++++------------- session.go | 100 +++++++++++++++++++++++++++++++++++++++++ session_test.go | 84 ++++++++++++++++++++++++++++++++++ tds.go | 85 +++++++++++++++-------------------- tds_login_test.go | 44 +++++++++++------- token.go | 58 +++++++----------------- version.go | 2 +- 13 files changed, 306 insertions(+), 236 deletions(-) create mode 100644 session.go create mode 100644 session_test.go diff --git a/appveyor.yml b/appveyor.yml index ba39e314..8a66adbf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -11,7 +11,7 @@ environment: SQLUSER: sa SQLPASSWORD: Password12! DATABASE: test - GOVERSION: 117 + GOVERSION: 118 COLUMNENCRYPTION: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 RACE: -race -cpu 4 diff --git a/bulkcopy.go b/bulkcopy.go index ec0e9b8d..3008359f 100644 --- a/bulkcopy.go +++ b/bulkcopy.go @@ -627,6 +627,6 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) func (b *Bulk) dlogf(ctx context.Context, format string, v ...interface{}) { if b.Debug { - b.cn.sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf(format, v...)) + b.cn.sess.LogF(ctx, msdsn.LogDebug, format, v...) } } diff --git a/go.mod b/go.mod index f321fcce..59ede8a0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/microsoft/go-mssqldb -go 1.17 +go 1.18 require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 @@ -8,6 +8,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 github.com/golang-sql/sqlexp v0.1.0 + github.com/google/uuid v1.6.0 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/stretchr/testify v1.9.0 golang.org/x/crypto v0.24.0 @@ -21,7 +22,6 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect diff --git a/go.sum b/go.sum index f9ddaa4c..f36e1dff 100644 --- a/go.sum +++ b/go.sum @@ -1,36 +1,24 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.0/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.1/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= @@ -52,144 +40,66 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/msdsn/conn_str.go b/msdsn/conn_str.go index 460dd4e3..04653c27 100644 --- a/msdsn/conn_str.go +++ b/msdsn/conn_str.go @@ -14,6 +14,8 @@ import ( "strings" "time" "unicode" + + "github.com/google/uuid" ) type ( @@ -44,6 +46,8 @@ const ( LogTransaction Log = 32 LogDebug Log = 64 LogRetries Log = 128 + // LogSessionIDs tells the session logger to include activity id and connection id + LogSessionIDs Log = 0x8000 ) const ( @@ -79,6 +83,7 @@ const ( DialTimeout = "dial timeout" Pipe = "pipe" MultiSubnetFailover = "multisubnetfailover" + NoTraceID = "notraceid" ) type Config struct { @@ -131,6 +136,11 @@ type Config struct { ColumnEncryption bool // Attempt to connect to all IPs in parallel when MultiSubnetFailover is true MultiSubnetFailover bool + // guid to set as Activity Id in the prelogin packet. Defaults to a new value for each Config. + ActivityID []byte + // When true, no connection id or trace id value is sent in the prelogin packet. + // Some cloud servers may block connections that lack such values. + NoTraceID bool } func readDERFile(filename string) ([]byte, error) { @@ -285,6 +295,10 @@ func Parse(dsn string) (Config, error) { Protocols: []string{}, } + activityid, uerr := uuid.NewRandom() + if uerr == nil { + p.ActivityID = activityid[:] + } var params map[string]string var err error @@ -504,6 +518,13 @@ func Parse(dsn string) (Config, error) { // Defaulting to true to prevent breaking change although other client libraries default to false p.MultiSubnetFailover = true } + nti, ok := params[NoTraceID] + if ok { + notraceid, err := strconv.ParseBool(nti) + if err == nil { + p.NoTraceID = notraceid + } + } return p, nil } diff --git a/msdsn/conn_str_test.go b/msdsn/conn_str_test.go index f1bf03eb..232845df 100644 --- a/msdsn/conn_str_test.go +++ b/msdsn/conn_str_test.go @@ -105,9 +105,8 @@ func TestValidConnectionString(t *testing.T) { {"disableretry=1", func(p Config) bool { return p.DisableRetry }}, {"disableretry=0", func(p Config) bool { return !p.DisableRetry }}, {"", func(p Config) bool { return p.DisableRetry == disableRetryDefault }}, - {"MultiSubnetFailover=true", func(p Config) bool { return p.MultiSubnetFailover }}, + {"MultiSubnetFailover=true;NoTraceID=true", func(p Config) bool { return p.MultiSubnetFailover && p.NoTraceID }}, {"MultiSubnetFailover=false", func(p Config) bool { return !p.MultiSubnetFailover }}, - // those are supported currently, but maybe should not be {"someparam", func(p Config) bool { return true }}, {";;=;", func(p Config) bool { return true }}, @@ -226,6 +225,9 @@ func TestConnParseRoundTripFixed(t *testing.T) { if err != nil { t.Fatal("Params after roundtrip are not valid", err) } + t.Log("params.URL " + params.URL().String()) + params.ActivityID = nil + rtParams.ActivityID = nil if !reflect.DeepEqual(params, rtParams) { t.Fatal("Parameters do not match after roundtrip", params, rtParams) } diff --git a/mssql.go b/mssql.go index 2d940ddf..62aaa437 100644 --- a/mssql.go +++ b/mssql.go @@ -281,9 +281,7 @@ func (c *Conn) checkBadConn(ctx context.Context, err error, mayRetry bool) error } if !c.connectionGood && mayRetry && !c.connector.params.DisableRetry { - if c.sess.logFlags&logRetries != 0 { - c.sess.logger.Log(ctx, msdsn.LogRetries, err.Error()) - } + c.sess.Log(ctx, msdsn.LogRetries, err.Error) return newRetryableError(err) } @@ -324,9 +322,7 @@ func (c *Conn) sendCommitRequest() error { reset := c.resetSession c.resetSession = false if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { - if c.sess.logFlags&logErrors != 0 { - c.sess.logger.Log(c.transactionCtx, msdsn.LogErrors, fmt.Sprintf("Failed to send CommitXact with %v", err)) - } + c.sess.LogF(c.transactionCtx, msdsn.LogErrors, "Failed to send CommitXact with %v", err) c.connectionGood = false return fmt.Errorf("faild to send CommitXact: %v", err) } @@ -351,9 +347,7 @@ func (c *Conn) sendRollbackRequest() error { reset := c.resetSession c.resetSession = false if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, "", reset); err != nil { - if c.sess.logFlags&logErrors != 0 { - c.sess.logger.Log(c.transactionCtx, msdsn.LogErrors, fmt.Sprintf("Failed to send RollbackXact with %v", err)) - } + c.sess.LogF(c.transactionCtx, msdsn.LogErrors, "Failed to send RollbackXact with %v", err) c.connectionGood = false return fmt.Errorf("failed to send RollbackXact: %v", err) } @@ -388,9 +382,7 @@ func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) erro reset := c.resetSession c.resetSession = false if err := sendBeginXact(c.sess.buf, headers, tdsIsolation, "", reset); err != nil { - if c.sess.logFlags&logErrors != 0 { - c.sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Failed to send BeginXact with %v", err)) - } + c.sess.LogF(ctx, msdsn.LogErrors, "Failed to send BeginXact with %v", err) c.connectionGood = false return fmt.Errorf("failed to send BeginXact: %v", err) } @@ -524,15 +516,13 @@ func (s *Stmt) sendQuery(ctx context.Context, args []namedValue) (err error) { conn := s.c // no need to check number of parameters here, it is checked by database/sql - if conn.sess.logFlags&logSQL != 0 { - conn.sess.logger.Log(ctx, msdsn.LogSQL, s.query) - } + conn.sess.LogS(ctx, msdsn.LogSQL, s.query) if conn.sess.logFlags&logParams != 0 && len(args) > 0 { for i := 0; i < len(args); i++ { if len(args[i].Name) > 0 { - s.c.sess.logger.Log(ctx, msdsn.LogParams, fmt.Sprintf("\t@%s\t%v", args[i].Name, args[i].Value)) + s.c.sess.LogF(ctx, msdsn.LogParams, "\t@%s\t%v", args[i].Name, args[i].Value) } else { - s.c.sess.logger.Log(ctx, msdsn.LogParams, fmt.Sprintf("\t@p%d\t%v", i+1, args[i].Value)) + s.c.sess.LogF(ctx, msdsn.LogParams, "\t@p%d\t%v", i+1, args[i].Value) } } } @@ -542,9 +532,7 @@ func (s *Stmt) sendQuery(ctx context.Context, args []namedValue) (err error) { isProc := isProc(s.query) if len(args) == 0 && !isProc { if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil { - if conn.sess.logFlags&logErrors != 0 { - conn.sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Failed to send SqlBatch with %v", err)) - } + conn.sess.LogF(ctx, msdsn.LogErrors, "Failed to send SqlBatch with %v", err) conn.connectionGood = false return fmt.Errorf("failed to send SQL Batch: %v", err) } @@ -567,9 +555,7 @@ func (s *Stmt) sendQuery(ctx context.Context, args []namedValue) (err error) { params[1] = makeStrParam(strings.Join(decls, ",")) } if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil { - if conn.sess.logFlags&logErrors != 0 { - conn.sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Failed to send Rpc with %v", err)) - } + conn.sess.LogF(ctx, msdsn.LogErrors, "Failed to send Rpc with %v", err) conn.connectionGood = false return fmt.Errorf("failed to send RPC: %v", err) } @@ -1298,9 +1284,7 @@ func (rc *Rowsq) Columns() (res []string) { for { tok, err := rc.reader.nextToken() if err == nil { - if rc.reader.sess.logFlags&logDebug != 0 { - rc.reader.sess.logger.Log(rc.reader.ctx, msdsn.LogDebug, fmt.Sprintf("Columns() token type:%v", reflect.TypeOf(tok))) - } + rc.reader.sess.LogF(rc.reader.ctx, msdsn.LogDebug, "Columns() token type:%v", reflect.TypeOf(tok)) if tok == nil { return []string{} } else { @@ -1327,9 +1311,7 @@ func (rc *Rowsq) Next(dest []driver.Value) error { } for { tok, err := rc.reader.nextToken() - if rc.reader.sess.logFlags&logDebug != 0 { - rc.reader.sess.logger.Log(rc.reader.ctx, msdsn.LogDebug, fmt.Sprintf("Next() token type:%v", reflect.TypeOf(tok))) - } + rc.reader.sess.LogF(rc.reader.ctx, msdsn.LogDebug, "Next() token type:%v", reflect.TypeOf(tok)) if err == nil { if tok == nil { return io.EOF @@ -1391,9 +1373,7 @@ func (rc *Rowsq) NextResultSet() error { scan: for { tok, err := rc.reader.nextToken() - if rc.reader.sess.logFlags&logDebug != 0 { - rc.reader.sess.logger.Log(rc.reader.ctx, msdsn.LogDebug, fmt.Sprintf("NextResultSet() token type:%v", reflect.TypeOf(tok))) - } + rc.reader.sess.LogF(rc.reader.ctx, msdsn.LogDebug, "NextResultSet() token type:%v", reflect.TypeOf(tok)) if err != nil { return err diff --git a/session.go b/session.go new file mode 100644 index 00000000..33b06d89 --- /dev/null +++ b/session.go @@ -0,0 +1,100 @@ +package mssql + +import ( + "context" + "fmt" + + "github.com/google/uuid" + "github.com/microsoft/go-mssqldb/aecmk" + "github.com/microsoft/go-mssqldb/msdsn" +) + +func newSession(outbuf *tdsBuffer, logger ContextLogger, p msdsn.Config) *tdsSession { + sess := &tdsSession{ + buf: outbuf, + logger: logger, + logFlags: uint64(p.LogFlags), + aeSettings: &alwaysEncryptedSettings{keyProviders: aecmk.GetGlobalCekProviders()}, + } + _ = sess.activityid.Scan(p.ActivityID) + // generating a guid has a small chance of failure. Make a best effort + connid, cerr := uuid.NewRandom() + if cerr == nil { + _ = sess.connid.Scan(connid[:]) + } + + return sess +} + +func (s *tdsSession) preparePreloginFields(ctx context.Context, p msdsn.Config, fe *featureExtFedAuth) map[uint8][]byte { + instance_buf := []byte(p.Instance) + instance_buf = append(instance_buf, 0) // zero terminate instance name + + var encrypt byte + switch p.Encryption { + default: + panic(fmt.Errorf("Unsupported Encryption Config %v", p.Encryption)) + case msdsn.EncryptionDisabled: + encrypt = encryptNotSup + case msdsn.EncryptionRequired: + encrypt = encryptOn + case msdsn.EncryptionOff: + encrypt = encryptOff + case msdsn.EncryptionStrict: + encrypt = encryptStrict + } + v := getDriverVersion(driverVersion) + fields := map[uint8][]byte{ + // 4 bytes for version and 2 bytes for minor version + preloginVERSION: {byte(v), byte(v >> 8), byte(v >> 16), byte(v >> 24), 0, 0}, + preloginENCRYPTION: {encrypt}, + preloginINSTOPT: instance_buf, + preloginTHREADID: {0, 0, 0, 0}, + preloginMARS: {0}, // MARS disabled + } + + if !p.NoTraceID { + traceID := make([]byte, 36) // 16 byte connection id + 16 byte activity id + 4 byte sequence number + connid, _ := s.connid.Value() + activityid, _ := s.activityid.Value() + _ = copy(traceID[:16], connid.([]byte)) + _ = copy(traceID[16:32], activityid.([]byte)) + fields[preloginTRACEID] = traceID + if (s.logFlags)&logDebug != 0 { + msg := fmt.Sprintf("Creating prelogin packet with connection id '%s' and activity id '%s'", s.connid, s.activityid) + s.logger.Log(ctx, msdsn.LogDebug, msg) + } + } + if fe.FedAuthLibrary != FedAuthLibraryReserved { + fields[preloginFEDAUTHREQUIRED] = []byte{1} + } + + return fields +} + +type logFunc func() string + +func (s *tdsSession) logPrefix() string { + if s.logFlags&uint64(msdsn.LogSessionIDs) != 0 { + return fmt.Sprintf("aid:%v cid:%v - ", s.activityid, s.connid) + } + return "" +} + +func (s *tdsSession) LogS(ctx context.Context, category msdsn.Log, msg string) { + s.Log(ctx, category, func() string { return msg }) +} + +// Log checks that the session logFlags includes the category before evaluating the logFunc and emitting the trace +func (s *tdsSession) Log(ctx context.Context, category msdsn.Log, logFunc logFunc) { + if s.logFlags&uint64(category) != 0 { + s.logger.Log(ctx, category, s.logPrefix()+logFunc()) + } +} + +// LogF checks that the session logFlags includes the category before calling fmt.Sprintf and emitting the trace +func (s *tdsSession) LogF(ctx context.Context, category msdsn.Log, format string, a ...any) { + if s.logFlags&uint64(category) != 0 { + s.logger.Log(ctx, category, s.logPrefix()+fmt.Sprintf(format, a...)) + } +} diff --git a/session_test.go b/session_test.go new file mode 100644 index 00000000..4050ca63 --- /dev/null +++ b/session_test.go @@ -0,0 +1,84 @@ +package mssql + +import ( + "bytes" + "context" + "testing" + + "github.com/google/uuid" + "github.com/microsoft/go-mssqldb/msdsn" + "github.com/stretchr/testify/assert" +) + +func TestNewSession(t *testing.T) { + p := msdsn.Config{ + LogFlags: 32, + } + id, _ := uuid.Parse("5ac439f7-d5de-484c-8e0a-cbe27e7e9d72") + p.ActivityID = id[:] + buf := makeBuf(9, []byte{0x01 /*id*/, 0xFF /*status*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02 /*test byte*/}) + sess := newSession(buf, nil, p) + assert.Equal(t, uint64(32), sess.logFlags, "logFlags") + activityid, err := sess.activityid.Value() + if assert.NoError(t, err, "activityid.Value()") { + assert.Equal(t, p.ActivityID, activityid.([]byte), "activityid") + } + connidStr := sess.connid.String() + _, err = uuid.Parse(connidStr) + if assert.NoErrorf(t, err, "Invalid connid '%s'", connidStr) { + assert.NotEqual(t, "00000000-0000-0000-0000-000000000000", connidStr) + } +} + +func TestPreparePreloginFields(t *testing.T) { + p := msdsn.Config{ + LogFlags: 32, + Encryption: msdsn.EncryptionStrict, + Instance: "i", + } + fe := &featureExtFedAuth{FedAuthLibrary: FedAuthLibraryADAL} + // any 16 bytes would do + id, _ := uuid.Parse("5ac439f7-d5de-484c-8e0a-cbe27e7e9d72") + p.ActivityID = id[:] + buf := makeBuf(9, []byte{0x01 /*id*/, 0xFF /*status*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02 /*test byte*/}) + sess := newSession(buf, nil, p) + fields := sess.preparePreloginFields(context.Background(), p, fe) + assert.Equal(t, []byte{encryptStrict}, fields[preloginENCRYPTION], "preloginENCRYPTION") + assert.Equal(t, []byte{'i', 0}, fields[preloginINSTOPT], "preloginINSTOPT") + traceid := fields[preloginTRACEID] + assert.Equal(t, id[:], traceid[16:32], "activity id portion of preloginTRACEID") + var connid UniqueIdentifier + err := connid.Scan(traceid[:16]) + if assert.NoError(t, err, "invalid connection id portion of preloginTRACEID") { + assert.Equal(t, sess.connid.String(), connid.String(), "connection id portion of preloginTRACEID") + } + + assert.Equal(t, []byte{1}, fields[preloginFEDAUTHREQUIRED], "preloginFEDAUTHREQUIRED") +} + +func TestLog(t *testing.T) { + p := msdsn.Config{ + LogFlags: msdsn.LogErrors | msdsn.LogMessages | msdsn.LogSessionIDs, + Encryption: msdsn.EncryptionStrict, + Instance: "i", + } + // any 16 bytes would do + id, _ := uuid.Parse("5ac439f7-d5de-484c-8e0a-cbe27e7e9d72") + p.ActivityID = id[:] + buf := makeBuf(9, []byte{0x01 /*id*/, 0xFF /*status*/, 0x0, 0x9 /*size*/, 0xff, 0xff, 0xff, 0xff, 0x02 /*test byte*/}) + var captureBuf bytes.Buffer + + l := bufContextLogger{&captureBuf} + sess := newSession(buf, l, p) + ctx := context.Background() + sess.LogS(ctx, msdsn.LogDebug, "Debug") + assert.Empty(t, l.Buff.Bytes(), "Debug is masked out") + sess.LogS(ctx, msdsn.LogErrors, "Errors") + msg := l.Buff.String() + assert.Contains(t, msg, "aid:"+sess.activityid.String()+" cid:"+sess.connid.String(), "Message should include aid and cid") + assert.Contains(t, msg, "Errors") + l.Buff.Reset() + sess.LogF(ctx, msdsn.LogMessages, "format:%s", "value") + msg = l.Buff.String() + assert.Contains(t, msg, "format:value") +} diff --git a/tds.go b/tds.go index 312d412e..852c4d9f 100644 --- a/tds.go +++ b/tds.go @@ -9,6 +9,7 @@ import ( "io" "io/ioutil" "net" + "os" "sort" "strings" "time" @@ -172,6 +173,8 @@ type tdsSession struct { routedPort uint16 alwaysEncrypted bool aeSettings *alwaysEncryptedSettings + connid UniqueIdentifier + activityid UniqueIdentifier } type alwaysEncryptedSettings struct { @@ -299,13 +302,16 @@ func readPrelogin(r *tdsBuffer) (map[uint8][]byte, error) { break } - // read prelogin option data - value, err := readPreloginOptionData(plOption, struct_buf) - if err != nil { - return nil, err - } - results[plOption.token] = value + // TRACEID data is not returned from the server + if plOption.token != preloginTRACEID { + // read prelogin option data + value, err := readPreloginOptionData(plOption, struct_buf) + if err != nil { + return nil, err + } + results[plOption.token] = value + } offset += preloginOptionSize } return results, nil @@ -992,40 +998,6 @@ func dialConnection(ctx context.Context, c *Connector, p *msdsn.Config, logger C return } -func preparePreloginFields(p msdsn.Config, fe *featureExtFedAuth) map[uint8][]byte { - instance_buf := []byte(p.Instance) - instance_buf = append(instance_buf, 0) // zero terminate instance name - - var encrypt byte - switch p.Encryption { - default: - panic(fmt.Errorf("Unsupported Encryption Config %v", p.Encryption)) - case msdsn.EncryptionDisabled: - encrypt = encryptNotSup - case msdsn.EncryptionRequired: - encrypt = encryptOn - case msdsn.EncryptionOff: - encrypt = encryptOff - case msdsn.EncryptionStrict: - encrypt = encryptStrict - } - v := getDriverVersion(driverVersion) - fields := map[uint8][]byte{ - // 4 bytes for version and 2 bytes for minor version - preloginVERSION: {byte(v), byte(v >> 8), byte(v >> 16), byte(v >> 24), 0, 0}, - preloginENCRYPTION: {encrypt}, - preloginINSTOPT: instance_buf, - preloginTHREADID: {0, 0, 0, 0}, - preloginMARS: {0}, // MARS disabled - } - - if fe.FedAuthLibrary != FedAuthLibraryReserved { - fields[preloginFEDAUTHREQUIRED] = []byte{1} - } - - return fields -} - func interpretPreloginResponse(p msdsn.Config, fe *featureExtFedAuth, fields map[uint8][]byte) (encrypt byte, err error) { // If the server returns the preloginFEDAUTHREQUIRED field, then federated authentication // is supported. The actual value may be 0 or 1, where 0 means either SSPI or federated @@ -1084,7 +1056,9 @@ func prepareLogin(ctx context.Context, c *Connector, p msdsn.Config, logger Cont CtlIntName: "go-mssqldb", ClientProgVer: getDriverVersion(driverVersion), ChangePassword: p.ChangePassword, + ClientPID: uint32(os.Getpid()), } + getClientId(&l.ClientID) if p.ColumnEncryption { _ = l.FeatureExt.Add(&featureExtColumnEncryption{}) } @@ -1204,12 +1178,7 @@ initiate_connection: } isTransportEncrypted = true } - sess := tdsSession{ - buf: outbuf, - logger: logger, - logFlags: uint64(p.LogFlags), - aeSettings: &alwaysEncryptedSettings{keyProviders: aecmk.GetGlobalCekProviders()}, - } + sess := newSession(outbuf, logger, p) for i, p := range c.keyProviders { sess.aeSettings.keyProviders[i] = p @@ -1222,7 +1191,7 @@ initiate_connection: fedAuth.ADALWorkflow = c.fedAuthADALWorkflow } - fields := preparePreloginFields(p, fedAuth) + fields := sess.preparePreloginFields(ctx, p, fedAuth) err = writePrelogin(packPrelogin, outbuf, fields) if err != nil { @@ -1309,7 +1278,7 @@ initiate_connection: // SSPI and federated authentication scenarios may require multiple // packet exchanges to complete the login sequence. for loginAck := false; !loginAck; { - reader := startReading(&sess, ctx, outputs{}) + reader := startReading(sess, ctx, outputs{}) // don't send attention or wait for cancel confirmation during login reader.noAttn = true @@ -1406,7 +1375,7 @@ initiate_connection: } goto initiate_connection } - return &sess, nil + return sess, nil } type featureExtColumnEncryption struct { @@ -1426,3 +1395,21 @@ func (f *featureExtColumnEncryption) toBytes() []byte { */ return []byte{0x01} } + +// return the 6 byte hardware identifier for the LOGIN7 packet +func getClientId(mac *[6]byte) { + interfaces, err := net.Interfaces() + if err == nil { + for _, i := range interfaces { + if i.Flags&net.FlagUp != 0 && i.HardwareAddr != nil { + c := 6 + if len(i.HardwareAddr) < 6 { + c = len(i.HardwareAddr) + } + copy(mac[:], i.HardwareAddr[:c]) + return + } + } + } + return +} diff --git a/tds_login_test.go b/tds_login_test.go index 780ae589..9e3d25c7 100644 --- a/tds_login_test.go +++ b/tds_login_test.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net" + "os" "regexp" "sync/atomic" "testing" @@ -132,7 +133,7 @@ func testLoginSequenceServer(result chan error, conn net.Conn, expectedPackets, } func TestLoginWithSQLServerAuth(t *testing.T) { - conn, err := NewConnector("sqlserver://test:secret@localhost:1433?Workstation ID=localhost&log=128&protocol=tcp") + conn, err := NewConnector("sqlserver://test:secret@localhost:1433?Workstation ID=localhost&log=128&protocol=tcp¬raceid=true") if err != nil { t.Errorf("Unable to parse dummy DSN: %v", err) } @@ -140,24 +141,25 @@ func TestLoginWithSQLServerAuth(t *testing.T) { defer tl.StopLogging() SetLogger(&tl) v := versionToHexString(getDriverVersion(driverVersion)) + pid := versionToHexString(uint32(os.Getpid())) mock := NewMockTransportDialer( []string{ fmt.Sprintf("12 01 00 2f 00 00 01 00 00 00 1a 00 06 01 00 20\n"+ "00 01 02 00 21 00 01 03 00 22 00 04 04 00 26 00\n"+ "01 ff %s 00 00 00 00 00 00 00 00 00\n", v), fmt.Sprintf("10 01 00 c6 00 00 01 00 be 00 00 00 04 00 00 74\n"+ - "00 10 00 00 %s 00 00 00 00 00 00 00 00\n"+ + "00 10 00 00 %s %s 00 00 00 00\n"+ "A0 02 00 00 00 00 00 00 00 00 00 00 5e 00 09 00\n"+ "70 00 04 00 78 00 06 00 84 00 0a 00 98 00 09 00\n"+ "00 00 00 00 aa 00 0a 00 be 00 00 00 be 00 00 00\n"+ - "00 00 00 00 00 00 be 00 00 00 be 00 00 00 be 00\n"+ + "%s be 00 00 00 be 00 00 00 be 00\n"+ "00 00 00 00 00 00 6c 00 6f 00 63 00 61 00 6c 00\n"+ "68 00 6f 00 73 00 74 00 74 00 65 00 73 00 74 00\n"+ "92 a5 f3 a5 93 a5 82 a5 f3 a5 e2 a5 67 00 6f 00\n"+ "2d 00 6d 00 73 00 73 00 71 00 6c 00 64 00 62 00\n"+ "6c 00 6f 00 63 00 61 00 6c 00 68 00 6f 00 73 00\n"+ "74 00 67 00 6f 00 2d 00 6d 00 73 00 73 00 71 00\n"+ - "6c 00 64 00 62 00\n", v), + "6c 00 64 00 62 00\n", v, pid, clientIdToHexString()), }, []string{ " 04 01 00 20 00 00 01 00 00 00 10 00 06 01 00 16\n" + @@ -184,7 +186,7 @@ func TestLoginWithSQLServerAuth(t *testing.T) { } func TestLoginWithSecurityTokenAuth(t *testing.T) { - config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp") + config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp¬raceid=true") if err != nil { t.Fatal(err) } @@ -201,6 +203,7 @@ func TestLoginWithSecurityTokenAuth(t *testing.T) { defer tl.StopLogging() SetLogger(&tl) v := versionToHexString(getDriverVersion(driverVersion)) + pid := versionToHexString(uint32(os.Getpid())) mock := NewMockTransportDialer( []string{ fmt.Sprintf("12 01 00 35 00 00 01 00 00 00 1F 00 06 01 00 25\n"+ @@ -208,18 +211,18 @@ func TestLoginWithSecurityTokenAuth(t *testing.T) { "01 06 00 2c 00 01 ff %s 00 00 00 00 00\n"+ "00 00 00 00 01\n", v), fmt.Sprintf("10 01 00 CF 00 00 01 00 C7 00 00 00 04 00 00 74\n"+ - "00 10 00 00 %s 00 00 00 00 00 00 00 00\n"+ + "00 10 00 00 %s %s 00 00 00 00\n"+ "A0 02 00 10 00 00 00 00 00 00 00 00 5E 00 09 00\n"+ "70 00 00 00 70 00 00 00 70 00 0A 00 84 00 09 00\n"+ "AA 00 04 00 96 00 0A 00 AA 00 00 00 AA 00 00 00\n"+ - "00 00 00 00 00 00 AA 00 00 00 AA 00 00 00 AA 00\n"+ + "%s AA 00 00 00 AA 00 00 00 AA 00\n"+ "00 00 00 00 00 00 6C 00 6F 00 63 00 61 00 6C 00\n"+ "68 00 6F 00 73 00 74 00 67 00 6F 00 2D 00 6D 00\n"+ "73 00 73 00 71 00 6C 00 64 00 62 00 6C 00 6F 00\n"+ "63 00 61 00 6C 00 68 00 6F 00 73 00 74 00 67 00\n"+ "6F 00 2D 00 6D 00 73 00 73 00 71 00 6C 00 64 00\n"+ "62 00 AE 00 00 00 02 13 00 00 00 03 0E 00 00 00\n"+ - "3C 00 74 00 6F 00 6B 00 65 00 6E 00 3E 00 FF\n", v), + "3C 00 74 00 6F 00 6B 00 65 00 6E 00 3E 00 FF\n", v, pid, clientIdToHexString()), }, []string{ " 04 01 00 20 00 00 01 00 00 00 10 00 06 01 00 16\n" + @@ -246,7 +249,7 @@ func TestLoginWithSecurityTokenAuth(t *testing.T) { } func TestLoginWithADALUsernamePasswordAuth(t *testing.T) { - config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp") + config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp¬raceid=true") if err != nil { t.Fatal(err) } @@ -265,6 +268,7 @@ func TestLoginWithADALUsernamePasswordAuth(t *testing.T) { defer tl.StopLogging() SetLogger(&tl) v := versionToHexString(getDriverVersion(driverVersion)) + pid := versionToHexString(uint32(os.Getpid())) mock := NewMockTransportDialer( []string{ fmt.Sprintf("12 01 00 35 00 00 01 00 00 00 1F 00 06 01 00 25\n"+ @@ -272,17 +276,17 @@ func TestLoginWithADALUsernamePasswordAuth(t *testing.T) { "01 06 00 2C 00 01 ff %s 00 00 00 00 00\n"+ "00 00 00 00 01\n", v), fmt.Sprintf("10 01 00 BE 00 00 01 00 b6 00 00 00 04 00 00 74\n"+ - "00 10 00 00 %s 00 00 00 00 00 00 00 00\n"+ + "00 10 00 00 %s %s 00 00 00 00\n"+ "A0 02 00 10 00 00 00 00 00 00 00 00 5e 00 09 00\n"+ "70 00 00 00 70 00 00 00 70 00 0a 00 84 00 09 00\n"+ "AA 00 04 00 96 00 0A 00 AA 00 00 00 AA 00 00 00\n"+ - "00 00 00 00 00 00 AA 00 00 00 AA 00 00 00 AA 00\n"+ + "%s AA 00 00 00 AA 00 00 00 AA 00\n"+ "00 00 00 00 00 00 6c 00 6f 00 63 00 61 00 6c 00\n"+ "68 00 6f 00 73 00 74 00 67 00 6f 00 2d 00 6d 00\n"+ "73 00 73 00 71 00 6c 00 64 00 62 00 6c 00 6f 00\n"+ "63 00 61 00 6c 00 68 00 6f 00 73 00 74 00 67 00\n"+ "6f 00 2d 00 6d 00 73 00 73 00 71 00 6c 00 64 00\n"+ - "62 00 AE 00 00 00 02 02 00 00 00 05 01 ff\n", v), + "62 00 AE 00 00 00 02 02 00 00 00 05 01 ff\n", v, pid, clientIdToHexString()), " 08 01 00 1e 00 00 01 00 12 00 00 00 0e 00 00 00\n" + "3c 00 74 00 6f 00 6b 00 65 00 6e 00 3e 00\n", }, @@ -321,7 +325,7 @@ func TestLoginWithADALUsernamePasswordAuth(t *testing.T) { } func TestLoginWithADALManagedIdentityAuth(t *testing.T) { - config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp") + config, err := msdsn.Parse("sqlserver://localhost:1433?Workstation ID=localhost&log=128&protocol=tcp¬raceid=true") if err != nil { t.Fatal(err) } @@ -341,6 +345,7 @@ func TestLoginWithADALManagedIdentityAuth(t *testing.T) { SetLogger(&tl) v := versionToHexString(getDriverVersion(driverVersion)) + pid := versionToHexString(uint32(os.Getpid())) mock := NewMockTransportDialer( []string{ fmt.Sprintf("12 01 00 35 00 00 01 00 00 00 1F 00 06 01 00 25\n"+ @@ -348,17 +353,17 @@ func TestLoginWithADALManagedIdentityAuth(t *testing.T) { "01 06 00 2C 00 01 ff %s 00 00 00 00 00\n"+ "00 00 00 00 01\n", v), fmt.Sprintf("10 01 00 be 00 00 01 00 b6 00 00 00 04 00 00 74\n"+ - "00 10 00 00 %s 00 00 00 00 00 00 00 00\n"+ + "00 10 00 00 %s %s 00 00 00 00\n"+ "A0 02 00 10 00 00 00 00 00 00 00 00 5e 00 09 00\n"+ "70 00 00 00 70 00 00 00 70 00 0a 00 84 00 09 00\n"+ "AA 00 04 00 96 00 0A 00 AA 00 00 00 AA 00 00 00\n"+ - "00 00 00 00 00 00 AA 00 00 00 AA 00 00 00 AA 00\n"+ + "%s AA 00 00 00 AA 00 00 00 AA 00\n"+ "00 00 00 00 00 00 6c 00 6f 00 63 00 61 00 6c 00\n"+ "68 00 6f 00 73 00 74 00 67 00 6f 00 2d 00 6d 00\n"+ "73 00 73 00 71 00 6c 00 64 00 62 00 6c 00 6f 00\n"+ "63 00 61 00 6c 00 68 00 6f 00 73 00 74 00 67 00\n"+ "6f 00 2d 00 6d 00 73 00 73 00 71 00 6c 00 64 00\n"+ - "62 00 AE 00 00 00 02 02 00 00 00 05 03 ff\n", v), + "62 00 AE 00 00 00 02 02 00 00 00 05 03 ff\n", v, pid, clientIdToHexString()), " 08 01 00 1e 00 00 01 00 12 00 00 00 0e 00 00 00\n" + "3c 00 74 00 6f 00 6b 00 65 00 6e 00 3e 00\n", }, @@ -395,3 +400,10 @@ func TestLoginWithADALManagedIdentityAuth(t *testing.T) { t.Error(err) } } + +func clientIdToHexString() string { + var clientid [6]byte + getClientId(&clientid) + return hex.EncodeToString(clientid[:]) + +} diff --git a/token.go b/token.go index bf8fffc3..04a3e421 100644 --- a/token.go +++ b/token.go @@ -261,9 +261,7 @@ func processEnvChg(ctx context.Context, sess *tdsSession) { if err != nil { badStreamPanic(err) } - if sess.logFlags&logTransaction != 0 { - sess.logger.Log(ctx, msdsn.LogTransaction, fmt.Sprintf("BEGIN TRANSACTION %x", sess.tranid)) - } + sess.LogF(ctx, msdsn.LogTransaction, "BEGIN TRANSACTION %x", sess.tranid) _, err = readBVarByte(r) if err != nil { badStreamPanic(err) @@ -277,12 +275,10 @@ func processEnvChg(ctx context.Context, sess *tdsSession) { if err != nil { badStreamPanic(err) } - if sess.logFlags&logTransaction != 0 { - if envtype == envTypCommitTran { - sess.logger.Log(ctx, msdsn.LogTransaction, fmt.Sprintf("COMMIT TRANSACTION %x", sess.tranid)) - } else { - sess.logger.Log(ctx, msdsn.LogTransaction, fmt.Sprintf("ROLLBACK TRANSACTION %x", sess.tranid)) - } + if envtype == envTypCommitTran { + sess.LogF(ctx, msdsn.LogTransaction, "COMMIT TRANSACTION %x", sess.tranid) + } else { + sess.LogF(ctx, msdsn.LogTransaction, "ROLLBACK TRANSACTION %x", sess.tranid) } sess.tranid = 0 case envEnlistDTC: @@ -396,9 +392,7 @@ func processEnvChg(ctx context.Context, sess *tdsSession) { sess.routedPort = newPort default: // ignore rest of records because we don't know how to skip those - if sess.logFlags&logDebug != 0 { - sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf("WARN: Unknown ENVCHANGE record detected with type id = %d", envtype)) - } + sess.LogF(ctx, msdsn.LogDebug, "WARN: Unknown ENVCHANGE record detected with type id = %d", envtype) return } } @@ -948,9 +942,7 @@ func parseReturnValue(r *tdsBuffer, s *tdsSession) (nv namedValue) { func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenStruct, outs outputs) { defer func() { if err := recover(); err != nil { - if sess.logFlags&logErrors != 0 { - sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("Intercepted panic %v", err)) - } + sess.LogF(ctx, msdsn.LogErrors, "Intercepted panic %v", err) if outs.msgq != nil { var derr error switch e := err.(type) { @@ -969,9 +961,7 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS colsReceived := false packet_type, err := sess.buf.BeginRead() if err != nil { - if sess.logFlags&logErrors != 0 { - sess.logger.Log(ctx, msdsn.LogErrors, fmt.Sprintf("BeginRead failed %v", err)) - } + sess.LogF(ctx, msdsn.LogErrors, "BeginRead failed %v", err) switch e := err.(type) { case *net.OpError: err = e @@ -989,9 +979,7 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS errs := make([]Error, 0, 5) for tokens := 0; ; tokens += 1 { token := token(sess.buf.byte()) - if sess.logFlags&logDebug != 0 { - sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf("got token %v", token)) - } + sess.LogF(ctx, msdsn.LogDebug, "got token %v", token) switch token { case tokenSSPI: ch <- parseSSPIMsg(sess.buf) @@ -1016,9 +1004,7 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS ch <- done if done.Status&doneCount != 0 { - if sess.logFlags&logRows != 0 { - sess.logger.Log(ctx, msdsn.LogRows, fmt.Sprintf("(%d rows affected)", done.RowCount)) - } + sess.LogF(ctx, msdsn.LogRows, "(%d rows affected)", done.RowCount) if (colsReceived || done.CurCmd != cmdSelect) && outs.msgq != nil { _ = sqlexp.ReturnMessageEnqueue(ctx, outs.msgq, sqlexp.MsgRowsAffected{Count: int64(done.RowCount)}) @@ -1045,9 +1031,7 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS if outs.msgq != nil { errs = make([]Error, 0, 5) } - if sess.logFlags&logDebug != 0 { - sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf("got DONE or DONEPROC status=%d", done.Status)) - } + sess.LogF(ctx, msdsn.LogDebug, "got DONE or DONEPROC status=%d", done.Status) if done.Status&doneSrvError != 0 { ch <- ServerError{done.getError()} if outs.msgq != nil { @@ -1057,9 +1041,7 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS } ch <- done if done.Status&doneCount != 0 { - if sess.logFlags&logRows != 0 { - sess.logger.Log(ctx, msdsn.LogRows, fmt.Sprintf("(Rows affected: %d)", done.RowCount)) - } + sess.LogF(ctx, msdsn.LogRows, "(Rows affected: %d)", done.RowCount) if (colsReceived || done.CurCmd != cmdSelect) && outs.msgq != nil { _ = sqlexp.ReturnMessageEnqueue(ctx, outs.msgq, sqlexp.MsgRowsAffected{Count: int64(done.RowCount)}) @@ -1106,24 +1088,16 @@ func processSingleResponse(ctx context.Context, sess *tdsSession, ch chan tokenS processEnvChg(ctx, sess) case tokenError: err := parseError72(sess.buf) - if sess.logFlags&logDebug != 0 { - sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf("got ERROR %d %s", err.Number, err.Message)) - } + sess.LogF(ctx, msdsn.LogDebug, "got ERROR %d %s", err.Number, err.Message) errs = append(errs, err) - if sess.logFlags&logErrors != 0 { - sess.logger.Log(ctx, msdsn.LogErrors, err.Message) - } + sess.LogS(ctx, msdsn.LogErrors, err.Message) if outs.msgq != nil { _ = sqlexp.ReturnMessageEnqueue(ctx, outs.msgq, sqlexp.MsgError{Error: err}) } case tokenInfo: info := parseInfo(sess.buf) - if sess.logFlags&logDebug != 0 { - sess.logger.Log(ctx, msdsn.LogDebug, fmt.Sprintf("got INFO %d %s", info.Number, info.Message)) - } - if sess.logFlags&logMessages != 0 { - sess.logger.Log(ctx, msdsn.LogMessages, info.Message) - } + sess.LogF(ctx, msdsn.LogDebug, "got INFO %d %s", info.Number, info.Message) + sess.LogS(ctx, msdsn.LogMessages, info.Message) if outs.msgq != nil { _ = sqlexp.ReturnMessageEnqueue(ctx, outs.msgq, sqlexp.MsgNotice{Message: info}) } diff --git a/version.go b/version.go index 161b4dde..b8ccd7c7 100644 --- a/version.go +++ b/version.go @@ -4,7 +4,7 @@ import "fmt" // Update this variable with the release tag before pushing the tag // This value is written to the prelogin and login7 packets during a new connection -const driverVersion = "v1.7.0" +const driverVersion = "v1.8.0" func getDriverVersion(ver string) uint32 { var majorVersion uint32