diff --git a/go.mod b/go.mod index d02765fb10f44..004d85911d6f9 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module code.gitea.io/gitea go 1.12 require ( - github.com/BurntSushi/toml v0.3.1 // indirect github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 github.com/RoaringBitmap/roaring v0.4.7 // indirect github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca @@ -11,7 +10,6 @@ require ( github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 // indirect - github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/blevesearch/bleve v0.0.0-20190214220507-05d86ea8f6e3 github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 // indirect @@ -27,7 +25,7 @@ require ( github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f + github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946 github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 // indirect github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594 // indirect @@ -61,7 +59,6 @@ require ( github.com/go-xorm/xorm v0.0.0-20190116032649-a6300f2a45e0 github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 - github.com/gogo/protobuf v1.2.1 // indirect github.com/google/go-github/v24 v24.0.1 github.com/gorilla/context v1.1.1 github.com/issue9/assert v1.3.2 // indirect @@ -84,7 +81,6 @@ require ( github.com/mattn/go-isatty v0.0.7 github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d // indirect github.com/mattn/go-sqlite3 v1.10.0 - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae // indirect @@ -93,10 +89,7 @@ require ( github.com/philhofer/fwd v1.0.0 // indirect github.com/pkg/errors v0.8.1 // indirect github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e - github.com/prometheus/client_golang v0.9.0 - github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect - github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 // indirect - github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d // indirect + github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 // indirect github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect @@ -115,10 +108,10 @@ require ( github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 go.etcd.io/bbolt v1.3.2 // indirect golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 - golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 - golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 + golang.org/x/net v0.0.0-20190311183353-d8887717615a + golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e - golang.org/x/text v0.3.0 + golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 // indirect gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect @@ -136,6 +129,6 @@ require ( ) replace ( - github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 + github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946 github.com/go-sql-driver/mysql => github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f ) diff --git a/go.sum b/go.sum index 6b0a59d5b5138..8d05acc4dbf8d 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,16 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= +cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 h1:UsHpWO0Elp6NaWVARdZHjiYwkhrspHVEGsyIKPb9OI8= github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34/go.mod h1:T9ezsOHcCrDCgA8aF1Cqr3sSYbO/xgdy8/R/XiIMAhA= github.com/RoaringBitmap/roaring v0.4.7 h1:eGUudvFzvF7Kxh7JjYvXfI1f7l22/2duFby7r5+d4oc= github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca h1:xU8R31tsvj6TesCBog973+UgI3TXjh/LqN5clki6hcc= github.com/Unknwon/cae v0.0.0-20160715032808-c6aac99ea2ca/go.mod h1:IRSre9/SEhVuy972TVuJLyaPTS73+8Owhe0Y0l9NXHc= github.com/Unknwon/com v0.0.0-20190321035513-0fed4efef755 h1:1B7wb36fHLSwZfHg6ngZhhtIEHQjiC5H4p7qQGBEffg= @@ -15,10 +21,13 @@ github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141 h1:SSvHGK7iMpeyp github.com/Unknwon/paginater v0.0.0-20151104151617-7748a72e0141/go.mod h1:fw0McLecf/G5NFwddCRmDckU6yovtk1YsgWIoepMbYo= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 h1:4jHLmof+Hba81591gfH5xYA8QXzuvgksxwPNrmjR2BA= github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470/go.mod h1:3I+3V7B6gTBYfdpYgIG2ymALS9H+5VDKUl3lHH7ToM4= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= @@ -37,6 +46,7 @@ github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a h1:k5TuEkqEYCR github.com/bradfitz/gomemcache v0.0.0-20160117192205-fb1f79c6b65a/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f h1:REH9VH5ubNR0skLaOxK7TRJeRbE2dDfvaouQo8FsRcA= github.com/chaseadamsio/goorgeous v0.0.0-20170901132237-098da33fde5f/go.mod h1:6QaC0vFoKWYDth94dHFNgRT2YkT5FHdQp/Yx15aAAi0= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/couchbase/gomemcached v0.0.0-20181122193126-5125a94a666c h1:K4FIibkr4//ziZKOKmt4RL0YImuTjLLBtwElf+F2lSQ= @@ -56,10 +66,15 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0 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/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449 h1:JpA+YMG4JLW8nzLmU05mTiuB0O17xHGxpWolEZ0zDuA= -github.com/denisenkom/go-mssqldb v0.0.0-20161128230840-e32ca5036449/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946 h1:xn+jBHAqNYs6CnHhJwfWZQspPHMEL+LzUk0vpqWj6eo= +github.com/denisenkom/go-mssqldb v0.0.0-20190418034912-35416408c946/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= +github.com/denisenkom/go-mssqldb v0.0.0-20190514213226-23b29e59681b h1:IPnx9jcsslwYYmDIxCSjmvdhzRv3R9z8pfLC9htYoIY= +github.com/denisenkom/go-mssqldb v0.0.0-20190514213226-23b29e59681b/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac h1:xrQJVwQCGqDvOO7/0+RyIq5J2M3Q4ZF7Ug/BMQtML1E= github.com/dgrijalva/jwt-go v0.0.0-20161101193935-9ed569b5d1ac/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712 h1:aaQcKT9WumO6JEJcRyTqFVq4XUZiUcKR2/GI31TOcz8= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/go-bindata-assetfs v0.0.0-20151224045452-57eb5e1fc594 h1:McZ/pt/pP/XAbLMDQGzm/iQUwW6OXmKVbFtmH9klWmc= @@ -97,6 +112,8 @@ github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd h1:r04M github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e h1:SiEs4J3BKVIeaWrH3tKaz3QLZhJ68iJ/A4xrzIoE5+Y= github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3 h1:n0H90987ZwasTc9r/RnuaU1G5ePfzLG6Bkc1cY3KqnY= github.com/go-macaron/bindata v0.0.0-20161222093048-85786f57eee3/go.mod h1:NkmXhFuAlCOqgV5EWhU1DKLrgztCEIVXGmr2DZv/+sk= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76uRMLLlGVyb0hiYbgX1FM5+ur81TJWzIw= @@ -121,6 +138,7 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f h1:fbIzwEaXt5b2bl9mm+PIufKTSGKk6ZuwSSTQ7iZj7Lo= github.com/go-sql-driver/mysql v0.0.0-20181218123637-c45f530f8e7f/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-xorm/builder v0.3.2/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= github.com/go-xorm/builder v0.3.3 h1:v8grgrwOGv/iHXIEhIvOwHZIPLrpxRKSX8yWSMLFn/4= github.com/go-xorm/builder v0.3.3/go.mod h1:v8mE3MFBgtL+RGFNfUnAMUqqfk/Y4W5KuwCFQIEpQLk= @@ -134,12 +152,16 @@ github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561 h1:deE7ritpK04Pgtpy github.com/gogits/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:YgYOrVn3Nj9Tq0EvjmFbphRytDj7JNRoWSStJZWDJTQ= github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183 h1:EBTlva3AOSb80G3JSwY6ZMdILEZJ1JKuewrbqrNjWuE= github.com/gogits/cron v0.0.0-20160810035002-7f3990acf183/go.mod h1:pX+V62FFmklia2fhP3P4YSY6iJdPO5jIDKFQ5fEd5QE= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= @@ -148,6 +170,9 @@ github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju5 github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1ks85zJ1lfDGgIiMDuIptTOhJq+zKyg= @@ -162,6 +187,7 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE= github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/issue9/assert v1.3.2 h1:IaTa37u4m1fUuTH9K9ldO5IONKVDXjLiUO1T9vj0OF0= @@ -182,16 +208,17 @@ github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 h1:vE7J1m7cCpiRVEIr1B5ccDxRpbPsWT5JU3if2Di5nE4= github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6 h1:9mszGwKDxHEY2cy+9XxCQKWIfkGPSAEFrcN8ghzyAKg= github.com/keybase/go-crypto v0.0.0-20170605145657-00ac4db533f6/go.mod h1:ghbZscTyKdM07+Fw3KSi0hcJm+AlEUWj8QLlPtijN/M= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f h1:tCnZKEmDovgV4jmsclh6CuKk9AMzTzyVWfejgkgccVg= github.com/klauspost/compress v0.0.0-20161025140425-8df558b6cb6f/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -199,6 +226,8 @@ github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc h1:WW8B7p7QBnFlqRV github.com/klauspost/cpuid v0.0.0-20160302075316-09cded8978dc/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6 h1:KAZ1BW2TCmT6PRihDPpocIy1QTtsAsrx6TneU/4+CMg= github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -242,6 +271,7 @@ github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbM github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc h1:z1PgdCCmYYVL0BoJTUgmAq1p7ca8fzYIPsNyfsN3xAU= github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY= github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -249,10 +279,12 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -260,14 +292,20 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e h1:ApqncJ84HYN8x8x5WV1T1YWDuPRF/0aXZhr91LnRMCQ= github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e/go.mod h1:Zad1CMQfSQZI5KLpahDiSUX4tMMREnXw98IvL1nhgMk= -github.com/prometheus/client_golang v0.9.0 h1:tXuTFVHC03mW0D+Ua1Q2d1EAVqLTuggX50V0VLICCzY= -github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39 h1:Cto4X6SVMWRPBkJ/3YHn1iDGDGc/Z+sW+AEMKHMVvN4= -github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d h1:GoAlyOgbOEIFdaDqxJVlbOQ1DtGmZWs/Qau0hIlk+WQ= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ= github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/russross/blackfriday v0.0.0-20180428102519-11635eb403ff h1:g9ZlAHmkc/h5So+OjNCkZWh+FjuKEOOOoyRkqlGA8+c= @@ -284,6 +322,7 @@ github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc h1: github.com/shurcooL/sanitized_anchor_name v0.0.0-20160918041101-1dba4b3954bc/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 h1:Jpy1PXuP99tXNrhbq2BaPz9B+jNAvH1JPQQpG/9GCXY= @@ -297,6 +336,7 @@ github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 h1:JNEGSiWg6D3lcBC github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2/go.mod h1:mjqs7N0Q6m5HpR7QfXVBZXZWSqTjQLeTujjA/xUp2uw= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= @@ -321,35 +361,65 @@ github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2 h1:Z/90sZLPOeCy2PwprqkFa25PdkusRzaj9P8zm/KNyvk= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480 h1:O5YqonU5IWby+w98jVUG9h7zlCWCcH4RHyPVReBmhzk= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519 h1:x6rhz8Y9CjbgQkccRGmELH6K+LJj7tOoh3XWeC1yaQM= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759 h1:TMrx+Qdx7uJAeUbv15N72h5Hmyb5+VDjEiMufAEAM04= -golang.org/x/oauth2 v0.0.0-20181101160152-c453e0c75759/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 h1:nn6Zav2sOQHCFJHEspya8KqxhFwKci30UxHy3HXPTyQ= @@ -390,6 +460,11 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= mvdan.cc/xurls/v2 v2.0.0 h1:r1zSOSNS/kqtpmATyMMMvaZ4/djsesbYz5kr0+qMRWc= mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= strk.kbt.io/projects/go/libravatar v0.0.0-20160628055650-5eed7bff870a h1:8q33ShxKXRwQ7JVd1ZnhIU3hZhwwn0Le+4fTeAackuM= diff --git a/vendor/cloud.google.com/go/AUTHORS b/vendor/cloud.google.com/go/AUTHORS new file mode 100644 index 0000000000000..c364af1da0953 --- /dev/null +++ b/vendor/cloud.google.com/go/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of cloud authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. + +Filippo Valsorda +Google Inc. +Ingo Oeser +Palm Stone Games, Inc. +Paweł Knap +Péter Szilágyi +Tyler Treat diff --git a/vendor/cloud.google.com/go/CONTRIBUTORS b/vendor/cloud.google.com/go/CONTRIBUTORS new file mode 100644 index 0000000000000..3b3cbed98e9a9 --- /dev/null +++ b/vendor/cloud.google.com/go/CONTRIBUTORS @@ -0,0 +1,40 @@ +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# Names should be added to this file as: +# Name + +# Keep the list alphabetically sorted. + +Alexis Hunt +Andreas Litt +Andrew Gerrand +Brad Fitzpatrick +Burcu Dogan +Dave Day +David Sansome +David Symonds +Filippo Valsorda +Glenn Lewis +Ingo Oeser +James Hall +Johan Euphrosine +Jonathan Amsterdam +Kunpei Sakai +Luna Duclos +Magnus Hiie +Mario Castro +Michael McGreevy +Omar Jarjur +Paweł Knap +Péter Szilágyi +Sarah Adams +Thanatat Tamtan +Toby Burress +Tuo Shan +Tyler Treat diff --git a/vendor/cloud.google.com/go/LICENSE b/vendor/cloud.google.com/go/LICENSE new file mode 100644 index 0000000000000..d645695673349 --- /dev/null +++ b/vendor/cloud.google.com/go/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/cloud.google.com/go/civil/civil.go b/vendor/cloud.google.com/go/civil/civil.go new file mode 100644 index 0000000000000..29272ef26a313 --- /dev/null +++ b/vendor/cloud.google.com/go/civil/civil.go @@ -0,0 +1,277 @@ +// Copyright 2016 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package civil implements types for civil time, a time-zone-independent +// representation of time that follows the rules of the proleptic +// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second +// minutes. +// +// Because they lack location information, these types do not represent unique +// moments or intervals of time. Use time.Time for that purpose. +package civil + +import ( + "fmt" + "time" +) + +// A Date represents a date (year, month, day). +// +// This type does not include location information, and therefore does not +// describe a unique 24-hour timespan. +type Date struct { + Year int // Year (e.g., 2014). + Month time.Month // Month of the year (January = 1, ...). + Day int // Day of the month, starting at 1. +} + +// DateOf returns the Date in which a time occurs in that time's location. +func DateOf(t time.Time) Date { + var d Date + d.Year, d.Month, d.Day = t.Date() + return d +} + +// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents. +func ParseDate(s string) (Date, error) { + t, err := time.Parse("2006-01-02", s) + if err != nil { + return Date{}, err + } + return DateOf(t), nil +} + +// String returns the date in RFC3339 full-date format. +func (d Date) String() string { + return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) +} + +// IsValid reports whether the date is valid. +func (d Date) IsValid() bool { + return DateOf(d.In(time.UTC)) == d +} + +// In returns the time corresponding to time 00:00:00 of the date in the location. +// +// In is always consistent with time.Date, even when time.Date returns a time +// on a different day. For example, if loc is America/Indiana/Vincennes, then both +// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc) +// and +// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc) +// return 23:00:00 on April 30, 1955. +// +// In panics if loc is nil. +func (d Date) In(loc *time.Location) time.Time { + return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc) +} + +// AddDays returns the date that is n days in the future. +// n can also be negative to go into the past. +func (d Date) AddDays(n int) Date { + return DateOf(d.In(time.UTC).AddDate(0, 0, n)) +} + +// DaysSince returns the signed number of days between the date and s, not including the end day. +// This is the inverse operation to AddDays. +func (d Date) DaysSince(s Date) (days int) { + // We convert to Unix time so we do not have to worry about leap seconds: + // Unix time increases by exactly 86400 seconds per day. + deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix() + return int(deltaUnix / 86400) +} + +// Before reports whether d1 occurs before d2. +func (d1 Date) Before(d2 Date) bool { + if d1.Year != d2.Year { + return d1.Year < d2.Year + } + if d1.Month != d2.Month { + return d1.Month < d2.Month + } + return d1.Day < d2.Day +} + +// After reports whether d1 occurs after d2. +func (d1 Date) After(d2 Date) bool { + return d2.Before(d1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of d.String(). +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The date is expected to be a string in a format accepted by ParseDate. +func (d *Date) UnmarshalText(data []byte) error { + var err error + *d, err = ParseDate(string(data)) + return err +} + +// A Time represents a time with nanosecond precision. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +// +// This type exists to represent the TIME type in storage-based APIs like BigQuery. +// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type. +type Time struct { + Hour int // The hour of the day in 24-hour format; range [0-23] + Minute int // The minute of the hour; range [0-59] + Second int // The second of the minute; range [0-59] + Nanosecond int // The nanosecond of the second; range [0-999999999] +} + +// TimeOf returns the Time representing the time of day in which a time occurs +// in that time's location. It ignores the date. +func TimeOf(t time.Time) Time { + var tm Time + tm.Hour, tm.Minute, tm.Second = t.Clock() + tm.Nanosecond = t.Nanosecond() + return tm +} + +// ParseTime parses a string and returns the time value it represents. +// ParseTime accepts an extended form of the RFC3339 partial-time format. After +// the HH:MM:SS part of the string, an optional fractional part may appear, +// consisting of a decimal point followed by one to nine decimal digits. +// (RFC3339 admits only one digit after the decimal point). +func ParseTime(s string) (Time, error) { + t, err := time.Parse("15:04:05.999999999", s) + if err != nil { + return Time{}, err + } + return TimeOf(t), nil +} + +// String returns the date in the format described in ParseTime. If Nanoseconds +// is zero, no fractional part will be generated. Otherwise, the result will +// end with a fractional part consisting of a decimal point and nine digits. +func (t Time) String() string { + s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second) + if t.Nanosecond == 0 { + return s + } + return s + fmt.Sprintf(".%09d", t.Nanosecond) +} + +// IsValid reports whether the time is valid. +func (t Time) IsValid() bool { + // Construct a non-zero time. + tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC) + return TimeOf(tm) == t +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of t.String(). +func (t Time) MarshalText() ([]byte, error) { + return []byte(t.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The time is expected to be a string in a format accepted by ParseTime. +func (t *Time) UnmarshalText(data []byte) error { + var err error + *t, err = ParseTime(string(data)) + return err +} + +// A DateTime represents a date and time. +// +// This type does not include location information, and therefore does not +// describe a unique moment in time. +type DateTime struct { + Date Date + Time Time +} + +// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub. + +// DateTimeOf returns the DateTime in which a time occurs in that time's location. +func DateTimeOf(t time.Time) DateTime { + return DateTime{ + Date: DateOf(t), + Time: TimeOf(t), + } +} + +// ParseDateTime parses a string and returns the DateTime it represents. +// ParseDateTime accepts a variant of the RFC3339 date-time format that omits +// the time offset but includes an optional fractional time, as described in +// ParseTime. Informally, the accepted format is +// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF] +// where the 'T' may be a lower-case 't'. +func ParseDateTime(s string) (DateTime, error) { + t, err := time.Parse("2006-01-02T15:04:05.999999999", s) + if err != nil { + t, err = time.Parse("2006-01-02t15:04:05.999999999", s) + if err != nil { + return DateTime{}, err + } + } + return DateTimeOf(t), nil +} + +// String returns the date in the format described in ParseDate. +func (dt DateTime) String() string { + return dt.Date.String() + "T" + dt.Time.String() +} + +// IsValid reports whether the datetime is valid. +func (dt DateTime) IsValid() bool { + return dt.Date.IsValid() && dt.Time.IsValid() +} + +// In returns the time corresponding to the DateTime in the given location. +// +// If the time is missing or ambigous at the location, In returns the same +// result as time.Date. For example, if loc is America/Indiana/Vincennes, then +// both +// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc) +// and +// civil.DateTime{ +// civil.Date{Year: 1955, Month: time.May, Day: 1}}, +// civil.Time{Minute: 30}}.In(loc) +// return 23:30:00 on April 30, 1955. +// +// In panics if loc is nil. +func (dt DateTime) In(loc *time.Location) time.Time { + return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc) +} + +// Before reports whether dt1 occurs before dt2. +func (dt1 DateTime) Before(dt2 DateTime) bool { + return dt1.In(time.UTC).Before(dt2.In(time.UTC)) +} + +// After reports whether dt1 occurs after dt2. +func (dt1 DateTime) After(dt2 DateTime) bool { + return dt2.Before(dt1) +} + +// MarshalText implements the encoding.TextMarshaler interface. +// The output is the result of dt.String(). +func (dt DateTime) MarshalText() ([]byte, error) { + return []byte(dt.String()), nil +} + +// UnmarshalText implements the encoding.TextUnmarshaler interface. +// The datetime is expected to be a string in a format accepted by ParseDateTime +func (dt *DateTime) UnmarshalText(data []byte) error { + var err error + *dt, err = ParseDateTime(string(data)) + return err +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/README.md b/vendor/github.com/denisenkom/go-mssqldb/README.md index 8570ae9f615d5..e211cbf5828f4 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/README.md +++ b/vendor/github.com/denisenkom/go-mssqldb/README.md @@ -1,78 +1,210 @@ # A pure Go MSSQL driver for Go's database/sql package +[![GoDoc](https://godoc.org/github.com/denisenkom/go-mssqldb?status.svg)](http://godoc.org/github.com/denisenkom/go-mssqldb) +[![Build status](https://ci.appveyor.com/api/projects/status/jrln8cs62wj9i0a2?svg=true)](https://ci.appveyor.com/project/denisenkom/go-mssqldb) +[![codecov](https://codecov.io/gh/denisenkom/go-mssqldb/branch/master/graph/badge.svg)](https://codecov.io/gh/denisenkom/go-mssqldb) + ## Install - go get github.com/denisenkom/go-mssqldb +Requires Go 1.8 or above. -## Tests +Install with `go get github.com/denisenkom/go-mssqldb` . -`go test` is used for testing. A running instance of MSSQL server is required. -Environment variables are used to pass login information. +## Connection Parameters and DSN -Example: +The recommended connection string uses a URL format: +`sqlserver://username:password@host/instance?param1=value¶m2=value` +Other supported formats are listed below. + +### Common parameters: + +* `user id` - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. +* `password` +* `database` +* `connection timeout` - in seconds (default is 0 for no timeout), set to 0 for no timeout. Recommended to set to 0 and use context to manage query and connection timeouts. +* `dial timeout` - in seconds (default is 15), set to 0 for no timeout +* `encrypt` + * `disable` - Data send between client and server is not encrypted. + * `false` - Data sent between client and server is not encrypted beyond the login packet. (Default) + * `true` - Data sent between client and server is encrypted. +* `app name` - The application name (default is go-mssqldb) - env HOST=localhost SQLUSER=sa SQLPASSWORD=sa DATABASE=test go test - -## Connection Parameters - -* "server" - host or host\instance (default localhost) -* "port" - used only when there is no instance in server (default 1433) -* "failoverpartner" - host or host\instance (default is no partner). -* "failoverport" - used only when there is no instance in failoverpartner (default 1433) -* "user id" - enter the SQL Server Authentication user id or the Windows Authentication user id in the DOMAIN\User format. On Windows, if user id is empty or missing Single-Sign-On is used. -* "password" -* "database" -* "connection timeout" - in seconds (default is 30) -* "dial timeout" - in seconds (default is 5) -* "keepAlive" - in seconds; 0 to disable (default is 0) -* "log" - logging flags (default 0/no logging, 63 for full logging) +### Connection parameters for ODBC and ADO style connection strings: + +* `server` - host or host\instance (default localhost) +* `port` - used only when there is no instance in server (default 1433) + +### Less common parameters: + +* `keepAlive` - in seconds; 0 to disable (default is 30) +* `failoverpartner` - host or host\instance (default is no partner). +* `failoverport` - used only when there is no instance in failoverpartner (default 1433) +* `packet size` - in bytes; 512 to 32767 (default is 4096) + * Encrypted connections have a maximum packet size of 16383 bytes + * Further information on usage: https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option +* `log` - logging flags (default 0/no logging, 63 for full logging) * 1 log errors * 2 log messages * 4 log rows affected * 8 trace sql statements * 16 log statement parameters * 32 log transaction begin/end -* "encrypt" - * disable - Data send between client and server is not encrypted. - * false - Data sent between client and server is not encrypted beyond the login packet. (Default) - * true - Data sent between client and server is encrypted. -* "TrustServerCertificate" +* `TrustServerCertificate` * false - Server certificate is checked. Default is false if encypt is specified. * true - Server certificate is not checked. Default is true if encrypt is not specified. If trust server certificate is true, driver accepts any certificate presented by the server and any host name in that certificate. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing. -* "certificate" - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. -* "hostNameInCertificate" - Specifies the Common Name (CN) in the server certificate. Default value is the server host. -* "ServerSPN" - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. -* "Workstation ID" - The workstation name (default is the host name) -* "app name" - The application name (default is go-mssqldb) -* "ApplicationIntent" - Can be given the value "ReadOnly" to initiate a read-only connection to an Availability Group listener. +* `certificate` - The file that contains the public key certificate of the CA that signed the SQL Server certificate. The specified certificate overrides the go platform specific CA certificates. +* `hostNameInCertificate` - Specifies the Common Name (CN) in the server certificate. Default value is the server host. +* `ServerSPN` - The kerberos SPN (Service Principal Name) for the server. Default is MSSQLSvc/host:port. +* `Workstation ID` - The workstation name (default is the host name) +* `ApplicationIntent` - Can be given the value `ReadOnly` to initiate a read-only connection to an Availability Group listener. -Example: +### The connection string can be specified in one of three formats: + + +1. URL: with `sqlserver` scheme. username and password appears before the host. Any instance appears as + the first segment in the path. All other options are query parameters. Examples: + + * `sqlserver://username:password@host/instance?param1=value¶m2=value` + * `sqlserver://username:password@host:port?param1=value¶m2=value` + * `sqlserver://sa@localhost/SQLExpress?database=master&connection+timeout=30` // `SQLExpress instance. + * `sqlserver://sa:mypass@localhost?database=master&connection+timeout=30` // username=sa, password=mypass. + * `sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30` // port 1234 on localhost. + * `sqlserver://sa:my%7Bpass@somehost?connection+timeout=30` // password is "my{pass" + + A string of this format can be constructed using the `URL` type in the `net/url` package. ```go - db, err := sql.Open("mssql", "server=localhost;user id=sa") + query := url.Values{} + query.Add("app name", "MyAppName") + + u := &url.URL{ + Scheme: "sqlserver", + User: url.UserPassword(username, password), + Host: fmt.Sprintf("%s:%d", hostname, port), + // Path: instance, // if connecting to an instance instead of a port + RawQuery: query.Encode(), + } + db, err := sql.Open("sqlserver", u.String()) ``` -## Statement Parameters +2. ADO: `key=value` pairs separated by `;`. Values may not contain `;`, leading and trailing whitespace is ignored. + Examples: + + * `server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `server=localhost;user id=sa;database=master;app name=MyAppName` + +3. ODBC: Prefix with `odbc`, `key=value` pairs separated by `;`. Allow `;` by wrapping + values in `{}`. Examples: + + * `odbc:server=localhost\\SQLExpress;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;database=master;app name=MyAppName` + * `odbc:server=localhost;user id=sa;password={foo;bar}` // Value marked with `{}`, password is "foo;bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Value marked with `{}`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foobar }` // Value marked with `{}`, password is "foobar " + * `odbc:server=localhost;user id=sa;password=foo{bar` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password=foo}bar` // Literal `}`, password is "foo}bar" + * `odbc:server=localhost;user id=sa;password={foo{bar}` // Literal `{`, password is "foo{bar" + * `odbc:server=localhost;user id=sa;password={foo}}bar}` // Escaped `} with `}}`, password is "foo}bar" + +## Executing Stored Procedures + +To run a stored procedure, set the query text to the procedure name: +```go +var account = "abc" +_, err := db.ExecContext(ctx, "sp_RunMe", + sql.Named("ID", 123), + sql.Named("Account", sql.Out{Dest: &account}), +) +``` -In the SQL statement text, literals may be replaced by a parameter that matches one of the following: +## Caveat for local temporary tables -* ? -* ?nnn -* :nnn -* $nnn +Due to protocol limitations, temporary tables will only be allocated on the connection +as a result of executing a query with zero parameters. The following query +will, due to the use of a parameter, execute in its own session, +and `#mytemp` will be de-allocated right away: -where nnn represents an integer that specifies a 1-indexed positional parameter. Ex: +```go +conn, err := pool.Conn(ctx) +defer conn.Close() +_, err := conn.ExecContext(ctx, "select @p1 as x into #mytemp", 1) +// at this point #mytemp is already dropped again as the session of the ExecContext is over +``` + +To work around this, always explicitly create the local temporary +table in a query without any parameters. As a special case, the driver +will then be able to execute the query directly on the +connection-scoped session. The following example works: ```go -db.Query("SELECT * FROM t WHERE a = ?3, b = ?2, c = ?1", "x", "y", "z") +conn, err := pool.Conn(ctx) + +// Set us up so that temp table is always cleaned up, since conn.Close() +// merely returns conn to pool, rather than actually closing the connection. +defer func() { + _, _ = conn.ExecContext(ctx, "drop table #mytemp") // always clean up + conn.Close() // merely returns conn to pool +}() + + +// Since we not pass any parameters below, the query will execute on the scope of +// the connection and succeed in creating the table. +_, err := conn.ExecContext(ctx, "create table #mytemp ( x int )") + +// #mytemp is now available even if you pass parameters +_, err := conn.ExecContext(ctx, "insert into #mytemp (x) values (@p1)", 1) + ``` -will expand to roughly +## Return Status + +To get the procedure return status, pass into the parameters a +`*mssql.ReturnStatus`. For example: +``` +var rs mssql.ReturnStatus +_, err := db.ExecContext(ctx, "theproc", &rs) +log.Printf("status=%d", rs) +``` + +## Parameters + +The `sqlserver` driver uses normal MS SQL Server syntax and expects parameters in +the sql query to be in the form of either `@Name` or `@p1` to `@pN` (ordinal position). -```sql -SELECT * FROM t WHERE a = 'z', b = 'y', c = 'x' +```go +db.QueryContext(ctx, `select * from t where ID = @ID and Name = @p2;`, sql.Named("ID", 6), "Bob") ``` +### Parameter Types + +To pass specific types to the query parameters, say `varchar` or `date` types, +you must convert the types to the type before passing in. The following types +are supported: + + * string -> nvarchar + * mssql.VarChar -> varchar + * time.Time -> datetimeoffset or datetime (TDS version dependent) + * mssql.DateTime1 -> datetime + * mssql.DateTimeOffset -> datetimeoffset + * "cloud.google.com/go/civil".Date -> date + * "cloud.google.com/go/civil".DateTime -> datetime2 + * "cloud.google.com/go/civil".Time -> time + * mssql.TVPType -> Table Value Parameter (TDS version dependent) + +## Important Notes + + * [LastInsertId](https://golang.org/pkg/database/sql/#Result.LastInsertId) should + not be used with this driver (or SQL Server) due to how the TDS protocol + works. Please use the [OUTPUT Clause](https://docs.microsoft.com/en-us/sql/t-sql/queries/output-clause-transact-sql) + or add a `select ID = convert(bigint, SCOPE_IDENTITY());` to the end of your + query (ref [SCOPE_IDENTITY](https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql)). + This will ensure you are getting the correct ID and will prevent a network round trip. + * [NewConnector](https://godoc.org/github.com/denisenkom/go-mssqldb#NewConnector) + may be used with [OpenDB](https://golang.org/pkg/database/sql/#OpenDB). + * [Connector.SessionInitSQL](https://godoc.org/github.com/denisenkom/go-mssqldb#Connector.SessionInitSQL) + may be set to set any driver specific session settings after the session + has been reset. If empty the session will still be reset but use the database + defaults in Go1.10+. ## Features @@ -87,6 +219,34 @@ SELECT * FROM t WHERE a = 'z', b = 'y', c = 'x' * Supports connections to AlwaysOn Availability Group listeners, including re-direction to read-only replicas. * Supports query notifications +## Tests + +`go test` is used for testing. A running instance of MSSQL server is required. +Environment variables are used to pass login information. + +Example: + + env SQLSERVER_DSN=sqlserver://user:pass@hostname/instance?database=test1 go test + +## Deprecated + +These features still exist in the driver, but they are are deprecated. + +### Query Parameter Token Replace (driver "mssql") + +If you use the driver name "mssql" (rather then "sqlserver") the SQL text +will be loosly parsed and an attempt to extract identifiers using one of + +* ? +* ?nnn +* :nnn +* $nnn + +will be used. This is not recommended with SQL Server. +There is at least one existing `won't fix` issue with the query parsing. + +Use the native "@Name" parameters instead with the "sqlserver" driver name. + ## Known Issues * SQL Server 2008 and 2008 R2 engine cannot handle login records when SSL encryption is not disabled. diff --git a/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml new file mode 100644 index 0000000000000..2ae5456d5cb70 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/appveyor.yml @@ -0,0 +1,48 @@ +version: 1.0.{build} + +os: Windows Server 2012 R2 + +clone_folder: c:\gopath\src\github.com\denisenkom\go-mssqldb + +environment: + GOPATH: c:\gopath + HOST: localhost + SQLUSER: sa + SQLPASSWORD: Password12! + DATABASE: test + GOVERSION: 110 + matrix: + - GOVERSION: 18 + SQLINSTANCE: SQL2016 + - GOVERSION: 19 + SQLINSTANCE: SQL2016 + - GOVERSION: 110 + SQLINSTANCE: SQL2016 + - SQLINSTANCE: SQL2014 + - SQLINSTANCE: SQL2012SP1 + - SQLINSTANCE: SQL2008R2SP2 + +install: + - set GOROOT=c:\go%GOVERSION% + - set PATH=%GOPATH%\bin;%GOROOT%\bin;%PATH% + - go version + - go env + - go get -u cloud.google.com/go/civil + +build_script: + - go build + +before_test: + # setup SQL Server + - ps: | + $instanceName = $env:SQLINSTANCE + Start-Service "MSSQL`$$instanceName" + Start-Service "SQLBrowser" + - sqlcmd -S "(local)\%SQLINSTANCE%" -Q "Use [master]; CREATE DATABASE test;" + - sqlcmd -S "(local)\%SQLINSTANCE%" -h -1 -Q "set nocount on; Select @@version" + - pip install codecov + + +test_script: + - go test -race -cpu 4 -coverprofile=coverage.txt -covermode=atomic + - codecov -f coverage.txt diff --git a/vendor/github.com/denisenkom/go-mssqldb/buf.go b/vendor/github.com/denisenkom/go-mssqldb/buf.go index 42e8ae345cf48..927d75d1b78b4 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/buf.go +++ b/vendor/github.com/denisenkom/go-mssqldb/buf.go @@ -2,12 +2,14 @@ package mssql import ( "encoding/binary" - "io" "errors" + "io" ) +type packetType uint8 + type header struct { - PacketType uint8 + PacketType packetType Status uint8 Size uint16 Spid uint16 @@ -15,125 +17,159 @@ type header struct { Pad uint8 } +// tdsBuffer reads and writes TDS packets of data to the transport. +// The write and read buffers are separate to make sending attn signals +// possible without locks. Currently attn signals are only sent during +// reads, not writes. type tdsBuffer struct { - buf []byte - pos uint16 - transport io.ReadWriteCloser - size uint16 + transport io.ReadWriteCloser + + packetSize int + + // Write fields. + wbuf []byte + wpos int + wPacketSeq byte + wPacketType packetType + + // Read fields. + rbuf []byte + rpos int + rsize int final bool - packet_type uint8 - afterFirst func() + rPacketType packetType + + // afterFirst is assigned to right after tdsBuffer is created and + // before the first use. It is executed after the first packet is + // written and then removed. + afterFirst func() } -func newTdsBuffer(bufsize int, transport io.ReadWriteCloser) *tdsBuffer { - buf := make([]byte, bufsize) - w := new(tdsBuffer) - w.buf = buf - w.pos = 8 - w.transport = transport - w.size = 0 - return w +func newTdsBuffer(bufsize uint16, transport io.ReadWriteCloser) *tdsBuffer { + return &tdsBuffer{ + packetSize: int(bufsize), + wbuf: make([]byte, 1<<16), + rbuf: make([]byte, 1<<16), + rpos: 8, + transport: transport, + } +} + +func (rw *tdsBuffer) ResizeBuffer(packetSize int) { + rw.packetSize = packetSize +} + +func (w *tdsBuffer) PackageSize() int { + return w.packetSize } func (w *tdsBuffer) flush() (err error) { - // writing packet size - binary.BigEndian.PutUint16(w.buf[2:], w.pos) + // Write packet size. + w.wbuf[0] = byte(w.wPacketType) + binary.BigEndian.PutUint16(w.wbuf[2:], uint16(w.wpos)) + w.wbuf[6] = w.wPacketSeq - // writing packet into underlying transport - if _, err = w.transport.Write(w.buf[:w.pos]); err != nil { + // Write packet into underlying transport. + if _, err = w.transport.Write(w.wbuf[:w.wpos]); err != nil { return err } + // It is possible to create a whole new buffer after a flush. + // Useful for debugging. Normally reuse the buffer. + // w.wbuf = make([]byte, 1<<16) - // execute afterFirst hook if it is set + // Execute afterFirst hook if it is set. if w.afterFirst != nil { w.afterFirst() w.afterFirst = nil } - w.pos = 8 - // packet number - w.buf[6] += 1 + w.wpos = 8 + w.wPacketSeq++ return nil } func (w *tdsBuffer) Write(p []byte) (total int, err error) { - total = 0 for { - copied := copy(w.buf[w.pos:], p) - w.pos += uint16(copied) + copied := copy(w.wbuf[w.wpos:w.packetSize], p) + w.wpos += copied total += copied if copied == len(p) { - break + return } if err = w.flush(); err != nil { return } p = p[copied:] } - return } func (w *tdsBuffer) WriteByte(b byte) error { - if int(w.pos) == len(w.buf) { + if int(w.wpos) == len(w.wbuf) || w.wpos == w.packetSize { if err := w.flush(); err != nil { return err } } - w.buf[w.pos] = b - w.pos += 1 + w.wbuf[w.wpos] = b + w.wpos += 1 return nil } -func (w *tdsBuffer) BeginPacket(packet_type byte) { - w.buf[0] = packet_type - w.buf[1] = 0 // packet is incomplete - w.buf[4] = 0 // spid - w.buf[5] = 0 - w.buf[6] = 1 // packet id - w.buf[7] = 0 // window - w.pos = 8 +func (w *tdsBuffer) BeginPacket(packetType packetType, resetSession bool) { + status := byte(0) + if resetSession { + switch packetType { + // Reset session can only be set on the following packet types. + case packSQLBatch, packRPCRequest, packTransMgrReq: + status = 0x8 + } + } + w.wbuf[1] = status // Packet is incomplete. This byte is set again in FinishPacket. + w.wpos = 8 + w.wPacketSeq = 1 + w.wPacketType = packetType } func (w *tdsBuffer) FinishPacket() error { - w.buf[1] = 1 // this is last packet + w.wbuf[1] |= 1 // Mark this as the last packet in the message. return w.flush() } +var headerSize = binary.Size(header{}) + func (r *tdsBuffer) readNextPacket() error { - header := header{} + h := header{} var err error - err = binary.Read(r.transport, binary.BigEndian, &header) + err = binary.Read(r.transport, binary.BigEndian, &h) if err != nil { return err } - offset := uint16(binary.Size(header)) - if int(header.Size) > len(r.buf) { + if int(h.Size) > r.packetSize { return errors.New("Invalid packet size, it is longer than buffer size") } - if int(offset) > int(header.Size) { + if headerSize > int(h.Size) { return errors.New("Invalid packet size, it is shorter than header size") } - _, err = io.ReadFull(r.transport, r.buf[offset:header.Size]) + _, err = io.ReadFull(r.transport, r.rbuf[headerSize:h.Size]) if err != nil { return err } - r.pos = offset - r.size = header.Size - r.final = header.Status != 0 - r.packet_type = header.PacketType + r.rpos = headerSize + r.rsize = int(h.Size) + r.final = h.Status != 0 + r.rPacketType = h.PacketType return nil } -func (r *tdsBuffer) BeginRead() (uint8, error) { +func (r *tdsBuffer) BeginRead() (packetType, error) { err := r.readNextPacket() if err != nil { return 0, err } - return r.packet_type, nil + return r.rPacketType, nil } func (r *tdsBuffer) ReadByte() (res byte, err error) { - if r.pos == r.size { + if r.rpos == r.rsize { if r.final { return 0, io.EOF } @@ -142,8 +178,8 @@ func (r *tdsBuffer) ReadByte() (res byte, err error) { return 0, err } } - res = r.buf[r.pos] - r.pos++ + res = r.rbuf[r.rpos] + r.rpos++ return res, nil } @@ -207,7 +243,7 @@ func (r *tdsBuffer) readUcs2(numchars int) string { func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { copied = 0 err = nil - if r.pos == r.size { + if r.rpos == r.rsize { if r.final { return 0, io.EOF } @@ -216,7 +252,7 @@ func (r *tdsBuffer) Read(buf []byte) (copied int, err error) { return } } - copied = copy(buf, r.buf[r.pos:r.size]) - r.pos += uint16(copied) + copied = copy(buf, r.rbuf[r.rpos:r.rsize]) + r.rpos += copied return } diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go new file mode 100644 index 0000000000000..3b319af893fd3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go @@ -0,0 +1,554 @@ +package mssql + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "math" + "reflect" + "strconv" + "strings" + "time" +) + +type Bulk struct { + // ctx is used only for AddRow and Done methods. + // This could be removed if AddRow and Done accepted + // a ctx field as well, which is available with the + // database/sql call. + ctx context.Context + + cn *Conn + metadata []columnStruct + bulkColumns []columnStruct + columnsName []string + tablename string + numRows int + + headerSent bool + Options BulkOptions + Debug bool +} +type BulkOptions struct { + CheckConstraints bool + FireTriggers bool + KeepNulls bool + KilobytesPerBatch int + RowsPerBatch int + Order []string + Tablock bool +} + +type DataValue interface{} + +func (cn *Conn) CreateBulk(table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: context.Background(), cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (cn *Conn) CreateBulkContext(ctx context.Context, table string, columns []string) (_ *Bulk) { + b := Bulk{ctx: ctx, cn: cn, tablename: table, headerSent: false, columnsName: columns} + b.Debug = false + return &b +} + +func (b *Bulk) sendBulkCommand(ctx context.Context) (err error) { + //get table columns info + err = b.getMetadata(ctx) + if err != nil { + return err + } + + //match the columns + for _, colname := range b.columnsName { + var bulkCol *columnStruct + + for _, m := range b.metadata { + if m.ColName == colname { + bulkCol = &m + break + } + } + if bulkCol != nil { + + if bulkCol.ti.TypeId == typeUdt { + //send udt as binary + bulkCol.ti.TypeId = typeBigVarBin + } + b.bulkColumns = append(b.bulkColumns, *bulkCol) + b.dlogf("Adding column %s %s %#x", colname, bulkCol.ColName, bulkCol.ti.TypeId) + } else { + return fmt.Errorf("Column %s does not exist in destination table %s", colname, b.tablename) + } + } + + //create the bulk command + + //columns definitions + var col_defs bytes.Buffer + for i, col := range b.bulkColumns { + if i != 0 { + col_defs.WriteString(", ") + } + col_defs.WriteString("[" + col.ColName + "] " + makeDecl(col.ti)) + } + + //options + var with_opts []string + + if b.Options.CheckConstraints { + with_opts = append(with_opts, "CHECK_CONSTRAINTS") + } + if b.Options.FireTriggers { + with_opts = append(with_opts, "FIRE_TRIGGERS") + } + if b.Options.KeepNulls { + with_opts = append(with_opts, "KEEP_NULLS") + } + if b.Options.KilobytesPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("KILOBYTES_PER_BATCH = %d", b.Options.KilobytesPerBatch)) + } + if b.Options.RowsPerBatch > 0 { + with_opts = append(with_opts, fmt.Sprintf("ROWS_PER_BATCH = %d", b.Options.RowsPerBatch)) + } + if len(b.Options.Order) > 0 { + with_opts = append(with_opts, fmt.Sprintf("ORDER(%s)", strings.Join(b.Options.Order, ","))) + } + if b.Options.Tablock { + with_opts = append(with_opts, "TABLOCK") + } + var with_part string + if len(with_opts) > 0 { + with_part = fmt.Sprintf("WITH (%s)", strings.Join(with_opts, ",")) + } + + query := fmt.Sprintf("INSERT BULK %s (%s) %s", b.tablename, col_defs.String(), with_part) + + stmt, err := b.cn.PrepareContext(ctx, query) + if err != nil { + return fmt.Errorf("Prepare failed: %s", err.Error()) + } + b.dlogf(query) + + _, err = stmt.(*Stmt).ExecContext(ctx, nil) + if err != nil { + return err + } + + b.headerSent = true + + var buf = b.cn.sess.buf + buf.BeginPacket(packBulkLoadBCP, false) + + // Send the columns metadata. + columnMetadata := b.createColMetadata() + _, err = buf.Write(columnMetadata) + + return +} + +// AddRow immediately writes the row to the destination table. +// The arguments are the row values in the order they were specified. +func (b *Bulk) AddRow(row []interface{}) (err error) { + if !b.headerSent { + err = b.sendBulkCommand(b.ctx) + if err != nil { + return + } + } + + if len(row) != len(b.bulkColumns) { + return fmt.Errorf("Row does not have the same number of columns than the destination table %d %d", + len(row), len(b.bulkColumns)) + } + + bytes, err := b.makeRowData(row) + if err != nil { + return + } + + _, err = b.cn.sess.buf.Write(bytes) + if err != nil { + return + } + + b.numRows = b.numRows + 1 + return +} + +func (b *Bulk) makeRowData(row []interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenRow)) + + var logcol bytes.Buffer + for i, col := range b.bulkColumns { + + if b.Debug { + logcol.WriteString(fmt.Sprintf(" col[%d]='%v' ", i, row[i])) + } + param, err := b.makeParam(row[i], col) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + + if col.ti.Writer == nil { + return nil, fmt.Errorf("no writer for column: %s, TypeId: %#x", + col.ColName, col.ti.TypeId) + } + err = col.ti.Writer(buf, param.ti, param.buffer) + if err != nil { + return nil, fmt.Errorf("bulkcopy: %s", err.Error()) + } + } + + b.dlogf("row[%d] %s\n", b.numRows, logcol.String()) + + return buf.Bytes(), nil +} + +func (b *Bulk) Done() (rowcount int64, err error) { + if b.headerSent == false { + //no rows had been sent + return 0, nil + } + var buf = b.cn.sess.buf + buf.WriteByte(byte(tokenDone)) + + binary.Write(buf, binary.LittleEndian, uint16(doneFinal)) + binary.Write(buf, binary.LittleEndian, uint16(0)) // curcmd + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint64(0)) //rowcount 0 + } else { + binary.Write(buf, binary.LittleEndian, uint32(0)) //rowcount 0 + } + + buf.FinishPacket() + + tokchan := make(chan tokenStruct, 5) + go processResponse(b.ctx, b.cn.sess, tokchan, nil) + + var rowCount int64 + for token := range tokchan { + switch token := token.(type) { + case doneStruct: + if token.Status&doneCount != 0 { + rowCount = int64(token.RowCount) + } + if token.isError() { + return 0, token.getError() + } + case error: + return 0, b.cn.checkBadConn(token) + } + } + return rowCount, nil +} + +func (b *Bulk) createColMetadata() []byte { + buf := new(bytes.Buffer) + buf.WriteByte(byte(tokenColMetadata)) // token + binary.Write(buf, binary.LittleEndian, uint16(len(b.bulkColumns))) // column count + + for i, col := range b.bulkColumns { + + if b.cn.sess.loginAck.TDSVersion >= verTDS72 { + binary.Write(buf, binary.LittleEndian, uint32(col.UserType)) // usertype, always 0? + } else { + binary.Write(buf, binary.LittleEndian, uint16(col.UserType)) + } + binary.Write(buf, binary.LittleEndian, uint16(col.Flags)) + + writeTypeInfo(buf, &b.bulkColumns[i].ti) + + if col.ti.TypeId == typeNText || + col.ti.TypeId == typeText || + col.ti.TypeId == typeImage { + + tablename_ucs2 := str2ucs2(b.tablename) + binary.Write(buf, binary.LittleEndian, uint16(len(tablename_ucs2)/2)) + buf.Write(tablename_ucs2) + } + colname_ucs2 := str2ucs2(col.ColName) + buf.WriteByte(uint8(len(colname_ucs2) / 2)) + buf.Write(colname_ucs2) + } + + return buf.Bytes() +} + +func (b *Bulk) getMetadata(ctx context.Context) (err error) { + stmt, err := b.cn.prepareContext(ctx, "SET FMTONLY ON") + if err != nil { + return + } + + _, err = stmt.ExecContext(ctx, nil) + if err != nil { + return + } + + // Get columns info. + stmt, err = b.cn.prepareContext(ctx, fmt.Sprintf("select * from %s SET FMTONLY OFF", b.tablename)) + if err != nil { + return + } + rows, err := stmt.QueryContext(ctx, nil) + if err != nil { + return fmt.Errorf("get columns info failed: %v", err) + } + b.metadata = rows.(*Rows).cols + + if b.Debug { + for _, col := range b.metadata { + b.dlogf("col: %s typeId: %#x size: %d scale: %d prec: %d flags: %d lcid: %#x\n", + col.ColName, col.ti.TypeId, col.ti.Size, col.ti.Scale, col.ti.Prec, + col.Flags, col.ti.Collation.LcidAndFlags) + } + } + + return rows.Close() +} + +func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error) { + res.ti.Size = col.ti.Size + res.ti.TypeId = col.ti.TypeId + + if val == nil { + res.ti.Size = 0 + return + } + + switch col.ti.TypeId { + + case typeInt1, typeInt2, typeInt4, typeInt8, typeIntN: + var intvalue int64 + + switch val := val.(type) { + case int: + intvalue = int64(val) + case int32: + intvalue = int64(val) + case int64: + intvalue = val + default: + err = fmt.Errorf("mssql: invalid type for int column") + return + } + + res.buffer = make([]byte, res.ti.Size) + if col.ti.Size == 1 { + res.buffer[0] = byte(intvalue) + } else if col.ti.Size == 2 { + binary.LittleEndian.PutUint16(res.buffer, uint16(intvalue)) + } else if col.ti.Size == 4 { + binary.LittleEndian.PutUint32(res.buffer, uint32(intvalue)) + } else if col.ti.Size == 8 { + binary.LittleEndian.PutUint64(res.buffer, uint64(intvalue)) + } + case typeFlt4, typeFlt8, typeFltN: + var floatvalue float64 + + switch val := val.(type) { + case float32: + floatvalue = float64(val) + case float64: + floatvalue = val + case int: + floatvalue = float64(val) + case int64: + floatvalue = float64(val) + default: + err = fmt.Errorf("mssql: invalid type for float column: %s", val) + return + } + + if col.ti.Size == 4 { + res.buffer = make([]byte, 4) + binary.LittleEndian.PutUint32(res.buffer, math.Float32bits(float32(floatvalue))) + } else if col.ti.Size == 8 { + res.buffer = make([]byte, 8) + binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(floatvalue)) + } + case typeNVarChar, typeNText, typeNChar: + + switch val := val.(type) { + case string: + res.buffer = str2ucs2(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for nvarchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeVarChar, typeBigVarChar, typeText, typeChar, typeBigChar: + switch val := val.(type) { + case string: + res.buffer = []byte(val) + case []byte: + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for varchar column: %s", val) + return + } + res.ti.Size = len(res.buffer) + + case typeBit, typeBitN: + if reflect.TypeOf(val).Kind() != reflect.Bool { + err = fmt.Errorf("mssql: invalid type for bit column: %s", val) + return + } + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = make([]byte, 1) + if val.(bool) { + res.buffer[0] = 1 + } + case typeDateTime2N: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTime2(val, int(col.ti.Scale)) + res.ti.Size = len(res.buffer) + default: + err = fmt.Errorf("mssql: invalid type for datetime2 column: %s", val) + return + } + case typeDateTimeOffsetN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + + default: + err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %s", val) + return + } + case typeDateN: + switch val := val.(type) { + case time.Time: + res.buffer = encodeDate(val) + res.ti.Size = len(res.buffer) + default: + err = fmt.Errorf("mssql: invalid type for date column: %s", val) + return + } + case typeDateTime, typeDateTimeN, typeDateTim4: + switch val := val.(type) { + case time.Time: + if col.ti.Size == 4 { + res.buffer = encodeDateTim4(val) + res.ti.Size = len(res.buffer) + } else if col.ti.Size == 8 { + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) + } else { + err = fmt.Errorf("mssql: invalid size of column") + } + + default: + err = fmt.Errorf("mssql: invalid type for datetime column: %s", val) + } + + // case typeMoney, typeMoney4, typeMoneyN: + case typeDecimal, typeDecimalN, typeNumeric, typeNumericN: + var value float64 + switch v := val.(type) { + case int: + value = float64(v) + case int8: + value = float64(v) + case int16: + value = float64(v) + case int32: + value = float64(v) + case int64: + value = float64(v) + case float32: + value = float64(v) + case float64: + value = v + case string: + if value, err = strconv.ParseFloat(v, 64); err != nil { + return res, fmt.Errorf("bulk: unable to convert string to float: %v", err) + } + default: + return res, fmt.Errorf("unknown value for decimal: %#v", v) + } + + perc := col.ti.Prec + scale := col.ti.Scale + var dec Decimal + dec, err = Float64ToDecimalScale(value, scale) + if err != nil { + return res, err + } + dec.prec = perc + + var length byte + switch { + case perc <= 9: + length = 4 + case perc <= 19: + length = 8 + case perc <= 28: + length = 12 + default: + length = 16 + } + + buf := make([]byte, length+1) + // first byte length written by typeInfo.writer + res.ti.Size = int(length) + 1 + // second byte sign + if value < 0 { + buf[0] = 0 + } else { + buf[0] = 1 + } + + ub := dec.UnscaledBytes() + l := len(ub) + if l > int(length) { + err = fmt.Errorf("decimal out of range: %s", dec) + return res, err + } + // reverse the bytes + for i, j := 1, l-1; j >= 0; i, j = i+1, j-1 { + buf[i] = ub[j] + } + res.buffer = buf + case typeBigVarBin, typeBigBinary: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Binary column: %s", val) + return + } + case typeGuid: + switch val := val.(type) { + case []byte: + res.ti.Size = len(val) + res.buffer = val + default: + err = fmt.Errorf("mssql: invalid type for Guid column: %s", val) + return + } + + default: + err = fmt.Errorf("mssql: type %x not implemented", col.ti.TypeId) + } + return + +} + +func (b *Bulk) dlogf(format string, v ...interface{}) { + if b.Debug { + b.cn.sess.log.Printf(format, v...) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go new file mode 100644 index 0000000000000..709505b2a06a7 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/bulkcopy_sql.go @@ -0,0 +1,93 @@ +package mssql + +import ( + "context" + "database/sql/driver" + "encoding/json" + "errors" +) + +type copyin struct { + cn *Conn + bulkcopy *Bulk + closed bool +} + +type serializableBulkConfig struct { + TableName string + ColumnsName []string + Options BulkOptions +} + +func (d *Driver) OpenConnection(dsn string) (*Conn, error) { + return d.open(context.Background(), dsn) +} + +func (c *Conn) prepareCopyIn(ctx context.Context, query string) (_ driver.Stmt, err error) { + config_json := query[11:] + + bulkconfig := serializableBulkConfig{} + err = json.Unmarshal([]byte(config_json), &bulkconfig) + if err != nil { + return + } + + bulkcopy := c.CreateBulkContext(ctx, bulkconfig.TableName, bulkconfig.ColumnsName) + bulkcopy.Options = bulkconfig.Options + + ci := ©in{ + cn: c, + bulkcopy: bulkcopy, + } + + return ci, nil +} + +func CopyIn(table string, options BulkOptions, columns ...string) string { + bulkconfig := &serializableBulkConfig{TableName: table, Options: options, ColumnsName: columns} + + config_json, err := json.Marshal(bulkconfig) + if err != nil { + panic(err) + } + + stmt := "INSERTBULK " + string(config_json) + + return stmt +} + +func (ci *copyin) NumInput() int { + return -1 +} + +func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { + panic("should never be called") +} + +func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { + if ci.closed { + return nil, errors.New("copyin query is closed") + } + + if len(v) == 0 { + rowCount, err := ci.bulkcopy.Done() + ci.closed = true + return driver.RowsAffected(rowCount), err + } + + t := make([]interface{}, len(v)) + for i, val := range v { + t[i] = val + } + + err = ci.bulkcopy.AddRow(t) + if err != nil { + return + } + + return driver.RowsAffected(0), nil +} + +func (ci *copyin) Close() (err error) { + return nil +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/collation.go b/vendor/github.com/denisenkom/go-mssqldb/collation.go deleted file mode 100644 index ac9cf20b7b051..0000000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/collation.go +++ /dev/null @@ -1,39 +0,0 @@ -package mssql - -import ( - "encoding/binary" - "io" -) - -// http://msdn.microsoft.com/en-us/library/dd340437.aspx - -type collation struct { - lcidAndFlags uint32 - sortId uint8 -} - -func (c collation) getLcid() uint32 { - return c.lcidAndFlags & 0x000fffff -} - -func (c collation) getFlags() uint32 { - return (c.lcidAndFlags & 0x0ff00000) >> 20 -} - -func (c collation) getVersion() uint32 { - return (c.lcidAndFlags & 0xf0000000) >> 28 -} - -func readCollation(r *tdsBuffer) (res collation) { - res.lcidAndFlags = r.uint32() - res.sortId = r.byte() - return -} - -func writeCollation(w io.Writer, col collation) (err error) { - if err = binary.Write(w, binary.LittleEndian, col.lcidAndFlags); err != nil { - return - } - err = binary.Write(w, binary.LittleEndian, col.sortId) - return -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/convert.go b/vendor/github.com/denisenkom/go-mssqldb/convert.go new file mode 100644 index 0000000000000..51bd4ee3ac73b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/convert.go @@ -0,0 +1,306 @@ +package mssql + +import "errors" + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Type conversions for Scan. + +// This file was imported from database.sql.convert for go 1.10.3 with minor modifications to get +// convertAssign function +// This function is used internally by sql to convert values during call to Scan, we need same +// logic to return values for OUTPUT parameters. +// TODO: sql library should instead expose function defaultCheckNamedValue to be callable by drivers + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +// convertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func convertAssign(dest, src interface{}) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = append((*d)[:0], s...) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil + } + case time.Time: + switch d := dest.(type) { + case *time.Time: + *d = s + return nil + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) + return nil + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *sql.RawBytes: + sv = reflect.ValueOf(src) + if b, ok := asBytes([]byte(*d)[:0], sv); ok { + *d = sql.RawBytes(b) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + if scanner, ok := dest.(sql.Scanner); ok { + return scanner.Scan(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + switch b := src.(type) { + case []byte: + dv.Set(reflect.ValueOf(cloneBytes(b))) + default: + dv.Set(sv) + } + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + // The following conversions use a string value as an intermediate representation + // to convert between various numeric types. + // + // This also allows scanning into user defined types such as "type Int int64". + // For symmetry, also check for string destination types. + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } else { + dv.Set(reflect.New(dv.Type().Elem())) + return convertAssign(dv.Interface(), src) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + case reflect.String: + switch v := src.(type) { + case string: + dv.SetString(v) + return nil + case []byte: + dv.SetString(string(v)) + return nil + } + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } else { + c := make([]byte, len(b)) + copy(c, b) + return c + } +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/decimal.go b/vendor/github.com/denisenkom/go-mssqldb/decimal.go index 76f3a6b5b49e4..372f64b4eb148 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/decimal.go +++ b/vendor/github.com/denisenkom/go-mssqldb/decimal.go @@ -32,7 +32,13 @@ func (d Decimal) ToFloat64() float64 { return val } +const autoScale = 100 + func Float64ToDecimal(f float64) (Decimal, error) { + return Float64ToDecimalScale(f, autoScale) +} + +func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { var dec Decimal if math.IsNaN(f) { return dec, errors.New("NaN") @@ -49,10 +55,10 @@ func Float64ToDecimal(f float64) (Decimal, error) { } dec.prec = 20 var integer float64 - for dec.scale = 0; dec.scale <= 20; dec.scale++ { + for dec.scale = 0; dec.scale <= scale; dec.scale++ { integer = f * scaletblflt64[dec.scale] _, frac := math.Modf(integer) - if frac == 0 { + if frac == 0 && scale == autoScale { break } } @@ -73,7 +79,7 @@ func init() { } } -func (d Decimal) Bytes() []byte { +func (d Decimal) BigInt() big.Int { bytes := make([]byte, 16) binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) @@ -84,9 +90,19 @@ func (d Decimal) Bytes() []byte { if !d.positive { x.Neg(&x) } + return x +} + +func (d Decimal) Bytes() []byte { + x := d.BigInt() return scaleBytes(x.String(), d.scale) } +func (d Decimal) UnscaledBytes() []byte { + x := d.BigInt() + return x.Bytes() +} + func scaleBytes(s string, scale uint8) []byte { z := make([]byte, 0, len(s)+1) if s[0] == '-' || s[0] == '+' { diff --git a/vendor/github.com/denisenkom/go-mssqldb/doc.go b/vendor/github.com/denisenkom/go-mssqldb/doc.go new file mode 100644 index 0000000000000..2e54929c572f9 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/doc.go @@ -0,0 +1,14 @@ +// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver) +// database servers. +// +// This package registers the driver: +// sqlserver: uses native "@" parameter placeholder names and does no pre-processing. +// +// If the ordinal position is used for query parameters, identifiers will be named +// "@p1", "@p2", ... "@pN". +// +// Please refer to the README for the format of the DSN. There are multiple DSN +// formats accepted: ADO style, ODBC style, and URL style. The following is an +// example of a URL style DSN: +// sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30 +package mssql diff --git a/vendor/github.com/denisenkom/go-mssqldb/go.mod b/vendor/github.com/denisenkom/go-mssqldb/go.mod new file mode 100644 index 0000000000000..1a6a38f917789 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/go.mod @@ -0,0 +1,10 @@ +module github.com/denisenkom/go-mssqldb + +go 1.12 + +require ( + cloud.google.com/go v0.37.4 + golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect +) diff --git a/vendor/github.com/denisenkom/go-mssqldb/go.sum b/vendor/github.com/denisenkom/go-mssqldb/go.sum new file mode 100644 index 0000000000000..e1936ecf70ba3 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/go.sum @@ -0,0 +1,168 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.2 h1:4y4L7BdHenTfZL0HervofNTHh9Ad6mNX72cQvl+5eH0= +cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= +go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= +go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= +golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= +google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +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= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/vendor/github.com/denisenkom/go-mssqldb/charset.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go similarity index 94% rename from vendor/github.com/denisenkom/go-mssqldb/charset.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go index f1cc247a9d6f1..8dc2279ea4833 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/charset.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/charset.go @@ -1,14 +1,14 @@ -package mssql +package cp type charsetMap struct { sb [256]rune // single byte runes, -1 for a double byte character lead byte db map[int]rune // double byte runes } -func collation2charset(col collation) *charsetMap { +func collation2charset(col Collation) *charsetMap { // http://msdn.microsoft.com/en-us/library/ms144250.aspx // http://msdn.microsoft.com/en-us/library/ms144250(v=sql.105).aspx - switch col.sortId { + switch col.SortId { case 30, 31, 32, 33, 34: return cp437 case 40, 41, 42, 44, 49, 55, 56, 57, 58, 59, 60, 61: @@ -86,7 +86,7 @@ func collation2charset(col collation) *charsetMap { return cp1252 } -func charset2utf8(col collation, s []byte) string { +func CharsetToUTF8(col Collation, s []byte) string { cm := collation2charset(col) if cm == nil { return string(s) diff --git a/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go new file mode 100644 index 0000000000000..ae7b03bf137eb --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/collation.go @@ -0,0 +1,20 @@ +package cp + +// http://msdn.microsoft.com/en-us/library/dd340437.aspx + +type Collation struct { + LcidAndFlags uint32 + SortId uint8 +} + +func (c Collation) getLcid() uint32 { + return c.LcidAndFlags & 0x000fffff +} + +func (c Collation) getFlags() uint32 { + return (c.LcidAndFlags & 0x0ff00000) >> 20 +} + +func (c Collation) getVersion() uint32 { + return (c.LcidAndFlags & 0xf0000000) >> 28 +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1250.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1250.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go index 8207366be764b..5c8094ec3cc83 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1250.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1250.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1250 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1251.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1251.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go index f5b81c3934cf4..dc5896770ca15 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1251.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1251.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1251 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1252.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1252.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go index ed705d35a7a27..5ae8703542f2e 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1252.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1252.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1252 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1253.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1253.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go index cb1e1a7623695..52c8e07aa69ec 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1253.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1253.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1253 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1254.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1254.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go index a4b09bb44f54c..5d8864a521fe7 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1254.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1254.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1254 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1255.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1255.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go index 97f9ee9e91330..60619895d92cc 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1255.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1255.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1255 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1256.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1256.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go index e91241b4489ec..ffd04b3e5bb95 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1256.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1256.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1256 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1257.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1257.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go index bd93e6f891a84..492da72ea4d03 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1257.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1257.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1257 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp1258.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp1258.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go index 4e1f8ac9438f5..80be52c596645 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp1258.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp1258.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp1258 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp437.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp437.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go index f47f8ecc77b41..76dedfb8ef53e 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp437.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp437.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp437 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp850.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp850.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go index e6b3d16904462..927ab249efa71 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp850.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp850.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp850 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp874.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp874.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go index 9d691a1a59572..723bf6c3926ab 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp874.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp874.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp874 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp932.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp932.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go index 980c55d815f60..5fc1377424a85 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp932.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp932.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp932 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp936.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp936.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go index fca5da76d4d09..d1fac12e26bbd 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp936.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp936.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp936 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp949.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp949.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go index cddfcbc852261..52c708dfa5cf3 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp949.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp949.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp949 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/cp950.go b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go similarity index 99% rename from vendor/github.com/denisenkom/go-mssqldb/cp950.go rename to vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go index cbf25cb91a8c8..1301cd0f05274 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/cp950.go +++ b/vendor/github.com/denisenkom/go-mssqldb/internal/cp/cp950.go @@ -1,4 +1,4 @@ -package mssql +package cp var cp950 *charsetMap = &charsetMap{ sb: [256]rune{ diff --git a/vendor/github.com/denisenkom/go-mssqldb/log.go b/vendor/github.com/denisenkom/go-mssqldb/log.go index f350aed09988e..9b8c551e88d92 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/log.go +++ b/vendor/github.com/denisenkom/go-mssqldb/log.go @@ -4,19 +4,26 @@ import ( "log" ) -type Logger log.Logger +type Logger interface { + Printf(format string, v ...interface{}) + Println(v ...interface{}) +} + +type optionalLogger struct { + logger Logger +} -func (logger *Logger) Printf(format string, v ...interface{}) { - if logger != nil { - (*log.Logger)(logger).Printf(format, v...) +func (o optionalLogger) Printf(format string, v ...interface{}) { + if o.logger != nil { + o.logger.Printf(format, v...) } else { log.Printf(format, v...) } } -func (logger *Logger) Println(v ...interface{}) { - if logger != nil { - (*log.Logger)(logger).Println(v...) +func (o optionalLogger) Println(v ...interface{}) { + if o.logger != nil { + o.logger.Println(v...) } else { log.Println(v...) } diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql.go b/vendor/github.com/denisenkom/go-mssqldb/mssql.go index 9663651e7c60c..9065da53dea51 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql.go +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql.go @@ -1,122 +1,331 @@ package mssql import ( + "context" "database/sql" "database/sql/driver" "encoding/binary" "errors" "fmt" "io" - "log" "math" "net" + "reflect" "strings" "time" + "unicode" ) +// ReturnStatus may be used to return the return value from a proc. +// +// var rs mssql.ReturnStatus +// _, err := db.Exec("theproc", &rs) +// log.Printf("return status = %d", rs) +type ReturnStatus int32 + +var driverInstance = &Driver{processQueryText: true} +var driverInstanceNoProcess = &Driver{processQueryText: false} + func init() { - sql.Register("mssql", &MssqlDriver{}) + sql.Register("mssql", driverInstance) + sql.Register("sqlserver", driverInstanceNoProcess) + createDialer = func(p *connectParams) Dialer { + return netDialer{&net.Dialer{KeepAlive: p.keepAlive}} + } } -type MssqlDriver struct { - log *log.Logger +var createDialer func(p *connectParams) Dialer + +type netDialer struct { + nd *net.Dialer } -func (d *MssqlDriver) SetLogger(logger *log.Logger) { - d.log = logger +func (d netDialer) DialContext(ctx context.Context, network string, addr string) (net.Conn, error) { + return d.nd.DialContext(ctx, network, addr) } -func CheckBadConn(err error) error { - if err == io.EOF { - return driver.ErrBadConn +type Driver struct { + log optionalLogger + + processQueryText bool +} + +// OpenConnector opens a new connector. Useful to dial with a context. +func (d *Driver) OpenConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err } + return &Connector{ + params: params, + driver: d, + }, nil +} - switch e := err.(type) { - case net.Error: - if e.Timeout() { - return e - } - return driver.ErrBadConn - default: - return err +func (d *Driver) Open(dsn string) (driver.Conn, error) { + return d.open(context.Background(), dsn) +} + +func SetLogger(logger Logger) { + driverInstance.SetLogger(logger) + driverInstanceNoProcess.SetLogger(logger) +} + +func (d *Driver) SetLogger(logger Logger) { + d.log = optionalLogger{logger} +} + +// NewConnector creates a new connector from a DSN. +// The returned connector may be used with sql.OpenDB. +func NewConnector(dsn string) (*Connector, error) { + params, err := parseConnectParams(dsn) + if err != nil { + return nil, err + } + c := &Connector{ + params: params, + driver: driverInstanceNoProcess, } + return c, nil } -type MssqlConn struct { - sess *tdsSession +// Connector holds the parsed DSN and is ready to make a new connection +// at any time. +// +// In the future, settings that cannot be passed through a string DSN +// may be set directly on the connector. +type Connector struct { + params connectParams + driver *Driver + + // SessionInitSQL is executed after marking a given session to be reset. + // When not present, the next query will still reset the session to the + // database defaults. + // + // When present the connection will immediately mark the session to + // be reset, then execute the SessionInitSQL text to setup the session + // that may be different from the base database defaults. + // + // For Example, the application relies on the following defaults + // but is not allowed to set them at the database system level. + // + // SET XACT_ABORT ON; + // SET TEXTSIZE -1; + // SET ANSI_NULLS ON; + // SET LOCK_TIMEOUT 10000; + // + // SessionInitSQL should not attempt to manually call sp_reset_connection. + // This will happen at the TDS layer. + // + // SessionInitSQL is optional. The session will be reset even if + // SessionInitSQL is empty. + SessionInitSQL string + + // Dialer sets a custom dialer for all network operations. + // If Dialer is not set, normal net dialers are used. + Dialer Dialer } -func (c *MssqlConn) Commit() error { - headers := []headerStruct{ - {hdrtype: dataStmHdrTransDescr, - data: transDescrHdr{c.sess.tranid, 1}.pack()}, +type Dialer interface { + DialContext(ctx context.Context, network string, addr string) (net.Conn, error) +} + +func (c *Connector) getDialer(p *connectParams) Dialer { + if c != nil && c.Dialer != nil { + return c.Dialer + } + return createDialer(p) +} + +type Conn struct { + connector *Connector + sess *tdsSession + transactionCtx context.Context + resetSession bool + + processQueryText bool + connectionGood bool + + outs map[string]interface{} + returnStatus *ReturnStatus +} + +func (c *Conn) setReturnStatus(s ReturnStatus) { + if c.returnStatus == nil { + return } - if err := sendCommitXact(c.sess.buf, headers, "", 0, 0, ""); err != nil { + *c.returnStatus = s +} + +func (c *Conn) checkBadConn(err error) error { + // this is a hack to address Issue #275 + // we set connectionGood flag to false if + // error indicates that connection is not usable + // but we return actual error instead of ErrBadConn + // this will cause connection to stay in a pool + // but next request to this connection will return ErrBadConn + + // it might be possible to revise this hack after + // https://github.com/golang/go/issues/20807 + // is implemented + switch err { + case nil: + return nil + case io.EOF: + c.connectionGood = false + return driver.ErrBadConn + case driver.ErrBadConn: + // It is an internal programming error if driver.ErrBadConn + // is ever passed to this function. driver.ErrBadConn should + // only ever be returned in response to a *mssql.Conn.connectionGood == false + // check in the external facing API. + panic("driver.ErrBadConn in checkBadConn. This should not happen.") + } + + switch err.(type) { + case net.Error: + c.connectionGood = false + return err + case StreamError: + c.connectionGood = false + return err + default: return err } +} + +func (c *Conn) clearOuts() { + c.outs = nil +} +func (c *Conn) simpleProcessResp(ctx context.Context) error { tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) + go processResponse(ctx, c.sess, tokchan, c.outs) + c.clearOuts() for tok := range tokchan { switch token := tok.(type) { + case doneStruct: + if token.isError() { + return c.checkBadConn(token.getError()) + } case error: - return token + return c.checkBadConn(token) } } return nil } -func (c *MssqlConn) Rollback() error { +func (c *Conn) Commit() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendCommitRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendCommitRequest() error { headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{c.sess.tranid, 1}.pack()}, } - if err := sendRollbackXact(c.sess.buf, headers, "", 0, 0, ""); err != nil { - return err + 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.log.Printf("Failed to send CommitXact with %v", err) + } + c.connectionGood = false + return fmt.Errorf("Faild to send CommitXact: %v", err) } + return nil +} - tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) - for tok := range tokchan { - switch token := tok.(type) { - case error: - return token +func (c *Conn) Rollback() error { + if !c.connectionGood { + return driver.ErrBadConn + } + if err := c.sendRollbackRequest(); err != nil { + return c.checkBadConn(err) + } + return c.simpleProcessResp(c.transactionCtx) +} + +func (c *Conn) sendRollbackRequest() error { + headers := []headerStruct{ + {hdrtype: dataStmHdrTransDescr, + data: transDescrHdr{c.sess.tranid, 1}.pack()}, + } + 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.log.Printf("Failed to send RollbackXact with %v", err) } + c.connectionGood = false + return fmt.Errorf("Failed to send RollbackXact: %v", err) } return nil } -func (c *MssqlConn) Begin() (driver.Tx, error) { +func (c *Conn) Begin() (driver.Tx, error) { + return c.begin(context.Background(), isolationUseCurrent) +} + +func (c *Conn) begin(ctx context.Context, tdsIsolation isoLevel) (tx driver.Tx, err error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + err = c.sendBeginRequest(ctx, tdsIsolation) + if err != nil { + return nil, c.checkBadConn(err) + } + tx, err = c.processBeginResponse(ctx) + if err != nil { + return nil, c.checkBadConn(err) + } + return +} + +func (c *Conn) sendBeginRequest(ctx context.Context, tdsIsolation isoLevel) error { + c.transactionCtx = ctx headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{0, 1}.pack()}, } - if err := sendBeginXact(c.sess.buf, headers, 0, ""); err != nil { - return nil, CheckBadConn(err) - } - tokchan := make(chan tokenStruct, 5) - go processResponse(c.sess, tokchan) - for tok := range tokchan { - switch token := tok.(type) { - case error: - if c.sess.tranid != 0 { - return nil, token - } - return nil, CheckBadConn(token) + 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.log.Printf("Failed to send BeginXact with %v", err) } + c.connectionGood = false + return fmt.Errorf("Failed to send BeginXact: %v", err) + } + return nil +} + +func (c *Conn) processBeginResponse(ctx context.Context) (driver.Tx, error) { + if err := c.simpleProcessResp(ctx); err != nil { + return nil, err } // successful BEGINXACT request will return sess.tranid // for started transaction return c, nil } -func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) { +func (d *Driver) open(ctx context.Context, dsn string) (*Conn, error) { params, err := parseConnectParams(dsn) if err != nil { return nil, err } + return d.connect(ctx, nil, params) +} - sess, err := connect(params) +// connect to the server, using the provided context for dialing only. +func (d *Driver) connect(ctx context.Context, c *Connector, params connectParams) (*Conn, error) { + sess, err := connect(ctx, c, d.log, params) if err != nil { // main server failed, try fail-over partner if params.failOverPartner == "" { @@ -128,24 +337,31 @@ func (d *MssqlDriver) Open(dsn string) (driver.Conn, error) { params.port = params.failOverPort } - sess, err = connect(params) + sess, err = connect(ctx, c, d.log, params) if err != nil { // fail-over partner also failed, now fail return nil, err } } - conn := &MssqlConn{sess} - conn.sess.log = (*Logger)(d.log) + conn := &Conn{ + connector: c, + sess: sess, + transactionCtx: context.Background(), + processQueryText: d.processQueryText, + connectionGood: true, + } + conn.sess.log = d.log + return conn, nil } -func (c *MssqlConn) Close() error { +func (c *Conn) Close() error { return c.sess.buf.transport.Close() } -type MssqlStmt struct { - c *MssqlConn +type Stmt struct { + c *Conn query string paramCount int notifSub *queryNotifSub @@ -157,16 +373,29 @@ type queryNotifSub struct { timeout uint32 } -func (c *MssqlConn) Prepare(query string) (driver.Stmt, error) { - q, paramCount := parseParams(query) - return &MssqlStmt{c, q, paramCount, nil}, nil +func (c *Conn) Prepare(query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(context.Background(), query) + } + return c.prepareContext(context.Background(), query) } -func (s *MssqlStmt) Close() error { +func (c *Conn) prepareContext(ctx context.Context, query string) (*Stmt, error) { + paramCount := -1 + if c.processQueryText { + query, paramCount = parseParams(query) + } + return &Stmt{c, query, paramCount, nil}, nil +} + +func (s *Stmt) Close() error { return nil } -func (s *MssqlStmt) SetQueryNotification(id, options string, timeout time.Duration) { +func (s *Stmt) SetQueryNotification(id, options string, timeout time.Duration) { to := uint32(timeout / time.Second) if to < 1 { to = 1 @@ -174,183 +403,326 @@ func (s *MssqlStmt) SetQueryNotification(id, options string, timeout time.Durati s.notifSub = &queryNotifSub{id, options, to} } -func (s *MssqlStmt) NumInput() int { +func (s *Stmt) NumInput() int { return s.paramCount } -func (s *MssqlStmt) sendQuery(args []driver.Value) (err error) { +func (s *Stmt) sendQuery(args []namedValue) (err error) { headers := []headerStruct{ {hdrtype: dataStmHdrTransDescr, data: transDescrHdr{s.c.sess.tranid, 1}.pack()}, } if s.notifSub != nil { - headers = append(headers, headerStruct{hdrtype: dataStmHdrQueryNotif, - data: queryNotifHdr{s.notifSub.msgText, s.notifSub.options, s.notifSub.timeout}.pack()}) + headers = append(headers, + headerStruct{ + hdrtype: dataStmHdrQueryNotif, + data: queryNotifHdr{ + s.notifSub.msgText, + s.notifSub.options, + s.notifSub.timeout, + }.pack(), + }) } - if len(args) != s.paramCount { - return errors.New(fmt.Sprintf("sql: expected %d parameters, got %d", s.paramCount, len(args))) - } - if s.c.sess.logFlags&logSQL != 0 { - s.c.sess.log.Println(s.query) + 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.log.Println(s.query) } - if s.c.sess.logFlags&logParams != 0 && len(args) > 0 { + if conn.sess.logFlags&logParams != 0 && len(args) > 0 { for i := 0; i < len(args); i++ { - s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i]) + if len(args[i].Name) > 0 { + s.c.sess.log.Printf("\t@%s\t%v\n", args[i].Name, args[i].Value) + } else { + s.c.sess.log.Printf("\t@p%d\t%v\n", i+1, args[i].Value) + } } - } + + reset := conn.resetSession + conn.resetSession = false if len(args) == 0 { - if err = sendSqlBatch72(s.c.sess.buf, s.query, headers); err != nil { - if s.c.sess.tranid != 0 { - return err + if err = sendSqlBatch72(conn.sess.buf, s.query, headers, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send SqlBatch with %v", err) } - return CheckBadConn(err) + conn.connectionGood = false + return fmt.Errorf("failed to send SQL Batch: %v", err) } } else { - params := make([]Param, len(args)+2) - decls := make([]string, len(args)) - params[0], err = s.makeParam(s.query) - if err != nil { - return - } - for i, val := range args { - params[i+2], err = s.makeParam(val) + proc := sp_ExecuteSql + var params []param + if isProc(s.query) { + proc.name = s.query + params, _, err = s.makeRPCParams(args, 0) if err != nil { return } - name := fmt.Sprintf("@p%d", i+1) - params[i+2].Name = name - decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+2].ti)) - } - params[1], err = s.makeParam(strings.Join(decls, ",")) - if err != nil { - return + } else { + var decls []string + params, decls, err = s.makeRPCParams(args, 2) + if err != nil { + return + } + params[0] = makeStrParam(s.query) + params[1] = makeStrParam(strings.Join(decls, ",")) } - if err = sendRpc(s.c.sess.buf, headers, Sp_ExecuteSql, 0, params); err != nil { - if s.c.sess.tranid != 0 { - return err + if err = sendRpc(conn.sess.buf, headers, proc, 0, params, reset); err != nil { + if conn.sess.logFlags&logErrors != 0 { + conn.sess.log.Printf("Failed to send Rpc with %v", err) } - return CheckBadConn(err) + conn.connectionGood = false + return fmt.Errorf("Failed to send RPC: %v", err) } } return } -func (s *MssqlStmt) Query(args []driver.Value) (res driver.Rows, err error) { +// isProc takes the query text in s and determines if it is a stored proc name +// or SQL text. +func isProc(s string) bool { + if len(s) == 0 { + return false + } + const ( + outside = iota + text + escaped + ) + st := outside + var rn1, rPrev rune + for _, r := range s { + rPrev = rn1 + rn1 = r + switch r { + // No newlines or string sequences. + case '\n', '\r', '\'', ';': + return false + } + switch st { + case outside: + switch { + case unicode.IsSpace(r): + return false + case r == '[': + st = escaped + continue + case r == ']' && rPrev == ']': + st = escaped + continue + case unicode.IsLetter(r): + st = text + } + case text: + switch { + case r == '.': + st = outside + continue + case unicode.IsSpace(r): + return false + } + case escaped: + switch { + case r == ']': + st = outside + continue + } + } + } + return true +} + +func (s *Stmt) makeRPCParams(args []namedValue, offset int) ([]param, []string, error) { + var err error + params := make([]param, len(args)+offset) + decls := make([]string, len(args)) + for i, val := range args { + params[i+offset], err = s.makeParam(val.Value) + if err != nil { + return nil, nil, err + } + var name string + if len(val.Name) > 0 { + name = "@" + val.Name + } else { + name = fmt.Sprintf("@p%d", val.Ordinal) + } + params[i+offset].Name = name + decls[i] = fmt.Sprintf("%s %s", name, makeDecl(params[i+offset].ti)) + } + return params, decls, nil +} + +type namedValue struct { + Name string + Ordinal int + Value driver.Value +} + +func convertOldArgs(args []driver.Value) []namedValue { + list := make([]namedValue, len(args)) + for i, v := range args { + list[i] = namedValue{ + Ordinal: i + 1, + Value: v, + } + } + return list +} + +func (s *Stmt) Query(args []driver.Value) (driver.Rows, error) { + return s.queryContext(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) queryContext(ctx context.Context, args []namedValue) (rows driver.Rows, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } if err = s.sendQuery(args); err != nil { - return + return nil, s.c.checkBadConn(err) } + return s.processQueryResponse(ctx) +} + +func (s *Stmt) processQueryResponse(ctx context.Context) (res driver.Rows, err error) { tokchan := make(chan tokenStruct, 5) - go processResponse(s.c.sess, tokchan) + ctx, cancel := context.WithCancel(ctx) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() // process metadata - var cols []string + var cols []columnStruct loop: for tok := range tokchan { switch token := tok.(type) { - // by ignoring DONE token we effectively - // skip empty result-sets - // this improves results in queryes like that: + // By ignoring DONE token we effectively + // skip empty result-sets. + // This improves results in queries like that: // set nocount on; select 1 // see TestIgnoreEmptyResults test //case doneStruct: //break loop case []columnStruct: - cols = make([]string, len(token)) - for i, col := range token { - cols[i] = col.ColName - } + cols = token break loop - case error: - if s.c.sess.tranid != 0 { - return nil, token + case doneStruct: + if token.isError() { + return nil, s.c.checkBadConn(token.getError()) } - return nil, CheckBadConn(token) + case ReturnStatus: + s.c.setReturnStatus(token) + case error: + return nil, s.c.checkBadConn(token) } } - return &MssqlRows{sess: s.c.sess, tokchan: tokchan, cols: cols}, nil + res = &Rows{stmt: s, tokchan: tokchan, cols: cols, cancel: cancel} + return } -func (s *MssqlStmt) Exec(args []driver.Value) (res driver.Result, err error) { +func (s *Stmt) Exec(args []driver.Value) (driver.Result, error) { + return s.exec(context.Background(), convertOldArgs(args)) +} + +func (s *Stmt) exec(ctx context.Context, args []namedValue) (res driver.Result, err error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } if err = s.sendQuery(args); err != nil { - return + return nil, s.c.checkBadConn(err) } + if res, err = s.processExec(ctx); err != nil { + return nil, s.c.checkBadConn(err) + } + return +} + +func (s *Stmt) processExec(ctx context.Context) (res driver.Result, err error) { tokchan := make(chan tokenStruct, 5) - go processResponse(s.c.sess, tokchan) + go processResponse(ctx, s.c.sess, tokchan, s.c.outs) + s.c.clearOuts() var rowCount int64 for token := range tokchan { switch token := token.(type) { case doneInProcStruct: if token.Status&doneCount != 0 { - rowCount = int64(token.RowCount) + rowCount += int64(token.RowCount) } case doneStruct: if token.Status&doneCount != 0 { - rowCount = int64(token.RowCount) - } - case error: - if s.c.sess.logFlags&logErrors != 0 { - s.c.sess.log.Println("got error:", token) + rowCount += int64(token.RowCount) } - if s.c.sess.tranid != 0 { - return nil, token + if token.isError() { + return nil, token.getError() } - return nil, CheckBadConn(token) + case ReturnStatus: + s.c.setReturnStatus(token) + case error: + return nil, token } } - return &MssqlResult{s.c, rowCount}, nil + return &Result{s.c, rowCount}, nil } -type MssqlRows struct { - sess *tdsSession - cols []string +type Rows struct { + stmt *Stmt + cols []columnStruct tokchan chan tokenStruct - nextCols []string + nextCols []columnStruct + + cancel func() } -func (rc *MssqlRows) Close() error { +func (rc *Rows) Close() error { + rc.cancel() for _ = range rc.tokchan { } rc.tokchan = nil return nil } -func (rc *MssqlRows) Columns() (res []string) { - return rc.cols +func (rc *Rows) Columns() (res []string) { + res = make([]string, len(rc.cols)) + for i, col := range rc.cols { + res[i] = col.ColName + } + return } -func (rc *MssqlRows) Next(dest []driver.Value) (err error) { +func (rc *Rows) Next(dest []driver.Value) error { + if !rc.stmt.c.connectionGood { + return driver.ErrBadConn + } if rc.nextCols != nil { return io.EOF } for tok := range rc.tokchan { switch tokdata := tok.(type) { case []columnStruct: - cols := make([]string, len(tokdata)) - for i, col := range tokdata { - cols[i] = col.ColName - } - rc.nextCols = cols + rc.nextCols = tokdata return io.EOF case []interface{}: for i := range dest { dest[i] = tokdata[i] } return nil + case doneStruct: + if tokdata.isError() { + return rc.stmt.c.checkBadConn(tokdata.getError()) + } case error: - return tokdata + return rc.stmt.c.checkBadConn(tokdata) } } return io.EOF } -func (rc *MssqlRows) HasNextResultSet() bool { +func (rc *Rows) HasNextResultSet() bool { return rc.nextCols != nil } -func (rc *MssqlRows) NextResultSet() error { +func (rc *Rows) NextResultSet() error { rc.cols = rc.nextCols rc.nextCols = nil if rc.cols == nil { @@ -359,11 +731,69 @@ func (rc *MssqlRows) NextResultSet() error { return nil } -func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func (r *Rows) ColumnTypeScanType(index int) reflect.Type { + return makeGoLangScanType(r.cols[index].ti) +} + +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func (r *Rows) ColumnTypeDatabaseTypeName(index int) string { + return makeGoLangTypeName(r.cols[index].ti) +} + +// RowsColumnTypeLength may be implemented by Rows. It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func (r *Rows) ColumnTypeLength(index int) (int64, bool) { + return makeGoLangTypeLength(r.cols[index].ti) +} + +// It should return +// the precision and scale for decimal types. If not applicable, ok should be false. +// The following are examples of returned values for various types: +// decimal(38, 4) (38, 4, true) +// int (0, 0, false) +// decimal (math.MaxInt64, math.MaxInt64, true) +func (r *Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool) { + return makeGoLangTypePrecisionScale(r.cols[index].ti) +} + +// The nullable value should +// be true if it is known the column may be null, or false if the column is known +// to be not nullable. +// If the column nullability is unknown, ok should be false. +func (r *Rows) ColumnTypeNullable(index int) (nullable, ok bool) { + nullable = r.cols[index].Flags&colFlagNullable != 0 + ok = true + return +} + +func makeStrParam(val string) (res param) { + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(val) + res.ti.Size = len(res.buffer) + return +} + +func (s *Stmt) makeParam(val driver.Value) (res param, err error) { if val == nil { - res.ti.TypeId = typeNVarChar + res.ti.TypeId = typeNull res.buffer = nil - res.ti.Size = 2 + res.ti.Size = 0 return } switch val := val.(type) { @@ -372,19 +802,34 @@ func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { res.buffer = make([]byte, 8) res.ti.Size = 8 binary.LittleEndian.PutUint64(res.buffer, uint64(val)) + case sql.NullInt64: + // only null values should be getting here + res.ti.TypeId = typeIntN + res.ti.Size = 8 + res.buffer = []byte{} + case float64: res.ti.TypeId = typeFltN res.ti.Size = 8 res.buffer = make([]byte, 8) binary.LittleEndian.PutUint64(res.buffer, math.Float64bits(val)) + case sql.NullFloat64: + // only null values should be getting here + res.ti.TypeId = typeFltN + res.ti.Size = 8 + res.buffer = []byte{} + case []byte: res.ti.TypeId = typeBigVarBin res.ti.Size = len(val) res.buffer = val case string: + res = makeStrParam(val) + case sql.NullString: + // only null values should be getting here res.ti.TypeId = typeNVarChar - res.buffer = str2ucs2(val) - res.ti.Size = len(res.buffer) + res.buffer = nil + res.ti.Size = 8000 case bool: res.ti.TypeId = typeBitN res.ti.Size = 1 @@ -392,55 +837,39 @@ func (s *MssqlStmt) makeParam(val driver.Value) (res Param, err error) { if val { res.buffer[0] = 1 } + case sql.NullBool: + // only null values should be getting here + res.ti.TypeId = typeBitN + res.ti.Size = 1 + res.buffer = []byte{} + case time.Time: if s.c.sess.loginAck.TDSVersion >= verTDS73 { res.ti.TypeId = typeDateTimeOffsetN res.ti.Scale = 7 - res.ti.Size = 10 - buf := make([]byte, 10) - res.buffer = buf - days, ns := dateTime2(val) - ns /= 100 - buf[0] = byte(ns) - buf[1] = byte(ns >> 8) - buf[2] = byte(ns >> 16) - buf[3] = byte(ns >> 24) - buf[4] = byte(ns >> 32) - buf[5] = byte(days) - buf[6] = byte(days >> 8) - buf[7] = byte(days >> 16) - _, offset := val.Zone() - offset /= 60 - buf[8] = byte(offset) - buf[9] = byte(offset >> 8) + res.buffer = encodeDateTimeOffset(val, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) } else { res.ti.TypeId = typeDateTimeN - res.ti.Size = 8 - res.buffer = make([]byte, 8) - ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) - dur := val.Sub(ref) - days := dur / (24 * time.Hour) - tm := (300 * (dur % (24 * time.Hour))) / time.Second - binary.LittleEndian.PutUint32(res.buffer[0:4], uint32(days)) - binary.LittleEndian.PutUint32(res.buffer[4:8], uint32(tm)) + res.buffer = encodeDateTime(val) + res.ti.Size = len(res.buffer) } default: - err = fmt.Errorf("mssql: unknown type for %T", val) - return + return s.makeParamExtra(val) } return } -type MssqlResult struct { - c *MssqlConn +type Result struct { + c *Conn rowsAffected int64 } -func (r *MssqlResult) RowsAffected() (int64, error) { +func (r *Result) RowsAffected() (int64, error) { return r.rowsAffected, nil } -func (r *MssqlResult) LastInsertId() (int64, error) { +func (r *Result) LastInsertId() (int64, error) { s, err := r.c.Prepare("select cast(@@identity as bigint)") if err != nil { return 0, err @@ -462,3 +891,83 @@ func (r *MssqlResult) LastInsertId() (int64, error) { lastInsertId := dest[0].(int64) return lastInsertId, nil } + +var _ driver.Pinger = &Conn{} + +// Ping is used to check if the remote server is available and satisfies the Pinger interface. +func (c *Conn) Ping(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + stmt := &Stmt{c, `select 1;`, 0, nil} + _, err := stmt.ExecContext(ctx, nil) + return err +} + +var _ driver.ConnBeginTx = &Conn{} + +// BeginTx satisfies ConnBeginTx. +func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if opts.ReadOnly { + return nil, errors.New("Read-only transactions are not supported") + } + + var tdsIsolation isoLevel + switch sql.IsolationLevel(opts.Isolation) { + case sql.LevelDefault: + tdsIsolation = isolationUseCurrent + case sql.LevelReadUncommitted: + tdsIsolation = isolationReadUncommited + case sql.LevelReadCommitted: + tdsIsolation = isolationReadCommited + case sql.LevelWriteCommitted: + return nil, errors.New("LevelWriteCommitted isolation level is not supported") + case sql.LevelRepeatableRead: + tdsIsolation = isolationRepeatableRead + case sql.LevelSnapshot: + tdsIsolation = isolationSnapshot + case sql.LevelSerializable: + tdsIsolation = isolationSerializable + case sql.LevelLinearizable: + return nil, errors.New("LevelLinearizable isolation level is not supported") + default: + return nil, errors.New("Isolation level is not supported or unknown") + } + return c.begin(ctx, tdsIsolation) +} + +func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if !c.connectionGood { + return nil, driver.ErrBadConn + } + if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { + return c.prepareCopyIn(ctx, query) + } + + return c.prepareContext(ctx, query) +} + +func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.queryContext(ctx, list) +} + +func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + if !s.c.connectionGood { + return nil, driver.ErrBadConn + } + list := make([]namedValue, len(args)) + for i, nv := range args { + list[i] = namedValue(nv) + } + return s.exec(ctx, list) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go deleted file mode 100644 index b8cffe9c01fe4..0000000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build go1.3 - -package mssql - -import ( - "net" -) - -func createDialer(p connectParams) *net.Dialer { - return &net.Dialer{Timeout: p.dial_timeout, KeepAlive: p.keepAlive} -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go deleted file mode 100644 index 3c7e72716d14c..0000000000000 --- a/vendor/github.com/denisenkom/go-mssqldb/mssql_go1.3pre.go +++ /dev/null @@ -1,11 +0,0 @@ -// +build !go1.3 - -package mssql - -import ( - "net" -) - -func createDialer(p *connectParams) *net.Dialer { - return &net.Dialer{Timeout: p.dial_timeout} -} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go new file mode 100644 index 0000000000000..833f047163778 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go @@ -0,0 +1,47 @@ +// +build go1.10 + +package mssql + +import ( + "context" + "database/sql/driver" +) + +var _ driver.Connector = &Connector{} +var _ driver.SessionResetter = &Conn{} + +func (c *Conn) ResetSession(ctx context.Context) error { + if !c.connectionGood { + return driver.ErrBadConn + } + c.resetSession = true + + if c.connector == nil || len(c.connector.SessionInitSQL) == 0 { + return nil + } + + s, err := c.prepareContext(ctx, c.connector.SessionInitSQL) + if err != nil { + return driver.ErrBadConn + } + _, err = s.exec(ctx, nil) + if err != nil { + return driver.ErrBadConn + } + + return nil +} + +// Connect to the server and return a TDS connection. +func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { + conn, err := c.driver.connect(ctx, c, c.params) + if err == nil { + err = conn.ResetSession(ctx) + } + return conn, err +} + +// Driver underlying the Connector. +func (c *Connector) Driver() driver.Driver { + return c.driver +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go new file mode 100644 index 0000000000000..ceb1872161f9b --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go @@ -0,0 +1,191 @@ +// +build go1.9 + +package mssql + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "time" + + // "github.com/cockroachdb/apd" + "cloud.google.com/go/civil" +) + +// Type alias provided for compatibility. + +type MssqlDriver = Driver // Deprecated: users should transition to the new name when possible. +type MssqlBulk = Bulk // Deprecated: users should transition to the new name when possible. +type MssqlBulkOptions = BulkOptions // Deprecated: users should transition to the new name when possible. +type MssqlConn = Conn // Deprecated: users should transition to the new name when possible. +type MssqlResult = Result // Deprecated: users should transition to the new name when possible. +type MssqlRows = Rows // Deprecated: users should transition to the new name when possible. +type MssqlStmt = Stmt // Deprecated: users should transition to the new name when possible. + +var _ driver.NamedValueChecker = &Conn{} + +// VarChar parameter types. +type VarChar string + +type NVarCharMax string +type VarCharMax string + +// DateTime1 encodes parameters to original DateTime SQL types. +type DateTime1 time.Time + +// DateTimeOffset encodes parameters to DateTimeOffset, preserving the UTC offset. +type DateTimeOffset time.Time + +func convertInputParameter(val interface{}) (interface{}, error) { + switch v := val.(type) { + case VarChar: + return val, nil + case NVarCharMax: + return val, nil + case VarCharMax: + return val, nil + case DateTime1: + return val, nil + case DateTimeOffset: + return val, nil + case civil.Date: + return val, nil + case civil.DateTime: + return val, nil + case civil.Time: + return val, nil + // case *apd.Decimal: + // return nil + default: + return driver.DefaultParameterConverter.ConvertValue(v) + } +} + +func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error { + switch v := nv.Value.(type) { + case sql.Out: + if c.outs == nil { + c.outs = make(map[string]interface{}) + } + c.outs[nv.Name] = v.Dest + + if v.Dest == nil { + return errors.New("destination is a nil pointer") + } + + dest_info := reflect.ValueOf(v.Dest) + if dest_info.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + + if dest_info.IsNil() { + return errors.New("destination is a nil pointer") + } + + pointed_value := reflect.Indirect(dest_info) + + // don't allow pointer to a pointer, only pointer to a value can be handled + // correctly + if pointed_value.Kind() == reflect.Ptr { + return errors.New("destination is a pointer to a pointer") + } + + // Unwrap the Out value and check the inner value. + val := pointed_value.Interface() + if val == nil { + return errors.New("MSSQL does not allow NULL value without type for OUTPUT parameters") + } + conv, err := convertInputParameter(val) + if err != nil { + return err + } + if conv == nil { + // if we replace with nil we would lose type information + nv.Value = sql.Out{Dest: val} + } else { + nv.Value = sql.Out{Dest: conv} + } + return nil + case *ReturnStatus: + *v = 0 // By default the return value should be zero. + c.returnStatus = v + return driver.ErrRemoveArgument + case TVPType: + return nil + default: + var err error + nv.Value, err = convertInputParameter(nv.Value) + return err + } +} + +func (s *Stmt) makeParamExtra(val driver.Value) (res param, err error) { + switch val := val.(type) { + case VarChar: + res.ti.TypeId = typeBigVarChar + res.buffer = []byte(val) + res.ti.Size = len(res.buffer) + case VarCharMax: + res.ti.TypeId = typeBigVarChar + res.buffer = []byte(val) + res.ti.Size = 0 // currently zero forces varchar(max) + case NVarCharMax: + res.ti.TypeId = typeNVarChar + res.buffer = str2ucs2(string(val)) + res.ti.Size = 0 // currently zero forces nvarchar(max) + case DateTime1: + t := time.Time(val) + res.ti.TypeId = typeDateTimeN + res.buffer = encodeDateTime(t) + res.ti.Size = len(res.buffer) + case DateTimeOffset: + res.ti.TypeId = typeDateTimeOffsetN + res.ti.Scale = 7 + res.buffer = encodeDateTimeOffset(time.Time(val), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Date: + res.ti.TypeId = typeDateN + res.buffer = encodeDate(val.In(time.UTC)) + res.ti.Size = len(res.buffer) + case civil.DateTime: + res.ti.TypeId = typeDateTime2N + res.ti.Scale = 7 + res.buffer = encodeDateTime2(val.In(time.UTC), int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case civil.Time: + res.ti.TypeId = typeTimeN + res.ti.Scale = 7 + res.buffer = encodeTime(val.Hour, val.Minute, val.Second, val.Nanosecond, int(res.ti.Scale)) + res.ti.Size = len(res.buffer) + case sql.Out: + res, err = s.makeParam(val.Dest) + res.Flags = fByRevValue + case TVPType: + err = val.check() + if err != nil { + return + } + schema, name, errGetName := getSchemeAndName(val.TVPTypeName) + if errGetName != nil { + return + } + res.ti.UdtInfo.TypeName = name + res.ti.UdtInfo.SchemaName = schema + res.ti.TypeId = typeTvp + res.buffer, err = val.encode(schema, name) + if err != nil { + return + } + res.ti.Size = len(res.buffer) + + default: + err = fmt.Errorf("mssql: unknown type for %T", val) + } + return +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + return convertAssign(scanInto, fromServer) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go new file mode 100644 index 0000000000000..9680f5107e0d2 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/mssql_go19pre.go @@ -0,0 +1,16 @@ +// +build !go1.9 + +package mssql + +import ( + "database/sql/driver" + "fmt" +) + +func (s *Stmt) makeParamExtra(val driver.Value) (param, error) { + return param{}, fmt.Errorf("mssql: unknown type for %T", val) +} + +func scanIntoOut(name string, fromServer, scanInto interface{}) error { + return fmt.Errorf("mssql: unsupported OUTPUT type, use a newer Go version") +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/net.go b/vendor/github.com/denisenkom/go-mssqldb/net.go index 72a87340db5fd..e3864d1a22245 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/net.go +++ b/vendor/github.com/denisenkom/go-mssqldb/net.go @@ -14,7 +14,7 @@ type timeoutConn struct { continueRead bool } -func NewTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { +func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn { return &timeoutConn{ c: conn, timeout: timeout, @@ -33,7 +33,7 @@ func (c *timeoutConn) Read(b []byte) (n int, err error) { c.continueRead = false } if !c.continueRead { - var packet uint8 + var packet packetType packet, err = c.buf.BeginRead() if err != nil { err = fmt.Errorf("Cannot read handshake packet: %s", err.Error()) @@ -48,9 +48,11 @@ func (c *timeoutConn) Read(b []byte) (n int, err error) { n, err = c.buf.Read(b) return } - err = c.c.SetDeadline(time.Now().Add(c.timeout)) - if err != nil { - return + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } } return c.c.Read(b) } @@ -58,7 +60,7 @@ func (c *timeoutConn) Read(b []byte) (n int, err error) { func (c *timeoutConn) Write(b []byte) (n int, err error) { if c.buf != nil { if !c.packetPending { - c.buf.BeginPacket(packPrelogin) + c.buf.BeginPacket(packPrelogin, false) c.packetPending = true } n, err = c.buf.Write(b) @@ -67,9 +69,11 @@ func (c *timeoutConn) Write(b []byte) (n int, err error) { } return } - err = c.c.SetDeadline(time.Now().Add(c.timeout)) - if err != nil { - return + if c.timeout > 0 { + err = c.c.SetDeadline(time.Now().Add(c.timeout)) + if err != nil { + return + } } return c.c.Write(b) } diff --git a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go index f853435c6ebdc..7c0cc4f785c39 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/ntlm.go +++ b/vendor/github.com/denisenkom/go-mssqldb/ntlm.go @@ -15,56 +15,56 @@ import ( ) const ( - NEGOTIATE_MESSAGE = 1 - CHALLENGE_MESSAGE = 2 - AUTHENTICATE_MESSAGE = 3 + _NEGOTIATE_MESSAGE = 1 + _CHALLENGE_MESSAGE = 2 + _AUTHENTICATE_MESSAGE = 3 ) const ( - NEGOTIATE_UNICODE = 0x00000001 - NEGOTIATE_OEM = 0x00000002 - NEGOTIATE_TARGET = 0x00000004 - NEGOTIATE_SIGN = 0x00000010 - NEGOTIATE_SEAL = 0x00000020 - NEGOTIATE_DATAGRAM = 0x00000040 - NEGOTIATE_LMKEY = 0x00000080 - NEGOTIATE_NTLM = 0x00000200 - NEGOTIATE_ANONYMOUS = 0x00000800 - NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000 - NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000 - NEGOTIATE_ALWAYS_SIGN = 0x00008000 - NEGOTIATE_TARGET_TYPE_DOMAIN = 0x00010000 - NEGOTIATE_TARGET_TYPE_SERVER = 0x00020000 - NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000 - NEGOTIATE_IDENTIFY = 0x00100000 - REQUEST_NON_NT_SESSION_KEY = 0x00400000 - NEGOTIATE_TARGET_INFO = 0x00800000 - NEGOTIATE_VERSION = 0x02000000 - NEGOTIATE_128 = 0x20000000 - NEGOTIATE_KEY_EXCH = 0x40000000 - NEGOTIATE_56 = 0x80000000 + _NEGOTIATE_UNICODE = 0x00000001 + _NEGOTIATE_OEM = 0x00000002 + _NEGOTIATE_TARGET = 0x00000004 + _NEGOTIATE_SIGN = 0x00000010 + _NEGOTIATE_SEAL = 0x00000020 + _NEGOTIATE_DATAGRAM = 0x00000040 + _NEGOTIATE_LMKEY = 0x00000080 + _NEGOTIATE_NTLM = 0x00000200 + _NEGOTIATE_ANONYMOUS = 0x00000800 + _NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000 + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000 + _NEGOTIATE_ALWAYS_SIGN = 0x00008000 + _NEGOTIATE_TARGET_TYPE_DOMAIN = 0x00010000 + _NEGOTIATE_TARGET_TYPE_SERVER = 0x00020000 + _NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000 + _NEGOTIATE_IDENTIFY = 0x00100000 + _REQUEST_NON_NT_SESSION_KEY = 0x00400000 + _NEGOTIATE_TARGET_INFO = 0x00800000 + _NEGOTIATE_VERSION = 0x02000000 + _NEGOTIATE_128 = 0x20000000 + _NEGOTIATE_KEY_EXCH = 0x40000000 + _NEGOTIATE_56 = 0x80000000 ) -const NEGOTIATE_FLAGS = NEGOTIATE_UNICODE | - NEGOTIATE_NTLM | - NEGOTIATE_OEM_DOMAIN_SUPPLIED | - NEGOTIATE_OEM_WORKSTATION_SUPPLIED | - NEGOTIATE_ALWAYS_SIGN | - NEGOTIATE_EXTENDED_SESSIONSECURITY +const _NEGOTIATE_FLAGS = _NEGOTIATE_UNICODE | + _NEGOTIATE_NTLM | + _NEGOTIATE_OEM_DOMAIN_SUPPLIED | + _NEGOTIATE_OEM_WORKSTATION_SUPPLIED | + _NEGOTIATE_ALWAYS_SIGN | + _NEGOTIATE_EXTENDED_SESSIONSECURITY -type NTLMAuth struct { +type ntlmAuth struct { Domain string UserName string Password string Workstation string } -func getAuth(user, password, service, workstation string) (Auth, bool) { +func getAuth(user, password, service, workstation string) (auth, bool) { if !strings.ContainsRune(user, '\\') { return nil, false } domain_user := strings.SplitN(user, "\\", 2) - return &NTLMAuth{ + return &ntlmAuth{ Domain: domain_user[0], UserName: domain_user[1], Password: password, @@ -86,13 +86,13 @@ func utf16le(val string) []byte { return v } -func (auth *NTLMAuth) InitialBytes() ([]byte, error) { +func (auth *ntlmAuth) InitialBytes() ([]byte, error) { domain_len := len(auth.Domain) workstation_len := len(auth.Workstation) msg := make([]byte, 40+domain_len+workstation_len) copy(msg, []byte("NTLMSSP\x00")) - binary.LittleEndian.PutUint32(msg[8:], NEGOTIATE_MESSAGE) - binary.LittleEndian.PutUint32(msg[12:], NEGOTIATE_FLAGS) + binary.LittleEndian.PutUint32(msg[8:], _NEGOTIATE_MESSAGE) + binary.LittleEndian.PutUint32(msg[12:], _NEGOTIATE_FLAGS) // Domain Name Fields binary.LittleEndian.PutUint16(msg[16:], uint16(domain_len)) binary.LittleEndian.PutUint16(msg[18:], uint16(domain_len)) @@ -198,11 +198,11 @@ func ntlmSessionResponse(clientNonce [8]byte, serverChallenge [8]byte, password return response(hash, passwordHash) } -func (auth *NTLMAuth) NextBytes(bytes []byte) ([]byte, error) { +func (auth *ntlmAuth) NextBytes(bytes []byte) ([]byte, error) { if string(bytes[0:8]) != "NTLMSSP\x00" { return nil, errorNTLM } - if binary.LittleEndian.Uint32(bytes[8:12]) != CHALLENGE_MESSAGE { + if binary.LittleEndian.Uint32(bytes[8:12]) != _CHALLENGE_MESSAGE { return nil, errorNTLM } flags := binary.LittleEndian.Uint32(bytes[20:24]) @@ -210,7 +210,7 @@ func (auth *NTLMAuth) NextBytes(bytes []byte) ([]byte, error) { copy(challenge[:], bytes[24:32]) var lm, nt []byte - if (flags & NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 { + if (flags & _NEGOTIATE_EXTENDED_SESSIONSECURITY) != 0 { nonce := clientChallenge() var lm_bytes [24]byte copy(lm_bytes[:8], nonce[:]) @@ -235,7 +235,7 @@ func (auth *NTLMAuth) NextBytes(bytes []byte) ([]byte, error) { msg := make([]byte, 88+lm_len+nt_len+domain_len+user_len+workstation_len) copy(msg, []byte("NTLMSSP\x00")) - binary.LittleEndian.PutUint32(msg[8:], AUTHENTICATE_MESSAGE) + binary.LittleEndian.PutUint32(msg[8:], _AUTHENTICATE_MESSAGE) // Lm Challenge Response Fields binary.LittleEndian.PutUint16(msg[12:], uint16(lm_len)) binary.LittleEndian.PutUint16(msg[14:], uint16(lm_len)) @@ -279,5 +279,5 @@ func (auth *NTLMAuth) NextBytes(bytes []byte) ([]byte, error) { return msg, nil } -func (auth *NTLMAuth) Free() { +func (auth *ntlmAuth) Free() { } diff --git a/vendor/github.com/denisenkom/go-mssqldb/parser.go b/vendor/github.com/denisenkom/go-mssqldb/parser.go index 9e37c16a655c1..8021ca603c954 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/parser.go +++ b/vendor/github.com/denisenkom/go-mssqldb/parser.go @@ -11,6 +11,9 @@ type parser struct { w bytes.Buffer paramCount int paramMax int + + // using map as a set + namedParams map[string]bool } func (p *parser) next() (rune, bool) { @@ -39,13 +42,14 @@ type stateFunc func(*parser) stateFunc func parseParams(query string) (string, int) { p := &parser{ - r: bytes.NewReader([]byte(query)), + r: bytes.NewReader([]byte(query)), + namedParams: map[string]bool{}, } state := parseNormal for state != nil { state = state(p) } - return p.w.String(), p.paramMax + return p.w.String(), p.paramMax + len(p.namedParams) } func parseNormal(p *parser) stateFunc { @@ -55,7 +59,7 @@ func parseNormal(p *parser) stateFunc { return nil } if ch == '?' { - return parseParameter + return parseOrdinalParameter } else if ch == '$' || ch == ':' { ch2, ok := p.next() if !ok { @@ -64,7 +68,9 @@ func parseNormal(p *parser) stateFunc { } p.unread() if ch2 >= '0' && ch2 <= '9' { - return parseParameter + return parseOrdinalParameter + } else if 'a' <= ch2 && ch2 <= 'z' || 'A' <= ch2 && ch2 <= 'Z' { + return parseNamedParameter } } p.write(ch) @@ -83,7 +89,7 @@ func parseNormal(p *parser) stateFunc { } } -func parseParameter(p *parser) stateFunc { +func parseOrdinalParameter(p *parser) stateFunc { var paramN int var ok bool for { @@ -113,6 +119,30 @@ func parseParameter(p *parser) stateFunc { return parseNormal } +func parseNamedParameter(p *parser) stateFunc { + var paramName string + var ok bool + for { + var ch rune + ch, ok = p.next() + if ok && (ch >= '0' && ch <= '9' || 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') { + paramName = paramName + string(ch) + } else { + break + } + } + if ok { + p.unread() + } + p.namedParams[paramName] = true + p.w.WriteString("@") + p.w.WriteString(paramName) + if !ok { + return nil + } + return parseNormal +} + func parseQuote(p *parser) stateFunc { for { ch, ok := p.next() diff --git a/vendor/github.com/denisenkom/go-mssqldb/rpc.go b/vendor/github.com/denisenkom/go-mssqldb/rpc.go index 00b9b1e217b68..4ca22578fae19 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/rpc.go +++ b/vendor/github.com/denisenkom/go-mssqldb/rpc.go @@ -4,7 +4,7 @@ import ( "encoding/binary" ) -type ProcId struct { +type procId struct { id uint16 name string } @@ -15,24 +15,13 @@ const ( fDefaultValue = 2 ) -type Param struct { +type param struct { Name string Flags uint8 ti typeInfo buffer []byte } -func MakeProcId(name string) (res ProcId) { - res.name = name - if len(name) == 0 { - panic("Proc name shouln't be empty") - } - if len(name) >= 0xffff { - panic("Invalid length of procedure name, should be less than 0xffff") - } - return res -} - const ( fWithRecomp = 1 fNoMetaData = 2 @@ -40,25 +29,25 @@ const ( ) var ( - Sp_Cursor = ProcId{1, ""} - Sp_CursorOpen = ProcId{2, ""} - Sp_CursorPrepare = ProcId{3, ""} - Sp_CursorExecute = ProcId{4, ""} - Sp_CursorPrepExec = ProcId{5, ""} - Sp_CursorUnprepare = ProcId{6, ""} - Sp_CursorFetch = ProcId{7, ""} - Sp_CursorOption = ProcId{8, ""} - Sp_CursorClose = ProcId{9, ""} - Sp_ExecuteSql = ProcId{10, ""} - Sp_Prepare = ProcId{11, ""} - Sp_PrepExec = ProcId{13, ""} - Sp_PrepExecRpc = ProcId{14, ""} - Sp_Unprepare = ProcId{15, ""} + sp_Cursor = procId{1, ""} + sp_CursorOpen = procId{2, ""} + sp_CursorPrepare = procId{3, ""} + sp_CursorExecute = procId{4, ""} + sp_CursorPrepExec = procId{5, ""} + sp_CursorUnprepare = procId{6, ""} + sp_CursorFetch = procId{7, ""} + sp_CursorOption = procId{8, ""} + sp_CursorClose = procId{9, ""} + sp_ExecuteSql = procId{10, ""} + sp_Prepare = procId{11, ""} + sp_PrepExec = procId{13, ""} + sp_PrepExecRpc = procId{14, ""} + sp_Unprepare = procId{15, ""} ) // http://msdn.microsoft.com/en-us/library/dd357576.aspx -func sendRpc(buf *tdsBuffer, headers []headerStruct, proc ProcId, flags uint16, params []Param) (err error) { - buf.BeginPacket(packRPCRequest) +func sendRpc(buf *tdsBuffer, headers []headerStruct, proc procId, flags uint16, params []param, resetSession bool) (err error) { + buf.BeginPacket(packRPCRequest, resetSession) writeAllHeaders(buf, headers) if len(proc.name) == 0 { var idswitch uint16 = 0xffff diff --git a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go index a6e95051c9fde..9b5bc6893f061 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go +++ b/vendor/github.com/denisenkom/go-mssqldb/sspi_windows.go @@ -113,7 +113,7 @@ type SSPIAuth struct { ctxt SecHandle } -func getAuth(user, password, service, workstation string) (Auth, bool) { +func getAuth(user, password, service, workstation string) (auth, bool) { if user == "" { return &SSPIAuth{Service: service}, true } diff --git a/vendor/github.com/denisenkom/go-mssqldb/tds.go b/vendor/github.com/denisenkom/go-mssqldb/tds.go index fd42dba34a26a..16d9ca826453b 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/tds.go +++ b/vendor/github.com/denisenkom/go-mssqldb/tds.go @@ -1,6 +1,7 @@ package mssql import ( + "context" "crypto/tls" "crypto/x509" "encoding/binary" @@ -9,11 +10,13 @@ import ( "io" "io/ioutil" "net" + "net/url" "os" "sort" "strconv" "strings" "time" + "unicode" "unicode/utf16" "unicode/utf8" ) @@ -47,13 +50,16 @@ func parseInstances(msg []byte) map[string]map[string]string { return results } -func getInstances(address string) (map[string]map[string]string, error) { - conn, err := net.DialTimeout("udp", address+":1434", 5*time.Second) +func getInstances(ctx context.Context, d Dialer, address string) (map[string]map[string]string, error) { + maxTime := 5 * time.Second + ctx, cancel := context.WithTimeout(ctx, maxTime) + defer cancel() + conn, err := d.DialContext(ctx, "udp", address+":1434") if err != nil { return nil, err } defer conn.Close() - conn.SetDeadline(time.Now().Add(5 * time.Second)) + conn.SetDeadline(time.Now().Add(maxTime)) _, err = conn.Write([]byte{3}) if err != nil { return nil, err @@ -79,11 +85,16 @@ const ( ) // packet types +// https://msdn.microsoft.com/en-us/library/dd304214.aspx const ( - packSQLBatch = 1 - packRPCRequest = 3 - packReply = 4 - packCancel = 6 + packSQLBatch packetType = 1 + packRPCRequest = 3 + packReply = 4 + + // 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx + // 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx + packAttention = 6 + packBulkLoadBCP = 7 packTransMgrReq = 14 packNormal = 15 @@ -119,7 +130,7 @@ type tdsSession struct { columns []columnStruct tranid uint64 logFlags uint64 - log *Logger + log optionalLogger routedServer string routedPort uint16 } @@ -131,6 +142,7 @@ const ( logSQL = 8 logParams = 16 logTransaction = 32 + logDebug = 64 ) type columnStruct struct { @@ -140,19 +152,19 @@ type columnStruct struct { ti typeInfo } -type KeySlice []uint8 +type keySlice []uint8 -func (p KeySlice) Len() int { return len(p) } -func (p KeySlice) Less(i, j int) bool { return p[i] < p[j] } -func (p KeySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p keySlice) Len() int { return len(p) } +func (p keySlice) Less(i, j int) bool { return p[i] < p[j] } +func (p keySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } // http://msdn.microsoft.com/en-us/library/dd357559.aspx func writePrelogin(w *tdsBuffer, fields map[uint8][]byte) error { var err error - w.BeginPacket(packPrelogin) + w.BeginPacket(packPrelogin, false) offset := uint16(5*len(fields) + 1) - keys := make(KeySlice, 0, len(fields)) + keys := make(keySlice, 0, len(fields)) for k, _ := range fields { keys = append(keys, k) } @@ -340,7 +352,7 @@ func manglePassword(password string) []byte { // http://msdn.microsoft.com/en-us/library/dd304019.aspx func sendLogin(w *tdsBuffer, login login) error { - w.BeginPacket(packLogin7) + w.BeginPacket(packLogin7, false) hostname := str2ucs2(login.HostName) username := str2ucs2(login.UserName) password := manglePassword(login.Password) @@ -490,6 +502,11 @@ func readBVarChar(r io.Reader) (res string, err error) { if err != nil { return "", err } + + // A zero length could be returned, return an empty string + if numchars == 0 { + return "", nil + } return readUcs2(r, int(numchars)) } @@ -588,7 +605,7 @@ func (hdr transDescrHdr) pack() (res []byte) { } func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { - // calculatint total length + // Calculating total length. var totallen uint32 = 4 for _, hdr := range headers { totallen += 4 + 2 + uint32(len(hdr.data)) @@ -616,10 +633,8 @@ func writeAllHeaders(w io.Writer, headers []headerStruct) (err error) { return nil } -func sendSqlBatch72(buf *tdsBuffer, - sqltext string, - headers []headerStruct) (err error) { - buf.BeginPacket(packSQLBatch) +func sendSqlBatch72(buf *tdsBuffer, sqltext string, headers []headerStruct, resetSession bool) (err error) { + buf.BeginPacket(packSQLBatch, resetSession) if err = writeAllHeaders(buf, headers); err != nil { return @@ -632,6 +647,13 @@ func sendSqlBatch72(buf *tdsBuffer, return buf.FinishPacket() } +// 2.2.1.7 Attention: https://msdn.microsoft.com/en-us/library/dd341449.aspx +// 4.19.2 Out-of-Band Attention Signal: https://msdn.microsoft.com/en-us/library/dd305167.aspx +func sendAttention(buf *tdsBuffer) error { + buf.BeginPacket(packAttention, false) + return buf.FinishPacket() +} + type connectParams struct { logFlags uint64 port uint64 @@ -654,6 +676,7 @@ type connectParams struct { typeFlags uint8 failOverPartner string failOverPort uint64 + packetSize uint16 } func splitConnectionString(dsn string) (res map[string]string) { @@ -677,19 +700,251 @@ func splitConnectionString(dsn string) (res map[string]string) { return res } +// Splits a URL in the ODBC format +func splitConnectionStringOdbc(dsn string) (map[string]string, error) { + res := map[string]string{} + + type parserState int + const ( + // Before the start of a key + parserStateBeforeKey parserState = iota + + // Inside a key + parserStateKey + + // Beginning of a value. May be bare or braced + parserStateBeginValue + + // Inside a bare value + parserStateBareValue + + // Inside a braced value + parserStateBracedValue + + // A closing brace inside a braced value. + // May be the end of the value or an escaped closing brace, depending on the next character + parserStateBracedValueClosingBrace + + // After a value. Next character should be a semicolon or whitespace. + parserStateEndValue + ) + + var state = parserStateBeforeKey + + var key string + var value string + + for i, c := range dsn { + switch state { + case parserStateBeforeKey: + switch { + case c == '=': + return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) + case !unicode.IsSpace(c) && c != ';': + state = parserStateKey + key += string(c) + } + + case parserStateKey: + switch c { + case '=': + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + state = parserStateBeginValue + + case ';': + // Key without value + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", i) + } + + res[key] = value + key = "" + value = "" + state = parserStateBeforeKey + + default: + key += string(c) + } + + case parserStateBeginValue: + switch { + case c == '{': + state = parserStateBracedValue + case c == ';': + // Empty value + res[key] = value + key = "" + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + state = parserStateBareValue + value += string(c) + } + + case parserStateBareValue: + if c == ';' { + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + key = "" + value = "" + state = parserStateBeforeKey + } else { + value += string(c) + } + + case parserStateBracedValue: + if c == '}' { + state = parserStateBracedValueClosingBrace + } else { + value += string(c) + } + + case parserStateBracedValueClosingBrace: + if c == '}' { + // Escaped closing brace + value += string(c) + state = parserStateBracedValue + continue + } + + // End of braced value + res[key] = value + key = "" + value = "" + + // This character is the first character past the end, + // so it needs to be parsed like the parserStateEndValue state. + state = parserStateEndValue + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + + case parserStateEndValue: + switch { + case c == ';': + state = parserStateBeforeKey + case unicode.IsSpace(c): + // Ignore whitespace + default: + return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) + } + } + } + + switch state { + case parserStateBeforeKey: // Okay + case parserStateKey: // Unfinished key. Treat as key without value. + key = normalizeOdbcKey(key) + if len(key) == 0 { + return res, fmt.Errorf("Unexpected end of key at index %d.", len(dsn)) + } + res[key] = value + case parserStateBeginValue: // Empty value + res[key] = value + case parserStateBareValue: + res[key] = strings.TrimRightFunc(value, unicode.IsSpace) + case parserStateBracedValue: + return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) + case parserStateBracedValueClosingBrace: // End of braced value + res[key] = value + case parserStateEndValue: // Okay + } + + return res, nil +} + +// Normalizes the given string as an ODBC-format key +func normalizeOdbcKey(s string) string { + return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) +} + +// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value +func splitConnectionStringURL(dsn string) (map[string]string, error) { + res := map[string]string{} + + u, err := url.Parse(dsn) + if err != nil { + return res, err + } + + if u.Scheme != "sqlserver" { + return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) + } + + if u.User != nil { + res["user id"] = u.User.Username() + p, exists := u.User.Password() + if exists { + res["password"] = p + } + } + + host, port, err := net.SplitHostPort(u.Host) + if err != nil { + host = u.Host + } + + if len(u.Path) > 0 { + res["server"] = host + "\\" + u.Path[1:] + } else { + res["server"] = host + } + + if len(port) > 0 { + res["port"] = port + } + + query := u.Query() + for k, v := range query { + if len(v) > 1 { + return res, fmt.Errorf("key %s provided more than once", k) + } + res[strings.ToLower(k)] = v[0] + } + + return res, nil +} + func parseConnectParams(dsn string) (connectParams, error) { - params := splitConnectionString(dsn) var p connectParams + + var params map[string]string + if strings.HasPrefix(dsn, "odbc:") { + parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) + if err != nil { + return p, err + } + params = parameters + } else if strings.HasPrefix(dsn, "sqlserver://") { + parameters, err := splitConnectionStringURL(dsn) + if err != nil { + return p, err + } + params = parameters + } else { + params = splitConnectionString(dsn) + } + strlog, ok := params["log"] if ok { var err error - p.logFlags, err = strconv.ParseUint(strlog, 10, 0) + p.logFlags, err = strconv.ParseUint(strlog, 10, 64) if err != nil { return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) } } server := params["server"] - parts := strings.SplitN(server, "\\", 2) + parts := strings.SplitN(server, `\`, 2) p.host = parts[0] if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { p.host = "localhost" @@ -705,36 +960,64 @@ func parseConnectParams(dsn string) (connectParams, error) { strport, ok := params["port"] if ok { var err error - p.port, err = strconv.ParseUint(strport, 0, 16) + p.port, err = strconv.ParseUint(strport, 10, 16) if err != nil { f := "Invalid tcp port '%v': %v" return p, fmt.Errorf(f, strport, err.Error()) } } - p.dial_timeout = 5 * time.Second - p.conn_timeout = 30 * time.Second - strconntimeout, ok := params["connection timeout"] + // https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option + // Default packet size remains at 4096 bytes + p.packetSize = 4096 + strpsize, ok := params["packet size"] if ok { - timeout, err := strconv.ParseUint(strconntimeout, 0, 16) + var err error + psize, err := strconv.ParseUint(strpsize, 0, 16) + if err != nil { + f := "Invalid packet size '%v': %v" + return p, fmt.Errorf(f, strpsize, err.Error()) + } + + // Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes + // NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request + // a higher packet size, the server will respond with an ENVCHANGE request to + // alter the packet size to 16383 bytes. + p.packetSize = uint16(psize) + if p.packetSize < 512 { + p.packetSize = 512 + } else if p.packetSize > 32767 { + p.packetSize = 32767 + } + } + + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + // + // Do not set a connection timeout. Use Context to manage such things. + // Default to zero, but still allow it to be set. + if strconntimeout, ok := params["connection timeout"]; ok { + timeout, err := strconv.ParseUint(strconntimeout, 10, 64) if err != nil { f := "Invalid connection timeout '%v': %v" return p, fmt.Errorf(f, strconntimeout, err.Error()) } p.conn_timeout = time.Duration(timeout) * time.Second } - strdialtimeout, ok := params["dial timeout"] - if ok { - timeout, err := strconv.ParseUint(strdialtimeout, 0, 16) + p.dial_timeout = 15 * time.Second + if strdialtimeout, ok := params["dial timeout"]; ok { + timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) if err != nil { f := "Invalid dial timeout '%v': %v" return p, fmt.Errorf(f, strdialtimeout, err.Error()) } p.dial_timeout = time.Duration(timeout) * time.Second } - keepAlive, ok := params["keepalive"] - if ok { - timeout, err := strconv.ParseUint(keepAlive, 0, 16) + + // default keep alive should be 30 seconds according to spec: + // https://msdn.microsoft.com/en-us/library/dd341108.aspx + p.keepAlive = 30 * time.Second + if keepAlive, ok := params["keepalive"]; ok { + timeout, err := strconv.ParseUint(keepAlive, 10, 64) if err != nil { f := "Invalid keepAlive value '%s': %s" return p, fmt.Errorf(f, keepAlive, err.Error()) @@ -743,7 +1026,7 @@ func parseConnectParams(dsn string) (connectParams, error) { } encrypt, ok := params["encrypt"] if ok { - if strings.ToUpper(encrypt) == "DISABLE" { + if strings.EqualFold(encrypt, "DISABLE") { p.disableEncryption = true } else { var err error @@ -819,7 +1102,7 @@ func parseConnectParams(dsn string) (connectParams, error) { return p, nil } -type Auth interface { +type auth interface { InitialBytes() ([]byte, error) NextBytes([]byte) ([]byte, error) Free() @@ -828,7 +1111,7 @@ type Auth interface { // SQL Server AlwaysOn Availability Group Listeners are bound by DNS to a // list of IP addresses. So if there is more than one, try them all and // use the first one that allows a connection. -func dialConnection(p connectParams) (conn net.Conn, err error) { +func dialConnection(ctx context.Context, c *Connector, p connectParams) (conn net.Conn, err error) { var ips []net.IP ips, err = net.LookupIP(p.host) if err != nil { @@ -839,9 +1122,9 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { ips = []net.IP{ip} } if len(ips) == 1 { - d := createDialer(p) + d := c.getDialer(&p) addr := net.JoinHostPort(ips[0].String(), strconv.Itoa(int(p.port))) - conn, err = d.Dial("tcp", addr) + conn, err = d.DialContext(ctx, "tcp", addr) } else { //Try Dials in parallel to avoid waiting for timeouts. @@ -850,9 +1133,9 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { portStr := strconv.Itoa(int(p.port)) for _, ip := range ips { go func(ip net.IP) { - d := createDialer(p) + d := c.getDialer(&p) addr := net.JoinHostPort(ip.String(), portStr) - conn, err := d.Dial("tcp", addr) + conn, err := d.DialContext(ctx, "tcp", addr) if err == nil { connChan <- conn } else { @@ -887,16 +1170,21 @@ func dialConnection(p connectParams) (conn net.Conn, err error) { f := "Unable to open tcp connection with host '%v:%v': %v" return nil, fmt.Errorf(f, p.host, p.port, err.Error()) } - return conn, err } -func connect(p connectParams) (res *tdsSession, err error) { - res = nil +func connect(ctx context.Context, c *Connector, log optionalLogger, p connectParams) (res *tdsSession, err error) { + dialCtx := ctx + if p.dial_timeout > 0 { + var cancel func() + dialCtx, cancel = context.WithTimeout(ctx, p.dial_timeout) + defer cancel() + } // if instance is specified use instance resolution service if p.instance != "" { p.instance = strings.ToUpper(p.instance) - instances, err := getInstances(p.host) + d := c.getDialer(&p) + instances, err := getInstances(dialCtx, d, p.host) if err != nil { f := "Unable to get instances from Sql Server Browser on host %v: %v" return nil, fmt.Errorf(f, p.host, err.Error()) @@ -914,16 +1202,17 @@ func connect(p connectParams) (res *tdsSession, err error) { } initiate_connection: - conn, err := dialConnection(p) + conn, err := dialConnection(dialCtx, c, p) if err != nil { return nil, err } - toconn := NewTimeoutConn(conn, p.conn_timeout) + toconn := newTimeoutConn(conn, p.conn_timeout) - outbuf := newTdsBuffer(4096, toconn) + outbuf := newTdsBuffer(p.packetSize, toconn) sess := tdsSession{ buf: outbuf, + log: log, logFlags: p.logFlags, } @@ -969,8 +1258,7 @@ initiate_connection: if p.certificate != "" { pem, err := ioutil.ReadFile(p.certificate) if err != nil { - f := "Cannot read certificate '%s': %s" - return nil, fmt.Errorf(f, p.certificate, err.Error()) + return nil, fmt.Errorf("Cannot read certificate %q: %v", p.certificate, err) } certs := x509.NewCertPool() certs.AppendCertsFromPEM(pem) @@ -980,15 +1268,20 @@ initiate_connection: config.InsecureSkipVerify = true } config.ServerName = p.hostInCertificate + // fix for https://github.com/denisenkom/go-mssqldb/issues/166 + // Go implementation of TLS payload size heuristic algorithm splits single TDS package to multiple TCP segments, + // while SQL Server seems to expect one TCP segment per encrypted TDS package. + // Setting DynamicRecordSizingDisabled to true disables that algorithm and uses 16384 bytes per TLS package + config.DynamicRecordSizingDisabled = true outbuf.transport = conn toconn.buf = outbuf tlsConn := tls.Client(toconn, &config) err = tlsConn.Handshake() + toconn.buf = nil outbuf.transport = tlsConn if err != nil { - f := "TLS Handshake failed: %s" - return nil, fmt.Errorf(f, err.Error()) + return nil, fmt.Errorf("TLS Handshake failed: %v", err) } if encrypt == encryptOff { outbuf.afterFirst = func() { @@ -999,7 +1292,7 @@ initiate_connection: login := login{ TDSVersion: verTDS74, - PacketSize: uint32(len(outbuf.buf)), + PacketSize: uint32(outbuf.PackageSize()), Database: p.database, OptionFlags2: fODBC, // to get unlimited TEXTSIZE HostName: p.workstation, @@ -1028,7 +1321,7 @@ initiate_connection: var sspi_msg []byte continue_login: tokchan := make(chan tokenStruct, 5) - go processResponse(&sess, tokchan) + go processResponse(context.Background(), &sess, tokchan, nil) success := false for tok := range tokchan { switch token := tok.(type) { @@ -1042,10 +1335,14 @@ continue_login: sess.loginAck = token case error: return nil, fmt.Errorf("Login error: %s", token.Error()) + case doneStruct: + if token.isError() { + return nil, fmt.Errorf("Login error: %s", token.getError()) + } } } if sspi_msg != nil { - outbuf.BeginPacket(packSSPIMessage) + outbuf.BeginPacket(packSSPIMessage, false) _, err = outbuf.Write(sspi_msg) if err != nil { return nil, err diff --git a/vendor/github.com/denisenkom/go-mssqldb/token.go b/vendor/github.com/denisenkom/go-mssqldb/token.go index f20bd14cc9ed3..1acac8a5d2bca 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/token.go +++ b/vendor/github.com/denisenkom/go-mssqldb/token.go @@ -1,30 +1,40 @@ package mssql import ( + "context" "encoding/binary" + "errors" + "fmt" "io" + "net" "strconv" "strings" ) +//go:generate stringer -type token + +type token byte + // token ids const ( - tokenReturnStatus = 121 // 0x79 - tokenColMetadata = 129 // 0x81 - tokenOrder = 169 // 0xA9 - tokenError = 170 // 0xAA - tokenInfo = 171 // 0xAB - tokenLoginAck = 173 // 0xad - tokenRow = 209 // 0xd1 - tokenNbcRow = 210 // 0xd2 - tokenEnvChange = 227 // 0xE3 - tokenSSPI = 237 // 0xED - tokenDone = 253 // 0xFD - tokenDoneProc = 254 - tokenDoneInProc = 255 + tokenReturnStatus token = 121 // 0x79 + tokenColMetadata token = 129 // 0x81 + tokenOrder token = 169 // 0xA9 + tokenError token = 170 // 0xAA + tokenInfo token = 171 // 0xAB + tokenReturnValue token = 0xAC + tokenLoginAck token = 173 // 0xad + tokenRow token = 209 // 0xd1 + tokenNbcRow token = 210 // 0xd2 + tokenEnvChange token = 227 // 0xE3 + tokenSSPI token = 237 // 0xED + tokenDone token = 253 // 0xFD + tokenDoneProc token = 254 + tokenDoneInProc token = 255 ) // done flags +// https://msdn.microsoft.com/en-us/library/dd340421.aspx const ( doneFinal = 0 doneMore = 1 @@ -59,6 +69,13 @@ const ( envRouting = 20 ) +// COLMETADATA flags +// https://msdn.microsoft.com/en-us/library/dd357363.aspx +const ( + colFlagNullable = 1 + // TODO implement more flags +) + // interface for all tokens type tokenStruct interface{} @@ -70,6 +87,19 @@ type doneStruct struct { Status uint16 CurCmd uint16 RowCount uint64 + errors []Error +} + +func (d doneStruct) isError() bool { + return d.Status&doneError != 0 || len(d.errors) > 0 +} + +func (d doneStruct) getError() Error { + if len(d.errors) > 0 { + return d.errors[len(d.errors)-1] + } else { + return Error{Message: "Request failed but didn't provide reason"} + } } type doneInProcStruct doneStruct @@ -120,27 +150,23 @@ func processEnvChg(sess *tdsSession) { badStreamPanic(err) } case envTypLanguage: - //currently ignored - // old value - _, err = readBVarChar(r) - if err != nil { - badStreamPanic(err) - } + // currently ignored // new value - _, err = readBVarChar(r) - if err != nil { + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - case envTypCharset: - //currently ignored // old value - _, err = readBVarChar(r) - if err != nil { + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } + case envTypCharset: + // currently ignored // new value - _, err = readBVarChar(r) - if err != nil { + if _, err = readBVarChar(r); err != nil { + badStreamPanic(err) + } + // old value + if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envTypPacketSize: @@ -156,38 +182,55 @@ func processEnvChg(sess *tdsSession) { if err != nil { badStreamPanicf("Invalid Packet size value returned from server (%s): %s", packetsize, err.Error()) } - if len(sess.buf.buf) != packetsizei { - newbuf := make([]byte, packetsizei) - copy(newbuf, sess.buf.buf) - sess.buf.buf = newbuf - } + sess.buf.ResizeBuffer(packetsizei) case envSortId: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envSortFlags: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envSqlCollation: // currently ignored - // old value - if _, err = readBVarChar(r); err != nil { + var collationSize uint8 + err = binary.Read(r, binary.LittleEndian, &collationSize) + if err != nil { badStreamPanic(err) } - // new value + + // SQL Collation data should contain 5 bytes in length + if collationSize != 5 { + badStreamPanicf("Invalid SQL Collation size value returned from server: %d", collationSize) + } + + // 4 bytes, contains: LCID ColFlags Version + var info uint32 + err = binary.Read(r, binary.LittleEndian, &info) + if err != nil { + badStreamPanic(err) + } + + // 1 byte, contains: sortID + var sortID uint8 + err = binary.Read(r, binary.LittleEndian, &sortID) + if err != nil { + badStreamPanic(err) + } + + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } @@ -226,21 +269,21 @@ func processEnvChg(sess *tdsSession) { sess.tranid = 0 case envEnlistDTC: // currently ignored - // old value + // new value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value, should be 0 + // old value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } case envDefectTran: // currently ignored - // old value, should be 0 + // new value if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } - // new value + // old value, should be 0 if _, err = readBVarChar(r); err != nil { badStreamPanic(err) } @@ -342,11 +385,9 @@ func processEnvChg(sess *tdsSession) { } } -type returnStatus int32 - // http://msdn.microsoft.com/en-us/library/dd358180.aspx -func parseReturnStatus(r *tdsBuffer) returnStatus { - return returnStatus(r.int32()) +func parseReturnStatus(r *tdsBuffer) ReturnStatus { + return ReturnStatus(r.int32()) } func parseOrder(r *tdsBuffer) (res orderStruct) { @@ -358,6 +399,7 @@ func parseOrder(r *tdsBuffer) (res orderStruct) { return res } +// https://msdn.microsoft.com/en-us/library/dd340421.aspx func parseDone(r *tdsBuffer) (res doneStruct) { res.Status = r.uint16() res.CurCmd = r.uint16() @@ -365,6 +407,7 @@ func parseDone(r *tdsBuffer) (res doneStruct) { return res } +// https://msdn.microsoft.com/en-us/library/dd340553.aspx func parseDoneInProc(r *tdsBuffer) (res doneInProcStruct) { res.Status = r.uint16() res.CurCmd = r.uint16() @@ -473,26 +516,57 @@ func parseInfo(r *tdsBuffer) (res Error) { return } -func processResponse(sess *tdsSession, ch chan tokenStruct) { +// https://msdn.microsoft.com/en-us/library/dd303881.aspx +func parseReturnValue(r *tdsBuffer) (nv namedValue) { + /* + ParamOrdinal + ParamName + Status + UserType + Flags + TypeInfo + CryptoMetadata + Value + */ + r.uint16() + nv.Name = r.BVarChar() + r.byte() + r.uint32() // UserType (uint16 prior to 7.2) + r.uint16() + ti := readTypeInfo(r) + nv.Value = ti.Reader(&ti, r) + return +} + +func processSingleResponse(sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { defer func() { if err := recover(); err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: Intercepted panic %v", err) + } ch <- err } close(ch) }() + packet_type, err := sess.buf.BeginRead() if err != nil { + if sess.logFlags&logErrors != 0 { + sess.log.Printf("ERROR: BeginRead failed %v", err) + } ch <- err return } if packet_type != packReply { - badStreamPanicf("invalid response packet type, expected REPLY, actual: %d", packet_type) + badStreamPanic(fmt.Errorf("unexpected packet type in reply: got %v, expected %v", packet_type, packReply)) } var columns []columnStruct - var lastError Error - var failed bool + errs := make([]Error, 0, 5) for { - token := sess.buf.byte() + token := token(sess.buf.byte()) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got token %v", token) + } switch token { case tokenSSPI: ch <- parseSSPIMsg(sess.buf) @@ -514,18 +588,17 @@ func processResponse(sess *tdsSession, ch chan tokenStruct) { ch <- done case tokenDone, tokenDoneProc: done := parseDone(sess.buf) - if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { - sess.log.Printf("(%d row(s) affected)\n", done.RowCount) - } - if done.Status&doneError != 0 || failed { - ch <- lastError - return + done.errors = errs + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got DONE or DONEPROC status=%d", done.Status) } if done.Status&doneSrvError != 0 { - lastError.Message = "Server Error" - ch <- lastError + ch <- errors.New("SQL Server had internal error") return } + if sess.logFlags&logRows != 0 && done.Status&doneCount != 0 { + sess.log.Printf("(%d row(s) affected)\n", done.RowCount) + } ch <- done if done.Status&doneMore == 0 { return @@ -544,18 +617,188 @@ func processResponse(sess *tdsSession, ch chan tokenStruct) { case tokenEnvChange: processEnvChg(sess) case tokenError: - lastError = parseError72(sess.buf) - failed = true + err := parseError72(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got ERROR %d %s", err.Number, err.Message) + } + errs = append(errs, err) if sess.logFlags&logErrors != 0 { - sess.log.Println(lastError.Message) + sess.log.Println(err.Message) } case tokenInfo: info := parseInfo(sess.buf) + if sess.logFlags&logDebug != 0 { + sess.log.Printf("got INFO %d %s", info.Number, info.Message) + } if sess.logFlags&logMessages != 0 { sess.log.Println(info.Message) } + case tokenReturnValue: + nv := parseReturnValue(sess.buf) + if len(nv.Name) > 0 { + name := nv.Name[1:] // Remove the leading "@". + if ov, has := outs[name]; has { + err = scanIntoOut(name, nv.Value, ov) + if err != nil { + fmt.Println("scan error", err) + ch <- err + } + } + } default: - badStreamPanicf("Unknown token type: %d", token) + badStreamPanic(fmt.Errorf("unknown token type returned: %v", token)) + } + } +} + +type parseRespIter byte + +const ( + parseRespIterContinue parseRespIter = iota // Continue parsing current token. + parseRespIterNext // Fetch the next token. + parseRespIterDone // Done with parsing the response. +) + +type parseRespState byte + +const ( + parseRespStateNormal parseRespState = iota // Normal response state. + parseRespStateCancel // Query is canceled, wait for server to confirm. + parseRespStateClosing // Waiting for tokens to come through. +) + +type parseResp struct { + sess *tdsSession + ctxDone <-chan struct{} + state parseRespState + cancelError error +} + +func (ts *parseResp) sendAttention(ch chan tokenStruct) parseRespIter { + if err := sendAttention(ts.sess.buf); err != nil { + ts.dlogf("failed to send attention signal %v", err) + ch <- err + return parseRespIterDone + } + ts.state = parseRespStateCancel + return parseRespIterContinue +} + +func (ts *parseResp) dlog(msg string) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Println(msg) + } +} +func (ts *parseResp) dlogf(f string, v ...interface{}) { + if ts.sess.logFlags&logDebug != 0 { + ts.sess.log.Printf(f, v...) + } +} + +func (ts *parseResp) iter(ctx context.Context, ch chan tokenStruct, tokChan chan tokenStruct) parseRespIter { + switch ts.state { + default: + panic("unknown state") + case parseRespStateNormal: + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished") + return parseRespIterDone + } + if err, ok := tok.(net.Error); ok && err.Timeout() { + ts.cancelError = err + ts.dlog("got timeout error, sending attention signal to server") + return ts.sendAttention(ch) + } + // Pass the token along. + ch <- tok + return parseRespIterContinue + + case <-ts.ctxDone: + ts.ctxDone = nil + ts.dlog("got cancel message, sending attention signal to server") + return ts.sendAttention(ch) + } + case parseRespStateCancel: // Read all responses until a DONE or error is received.Auth + select { + case tok, ok := <-tokChan: + if !ok { + ts.dlog("response finished but waiting for attention ack") + return parseRespIterNext + } + switch tok := tok.(type) { + default: + // Ignore all other tokens while waiting. + // The TDS spec says other tokens may arrive after an attention + // signal is sent. Ignore these tokens and continue looking for + // a DONE with attention confirm mark. + case doneStruct: + if tok.Status&doneAttn != 0 { + ts.dlog("got cancellation confirmation from server") + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } else { + ch <- ctx.Err() + } + return parseRespIterDone + } + + // If an error happens during cancel, pass it along and just stop. + // We are uncertain to receive more tokens. + case error: + ch <- tok + ts.state = parseRespStateClosing + } + return parseRespIterContinue + case <-ts.ctxDone: + ts.ctxDone = nil + ts.state = parseRespStateClosing + return parseRespIterContinue + } + case parseRespStateClosing: // Wait for current token chan to close. + if _, ok := <-tokChan; !ok { + ts.dlog("response finished") + return parseRespIterDone + } + return parseRespIterContinue + } +} + +func processResponse(ctx context.Context, sess *tdsSession, ch chan tokenStruct, outs map[string]interface{}) { + ts := &parseResp{ + sess: sess, + ctxDone: ctx.Done(), + } + defer func() { + // Ensure any remaining error is piped through + // or the query may look like it executed when it actually failed. + if ts.cancelError != nil { + ch <- ts.cancelError + ts.cancelError = nil + } + close(ch) + }() + + // Loop over multiple responses. + for { + ts.dlog("initiating response reading") + + tokChan := make(chan tokenStruct) + go processSingleResponse(sess, tokChan, outs) + + // Loop over multiple tokens in response. + tokensLoop: + for { + switch ts.iter(ctx, ch, tokChan) { + case parseRespIterContinue: + // Nothing, continue to next token. + case parseRespIterNext: + break tokensLoop + case parseRespIterDone: + return + } } } } diff --git a/vendor/github.com/denisenkom/go-mssqldb/token_string.go b/vendor/github.com/denisenkom/go-mssqldb/token_string.go new file mode 100644 index 0000000000000..c075b23be0138 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/token_string.go @@ -0,0 +1,53 @@ +// Code generated by "stringer -type token"; DO NOT EDIT + +package mssql + +import "fmt" + +const ( + _token_name_0 = "tokenReturnStatus" + _token_name_1 = "tokenColMetadata" + _token_name_2 = "tokenOrdertokenErrortokenInfo" + _token_name_3 = "tokenLoginAck" + _token_name_4 = "tokenRowtokenNbcRow" + _token_name_5 = "tokenEnvChange" + _token_name_6 = "tokenSSPI" + _token_name_7 = "tokenDonetokenDoneProctokenDoneInProc" +) + +var ( + _token_index_0 = [...]uint8{0, 17} + _token_index_1 = [...]uint8{0, 16} + _token_index_2 = [...]uint8{0, 10, 20, 29} + _token_index_3 = [...]uint8{0, 13} + _token_index_4 = [...]uint8{0, 8, 19} + _token_index_5 = [...]uint8{0, 14} + _token_index_6 = [...]uint8{0, 9} + _token_index_7 = [...]uint8{0, 9, 22, 37} +) + +func (i token) String() string { + switch { + case i == 121: + return _token_name_0 + case i == 129: + return _token_name_1 + case 169 <= i && i <= 171: + i -= 169 + return _token_name_2[_token_index_2[i]:_token_index_2[i+1]] + case i == 173: + return _token_name_3 + case 209 <= i && i <= 210: + i -= 209 + return _token_name_4[_token_index_4[i]:_token_index_4[i+1]] + case i == 227: + return _token_name_5 + case i == 237: + return _token_name_6 + case 253 <= i && i <= 255: + i -= 253 + return _token_name_7[_token_index_7[i]:_token_index_7[i+1]] + default: + return fmt.Sprintf("token(%d)", i) + } +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/tran.go b/vendor/github.com/denisenkom/go-mssqldb/tran.go index ae38107661139..cb6436816f97e 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/tran.go +++ b/vendor/github.com/denisenkom/go-mssqldb/tran.go @@ -1,6 +1,7 @@ +package mssql + // Transaction Manager requests // http://msdn.microsoft.com/en-us/library/dd339887.aspx -package mssql import ( "encoding/binary" @@ -16,9 +17,19 @@ const ( tmSaveXact = 9 ) -func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation uint8, - name string) (err error) { - buf.BeginPacket(packTransMgrReq) +type isoLevel uint8 + +const ( + isolationUseCurrent isoLevel = 0 + isolationReadUncommited = 1 + isolationReadCommited = 2 + isolationRepeatableRead = 3 + isolationSerializable = 4 + isolationSnapshot = 5 +) + +func sendBeginXact(buf *tdsBuffer, headers []headerStruct, isolation isoLevel, name string, resetSession bool) (err error) { + buf.BeginPacket(packTransMgrReq, resetSession) writeAllHeaders(buf, headers) var rqtype uint16 = tmBeginXact err = binary.Write(buf, binary.LittleEndian, &rqtype) @@ -40,8 +51,8 @@ const ( fBeginXact = 1 ) -func sendCommitXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string) error { - buf.BeginPacket(packTransMgrReq) +func sendCommitXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) writeAllHeaders(buf, headers) var rqtype uint16 = tmCommitXact err := binary.Write(buf, binary.LittleEndian, &rqtype) @@ -69,8 +80,8 @@ func sendCommitXact(buf *tdsBuffer, headers []headerStruct, name string, flags u return buf.FinishPacket() } -func sendRollbackXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string) error { - buf.BeginPacket(packTransMgrReq) +func sendRollbackXact(buf *tdsBuffer, headers []headerStruct, name string, flags uint8, isolation uint8, newname string, resetSession bool) error { + buf.BeginPacket(packTransMgrReq, resetSession) writeAllHeaders(buf, headers) var rqtype uint16 = tmRollbackXact err := binary.Write(buf, binary.LittleEndian, &rqtype) diff --git a/vendor/github.com/denisenkom/go-mssqldb/tvp_go19.go b/vendor/github.com/denisenkom/go-mssqldb/tvp_go19.go new file mode 100644 index 0000000000000..45c9aa9460582 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/tvp_go19.go @@ -0,0 +1,232 @@ +// +build go1.9 + +package mssql + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "reflect" + "strings" + "time" +) + +const ( + jsonTag = "json" + tvpTag = "tvp" + skipTagValue = "-" + sqlSeparator = "." +) + +var ( + ErrorEmptyTVPTypeName = errors.New("TVPTypeName must not be empty") + ErrorTypeSlice = errors.New("TVPType must be slice type") + ErrorTypeSliceIsEmpty = errors.New("TVPType mustn't be null value") + ErrorSkip = errors.New("all fields mustn't skip") + ErrorObjectName = errors.New("wrong tvp name") +) + +//TVPType is driver type, which allows supporting Table Valued Parameters (TVP) in SQL Server +type TVPType struct { + //TVP param name, mustn't be default value + TVPTypeName string + //TVP Value Param must be the slice, mustn't be nil + TVPValue interface{} +} + +func (tvp TVPType) check() error { + if len(tvp.TVPTypeName) == 0 { + return ErrorEmptyTVPTypeName + } + if !isProc(tvp.TVPTypeName) { + return ErrorEmptyTVPTypeName + } + if sepCount := getCountSQLSeparators(tvp.TVPTypeName); sepCount > 1 { + return ErrorObjectName + } + valueOf := reflect.ValueOf(tvp.TVPValue) + if valueOf.Kind() != reflect.Slice { + return ErrorTypeSlice + } + if valueOf.IsNil() { + return ErrorTypeSliceIsEmpty + } + if reflect.TypeOf(tvp.TVPValue).Elem().Kind() != reflect.Struct { + return ErrorTypeSlice + } + return nil +} + +func (tvp TVPType) encode(schema, name string) ([]byte, error) { + columnStr, tvpFieldIndexes, err := tvp.columnTypes() + if err != nil { + return nil, err + } + preparedBuffer := make([]byte, 0, 20+(10*len(columnStr))) + buf := bytes.NewBuffer(preparedBuffer) + err = writeBVarChar(buf, "") + if err != nil { + return nil, err + } + + writeBVarChar(buf, schema) + writeBVarChar(buf, name) + binary.Write(buf, binary.LittleEndian, uint16(len(columnStr))) + + for i, column := range columnStr { + binary.Write(buf, binary.LittleEndian, uint32(column.UserType)) + binary.Write(buf, binary.LittleEndian, uint16(column.Flags)) + writeTypeInfo(buf, &columnStr[i].ti) + writeBVarChar(buf, "") + } + err = buf.WriteByte(_TVP_END_TOKEN) + if err != nil { + return nil, err + } + conn := new(Conn) + conn.sess = new(tdsSession) + conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73} + stmt := &Stmt{ + c: conn, + } + + val := reflect.ValueOf(tvp.TVPValue) + for i := 0; i < val.Len(); i++ { + refStr := reflect.ValueOf(val.Index(i).Interface()) + buf.WriteByte(_TVP_ROW_TOKEN) + for _, j := range tvpFieldIndexes { + field := refStr.Field(j) + tvpVal := field.Interface() + valOf := reflect.ValueOf(tvpVal) + elemKind := field.Kind() + if elemKind == reflect.Ptr && valOf.IsNil() { + switch tvpVal.(type) { + case *bool, *time.Time, *int8, *int16, *int32, *int64, *float32, *float64: + binary.Write(buf, binary.LittleEndian, uint8(0)) + continue + default: + binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL)) + continue + } + } + if elemKind == reflect.Slice && valOf.IsNil() { + binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL)) + continue + } + + cval, err := convertInputParameter(tvpVal) + if err != nil { + return nil, fmt.Errorf("failed to convert tvp parameter row col: %s", err) + } + param, err := stmt.makeParam(cval) + if err != nil { + return nil, fmt.Errorf("failed to make tvp parameter row col: %s", err) + } + columnStr[j].ti.Writer(buf, param.ti, param.buffer) + } + } + buf.WriteByte(_TVP_END_TOKEN) + return buf.Bytes(), nil +} + +func (tvp TVPType) columnTypes() ([]columnStruct, []int, error) { + val := reflect.ValueOf(tvp.TVPValue) + var firstRow interface{} + if val.Len() != 0 { + firstRow = val.Index(0).Interface() + } else { + firstRow = reflect.New(reflect.TypeOf(tvp.TVPValue).Elem()).Elem().Interface() + } + + tvpRow := reflect.TypeOf(firstRow) + columnCount := tvpRow.NumField() + defaultValues := make([]interface{}, 0, columnCount) + tvpFieldIndexes := make([]int, 0, columnCount) + for i := 0; i < columnCount; i++ { + field := tvpRow.Field(i) + tvpTagValue, isTvpTag := field.Tag.Lookup(tvpTag) + jsonTagValue, isJsonTag := field.Tag.Lookup(jsonTag) + if IsSkipField(tvpTagValue, isTvpTag, jsonTagValue, isJsonTag) { + continue + } + tvpFieldIndexes = append(tvpFieldIndexes, i) + if field.Type.Kind() == reflect.Ptr { + v := reflect.New(field.Type.Elem()) + defaultValues = append(defaultValues, v.Interface()) + continue + } + defaultValues = append(defaultValues, reflect.Zero(field.Type).Interface()) + } + + if columnCount-len(tvpFieldIndexes) == columnCount { + return nil, nil, ErrorSkip + } + + conn := new(Conn) + conn.sess = new(tdsSession) + conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73} + stmt := &Stmt{ + c: conn, + } + + columnConfiguration := make([]columnStruct, 0, columnCount) + for index, val := range defaultValues { + cval, err := convertInputParameter(val) + if err != nil { + return nil, nil, fmt.Errorf("failed to convert tvp parameter row %d col %d: %s", index, val, err) + } + param, err := stmt.makeParam(cval) + if err != nil { + return nil, nil, err + } + column := columnStruct{ + ti: param.ti, + } + switch param.ti.TypeId { + case typeNVarChar, typeBigVarBin: + column.ti.Size = 0 + } + columnConfiguration = append(columnConfiguration, column) + } + + return columnConfiguration, tvpFieldIndexes, nil +} + +func IsSkipField(tvpTagValue string, isTvpValue bool, jsonTagValue string, isJsonTagValue bool) bool { + if !isTvpValue && !isJsonTagValue { + return false + } else if isTvpValue && tvpTagValue != skipTagValue { + return false + } else if !isTvpValue && isJsonTagValue && jsonTagValue != skipTagValue { + return false + } + return true +} + +func getSchemeAndName(tvpName string) (string, string, error) { + if len(tvpName) == 0 { + return "", "", ErrorEmptyTVPTypeName + } + splitVal := strings.Split(tvpName, ".") + if len(splitVal) > 2 { + return "", "", errors.New("wrong tvp name") + } + if len(splitVal) == 2 { + res := make([]string, 2) + for key, value := range splitVal { + tmp := strings.Replace(value, "[", "", -1) + tmp = strings.Replace(tmp, "]", "", -1) + res[key] = tmp + } + return res[0], res[1], nil + } + tmp := strings.Replace(splitVal[0], "[", "", -1) + tmp = strings.Replace(tmp, "]", "", -1) + + return "", tmp, nil +} + +func getCountSQLSeparators(str string) int { + return strings.Count(str, sqlSeparator) +} diff --git a/vendor/github.com/denisenkom/go-mssqldb/types.go b/vendor/github.com/denisenkom/go-mssqldb/types.go index c38862e9eb767..b2b06d765d50f 100644 --- a/vendor/github.com/denisenkom/go-mssqldb/types.go +++ b/vendor/github.com/denisenkom/go-mssqldb/types.go @@ -6,8 +6,11 @@ import ( "fmt" "io" "math" + "reflect" "strconv" "time" + + "github.com/denisenkom/go-mssqldb/internal/cp" ) // fixed-length data types @@ -59,6 +62,7 @@ const ( typeNChar = 0xef typeXml = 0xf1 typeUdt = 0xf0 + typeTvp = 0xf3 // long length types typeText = 0x23 @@ -66,6 +70,17 @@ const ( typeNText = 0x63 typeVariant = 0x62 ) +const _PLP_NULL = 0xFFFFFFFFFFFFFFFF +const _UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFE +const _PLP_TERMINATOR = 0x00000000 +const _TVP_NULL_TOKEN = 0xffff + +// TVP COLUMN FLAGS +const _TVP_COLUMN_DEFAULT_FLAG = 0x200 +const _TVP_END_TOKEN = 0x00 +const _TVP_ROW_TOKEN = 0x01 +const _TVP_ORDER_UNIQUE_TOKEN = 0x10 +const _TVP_COLUMN_ORDERING_TOKEN = 0x11 // TYPE_INFO rule // http://msdn.microsoft.com/en-us/library/dd358284.aspx @@ -75,11 +90,32 @@ type typeInfo struct { Scale uint8 Prec uint8 Buffer []byte - Collation collation + Collation cp.Collation + UdtInfo udtInfo + XmlInfo xmlInfo Reader func(ti *typeInfo, r *tdsBuffer) (res interface{}) Writer func(w io.Writer, ti typeInfo, buf []byte) (err error) } +// Common Language Runtime (CLR) Instances +// http://msdn.microsoft.com/en-us/library/dd357962.aspx +type udtInfo struct { + //MaxByteSize uint32 + DBName string + SchemaName string + TypeName string + AssemblyQualifiedName string +} + +// XML Values +// http://msdn.microsoft.com/en-us/library/dd304764.aspx +type xmlInfo struct { + SchemaPresent uint8 + DBName string + OwningSchema string + XmlSchemaCollection string +} + func readTypeInfo(r *tdsBuffer) (res typeInfo) { res.TypeId = r.byte() switch res.TypeId { @@ -106,6 +142,7 @@ func readTypeInfo(r *tdsBuffer) (res typeInfo) { return } +// https://msdn.microsoft.com/en-us/library/dd358284.aspx func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { err = binary.Write(w, binary.LittleEndian, ti.TypeId) if err != nil { @@ -114,7 +151,11 @@ func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { switch ti.TypeId { case typeNull, typeInt1, typeBit, typeInt2, typeInt4, typeDateTim4, typeFlt4, typeMoney, typeDateTime, typeFlt8, typeMoney4, typeInt8: - // those are fixed length types + // those are fixed length + // https://msdn.microsoft.com/en-us/library/dd341171.aspx + ti.Writer = writeFixedType + case typeTvp: + ti.Writer = writeFixedType default: // all others are VARLENTYPE err = writeVarLen(w, ti) if err != nil { @@ -124,19 +165,27 @@ func writeTypeInfo(w io.Writer, ti *typeInfo) (err error) { return } +func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { + _, err = w.Write(buf) + return +} + +// https://msdn.microsoft.com/en-us/library/dd358341.aspx func writeVarLen(w io.Writer, ti *typeInfo) (err error) { switch ti.TypeId { - case typeDateN: + case typeDateN: + ti.Writer = writeByteLenType case typeTimeN, typeDateTime2N, typeDateTimeOffsetN: if err = binary.Write(w, binary.LittleEndian, ti.Scale); err != nil { return } ti.Writer = writeByteLenType - case typeGuid, typeIntN, typeDecimal, typeNumeric, + case typeIntN, typeDecimal, typeNumeric, typeBitN, typeDecimalN, typeNumericN, typeFltN, typeMoneyN, typeDateTimeN, typeChar, typeVarChar, typeBinary, typeVarBinary: + // byle len types if ti.Size > 0xff { panic("Invalid size for BYLELEN_TYPE") @@ -156,8 +205,17 @@ func writeVarLen(w io.Writer, ti *typeInfo) (err error) { } } ti.Writer = writeByteLenType + case typeGuid: + if !(ti.Size == 0x10 || ti.Size == 0x00) { + panic("Invalid size for BYLELEN_TYPE") + } + if err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)); err != nil { + return + } + ti.Writer = writeByteLenType case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, typeNVarChar, typeNChar, typeXml, typeUdt: + // short len types if ti.Size > 8000 || ti.Size == 0 { if err = binary.Write(w, binary.LittleEndian, uint16(0xffff)); err != nil { @@ -176,14 +234,19 @@ func writeVarLen(w io.Writer, ti *typeInfo) (err error) { return } case typeXml: - var schemapresent uint8 = 0 - if err = binary.Write(w, binary.LittleEndian, schemapresent); err != nil { + if err = binary.Write(w, binary.LittleEndian, ti.XmlInfo.SchemaPresent); err != nil { return } } case typeText, typeImage, typeNText, typeVariant: // LONGLEN_TYPE - panic("LONGLEN_TYPE not implemented") + if err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)); err != nil { + return + } + if err = writeCollation(w, ti.Collation); err != nil { + return + } + ti.Writer = writeLongLenType default: panic("Invalid type") } @@ -198,6 +261,48 @@ func decodeDateTim4(buf []byte) time.Time { 0, int(mins), 0, 0, time.UTC) } +func encodeDateTim4(val time.Time) (buf []byte) { + buf = make([]byte, 4) + + ref := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC) + dur := val.Sub(ref) + days := dur / (24 * time.Hour) + mins := val.Hour()*60 + val.Minute() + if days < 0 { + days = 0 + mins = 0 + } + + binary.LittleEndian.PutUint16(buf[:2], uint16(days)) + binary.LittleEndian.PutUint16(buf[2:], uint16(mins)) + return +} + +// encodes datetime value +// type identifier is typeDateTimeN +func encodeDateTime(t time.Time) (res []byte) { + // base date in days since Jan 1st 1900 + basedays := gregorianDays(1900, 1) + // days since Jan 1st 1900 (same TZ as t) + days := gregorianDays(t.Year(), t.YearDay()) - basedays + tm := 300*(t.Second()+t.Minute()*60+t.Hour()*60*60) + t.Nanosecond()*300/1e9 + // minimum and maximum possible + mindays := gregorianDays(1753, 1) - basedays + maxdays := gregorianDays(9999, 365) - basedays + if days < mindays { + days = mindays + tm = 0 + } + if days > maxdays { + days = maxdays + tm = (23*60*60+59*60+59)*300 + 299 + } + res = make([]byte, 8) + binary.LittleEndian.PutUint32(res[0:4], uint32(days)) + binary.LittleEndian.PutUint32(res[4:8], uint32(tm)) + return +} + func decodeDateTime(buf []byte) time.Time { days := int32(binary.LittleEndian.Uint32(buf)) tm := binary.LittleEndian.Uint32(buf[4:]) @@ -207,7 +312,7 @@ func decodeDateTime(buf []byte) time.Time { 0, 0, secs, ns, time.UTC) } -func readFixedType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readFixedType(ti *typeInfo, r *tdsBuffer) interface{} { r.ReadFull(ti.Buffer) buf := ti.Buffer switch ti.TypeId { @@ -241,12 +346,7 @@ func readFixedType(ti *typeInfo, r *tdsBuffer) (res interface{}) { panic("shoulnd't get here") } -func writeFixedType(w io.Writer, ti typeInfo, buf []byte) (err error) { - _, err = w.Write(buf) - return -} - -func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readByteLenType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.byte() if size == 0 { return nil @@ -278,7 +378,7 @@ func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { case 8: return int64(binary.LittleEndian.Uint64(buf)) default: - badStreamPanicf("Invalid size for INTNTYPE") + badStreamPanicf("Invalid size for INTNTYPE: %d", len(buf)) } case typeDecimal, typeNumeric, typeDecimalN, typeNumericN: return decodeDecimal(ti.Prec, ti.Scale, buf) @@ -305,6 +405,10 @@ func readByteLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { default: badStreamPanicf("Invalid size for MONEYNTYPE") } + case typeDateTim4: + return decodeDateTim4(buf) + case typeDateTime: + return decodeDateTime(buf) case typeDateTimeN: switch len(buf) { case 4: @@ -333,7 +437,7 @@ func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { if ti.Size > 0xff { panic("Invalid size for BYTELEN_TYPE") } - err = binary.Write(w, binary.LittleEndian, uint8(ti.Size)) + err = binary.Write(w, binary.LittleEndian, uint8(len(buf))) if err != nil { return } @@ -341,7 +445,7 @@ func writeByteLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { return } -func readShortLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readShortLenType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.uint16() if size == 0xffff { return nil @@ -384,7 +488,7 @@ func writeShortLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { return } -func readLongLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readLongLenType(ti *typeInfo, r *tdsBuffer) interface{} { // information about this format can be found here: // http://msdn.microsoft.com/en-us/library/dd304783.aspx // and here: @@ -415,10 +519,51 @@ func readLongLenType(ti *typeInfo, r *tdsBuffer) (res interface{}) { } panic("shoulnd't get here") } +func writeLongLenType(w io.Writer, ti typeInfo, buf []byte) (err error) { + //textptr + err = binary.Write(w, binary.LittleEndian, byte(0x10)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + //timestamp? + err = binary.Write(w, binary.LittleEndian, uint64(0xFFFFFFFFFFFFFFFF)) + if err != nil { + return + } + + err = binary.Write(w, binary.LittleEndian, uint32(ti.Size)) + if err != nil { + return + } + _, err = w.Write(buf) + return +} + +func readCollation(r *tdsBuffer) (res cp.Collation) { + res.LcidAndFlags = r.uint32() + res.SortId = r.byte() + return +} + +func writeCollation(w io.Writer, col cp.Collation) (err error) { + if err = binary.Write(w, binary.LittleEndian, col.LcidAndFlags); err != nil { + return + } + err = binary.Write(w, binary.LittleEndian, col.SortId) + return +} // reads variant value // http://msdn.microsoft.com/en-us/library/dd303302.aspx -func readVariantType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readVariantType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.int32() if size == 0 { return nil @@ -510,14 +655,14 @@ func readVariantType(ti *typeInfo, r *tdsBuffer) (res interface{}) { // partially length prefixed stream // http://msdn.microsoft.com/en-us/library/dd340469.aspx -func readPLPType(ti *typeInfo, r *tdsBuffer) (res interface{}) { +func readPLPType(ti *typeInfo, r *tdsBuffer) interface{} { size := r.uint64() var buf *bytes.Buffer switch size { - case 0xffffffffffffffff: + case _PLP_NULL: // null return nil - case 0xfffffffffffffffe: + case _UNKNOWN_PLP_LEN: // size unknown buf = bytes.NewBuffer(make([]byte, 0, 1000)) default: @@ -548,15 +693,16 @@ func readPLPType(ti *typeInfo, r *tdsBuffer) (res interface{}) { } func writePLPType(w io.Writer, ti typeInfo, buf []byte) (err error) { - if err = binary.Write(w, binary.LittleEndian, uint64(len(buf))); err != nil { + if err = binary.Write(w, binary.LittleEndian, uint64(_UNKNOWN_PLP_LEN)); err != nil { return } for { chunksize := uint32(len(buf)) - if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { + if chunksize == 0 { + err = binary.Write(w, binary.LittleEndian, uint32(_PLP_TERMINATOR)) return } - if chunksize == 0 { + if err = binary.Write(w, binary.LittleEndian, chunksize); err != nil { return } if _, err = w.Write(buf[:chunksize]); err != nil { @@ -606,19 +752,27 @@ func readVarLen(ti *typeInfo, r *tdsBuffer) { } ti.Reader = readByteLenType case typeXml: - schemapresent := r.byte() - if schemapresent != 0 { - // just ignore this for now + ti.XmlInfo.SchemaPresent = r.byte() + if ti.XmlInfo.SchemaPresent != 0 { // dbname - r.BVarChar() + ti.XmlInfo.DBName = r.BVarChar() // owning schema - r.BVarChar() + ti.XmlInfo.OwningSchema = r.BVarChar() // xml schema collection - r.UsVarChar() + ti.XmlInfo.XmlSchemaCollection = r.UsVarChar() } ti.Reader = readPLPType + case typeUdt: + ti.Size = int(r.uint16()) + ti.UdtInfo.DBName = r.BVarChar() + ti.UdtInfo.SchemaName = r.BVarChar() + ti.UdtInfo.TypeName = r.BVarChar() + ti.UdtInfo.AssemblyQualifiedName = r.UsVarChar() + + ti.Buffer = make([]byte, ti.Size) + ti.Reader = readPLPType case typeBigVarBin, typeBigVarChar, typeBigBinary, typeBigChar, - typeNVarChar, typeNChar, typeUdt: + typeNVarChar, typeNChar: // short len types ti.Size = int(r.uint16()) switch ti.TypeId { @@ -701,13 +855,23 @@ func decodeDecimal(prec uint8, scale uint8, buf []byte) []byte { // http://msdn.microsoft.com/en-us/library/ee780895.aspx func decodeDateInt(buf []byte) (days int) { - return int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + days = int(buf[0]) + int(buf[1])*256 + int(buf[2])*256*256 + return } func decodeDate(buf []byte) time.Time { return time.Date(1, 1, 1+decodeDateInt(buf), 0, 0, 0, 0, time.UTC) } +func encodeDate(val time.Time) (buf []byte) { + days, _, _ := dateTime2(val) + buf = make([]byte, 3) + buf[0] = byte(days) + buf[1] = byte(days >> 8) + buf[2] = byte(days >> 16) + return +} + func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) { var acc uint64 = 0 for i := len(buf) - 1; i >= 0; i-- { @@ -723,11 +887,41 @@ func decodeTimeInt(scale uint8, buf []byte) (sec int, ns int) { return } +// calculate size of time field in bytes +func calcTimeSize(scale int) int { + if scale <= 2 { + return 3 + } else if scale <= 4 { + return 4 + } else { + return 5 + } +} + +// writes time value into a field buffer +// buffer should be at least calcTimeSize long +func encodeTimeInt(seconds, ns, scale int, buf []byte) { + ns_total := int64(seconds)*1000*1000*1000 + int64(ns) + t := ns_total / int64(math.Pow10(int(scale)*-1)*1e9) + buf[0] = byte(t) + buf[1] = byte(t >> 8) + buf[2] = byte(t >> 16) + buf[3] = byte(t >> 24) + buf[4] = byte(t >> 32) +} + func decodeTime(scale uint8, buf []byte) time.Time { sec, ns := decodeTimeInt(scale, buf) return time.Date(1, 1, 1, 0, 0, sec, ns, time.UTC) } +func encodeTime(hour, minute, second, ns, scale int) (buf []byte) { + seconds := hour*3600 + minute*60 + second + buf = make([]byte, calcTimeSize(scale)) + encodeTimeInt(seconds, ns, scale, buf) + return +} + func decodeDateTime2(scale uint8, buf []byte) time.Time { timesize := len(buf) - 3 sec, ns := decodeTimeInt(scale, buf[:timesize]) @@ -735,6 +929,17 @@ func decodeDateTime2(scale uint8, buf []byte) time.Time { return time.Date(1, 1, 1+days, 0, 0, sec, ns, time.UTC) } +func encodeDateTime2(val time.Time, scale int) (buf []byte) { + days, seconds, ns := dateTime2(val) + timesize := calcTimeSize(scale) + buf = make([]byte, 3+timesize) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + return +} + func decodeDateTimeOffset(scale uint8, buf []byte) time.Time { timesize := len(buf) - 3 - 2 sec, ns := decodeTimeInt(scale, buf[:timesize]) @@ -746,29 +951,48 @@ func decodeDateTimeOffset(scale uint8, buf []byte) time.Time { time.FixedZone("", offset*60)) } -func divFloor(x int64, y int64) int64 { - q := x / y - r := x % y - if r != 0 && ((r < 0) != (y < 0)) { - q-- - } - return q +func encodeDateTimeOffset(val time.Time, scale int) (buf []byte) { + timesize := calcTimeSize(scale) + buf = make([]byte, timesize+2+3) + days, seconds, ns := dateTime2(val.In(time.UTC)) + encodeTimeInt(seconds, ns, scale, buf) + buf[timesize] = byte(days) + buf[timesize+1] = byte(days >> 8) + buf[timesize+2] = byte(days >> 16) + _, offset := val.Zone() + offset /= 60 + buf[timesize+3] = byte(offset) + buf[timesize+4] = byte(offset >> 8) + return +} + +// returns days since Jan 1st 0001 in Gregorian calendar +func gregorianDays(year, yearday int) int { + year0 := year - 1 + return year0*365 + year0/4 - year0/100 + year0/400 + yearday - 1 } -func dateTime2(t time.Time) (days int32, ns int64) { - // number of days since Jan 1 1970 UTC - days64 := divFloor(t.Unix(), 24*60*60) - // number of days since Jan 1 1 UTC - days = int32(days64) + 1969*365 + 1969/4 - 1969/100 + 1969/400 - // number of seconds within day - secs := t.Unix() - days64*24*60*60 - // number of nanoseconds within day - ns = secs*1e9 + int64(t.Nanosecond()) +func dateTime2(t time.Time) (days int, seconds int, ns int) { + // days since Jan 1 1 (in same TZ as t) + days = gregorianDays(t.Year(), t.YearDay()) + seconds = t.Second() + t.Minute()*60 + t.Hour()*60*60 + ns = t.Nanosecond() + if days < 0 { + days = 0 + seconds = 0 + ns = 0 + } + max := gregorianDays(9999, 365) + if days > max { + days = max + seconds = 59 + 59*60 + 23*60*60 + ns = 999999900 + } return } -func decodeChar(col collation, buf []byte) string { - return charset2utf8(col, buf) +func decodeChar(col cp.Collation, buf []byte) string { + return cp.CharsetToUTF8(col, buf) } func decodeUcs2(buf []byte) string { @@ -787,12 +1011,129 @@ func decodeXml(ti typeInfo, buf []byte) string { return decodeUcs2(buf) } -func decodeUdt(ti typeInfo, buf []byte) int { - panic("Not implemented") +func decodeUdt(ti typeInfo, buf []byte) []byte { + return buf +} + +// makes go/sql type instance as described below +// It should return +// the value type that can be used to scan types into. For example, the database +// column type "bigint" this should return "reflect.TypeOf(int64(0))". +func makeGoLangScanType(ti typeInfo) reflect.Type { + switch ti.TypeId { + case typeInt1: + return reflect.TypeOf(int64(0)) + case typeInt2: + return reflect.TypeOf(int64(0)) + case typeInt4: + return reflect.TypeOf(int64(0)) + case typeInt8: + return reflect.TypeOf(int64(0)) + case typeFlt4: + return reflect.TypeOf(float64(0)) + case typeIntN: + switch ti.Size { + case 1: + return reflect.TypeOf(int64(0)) + case 2: + return reflect.TypeOf(int64(0)) + case 4: + return reflect.TypeOf(int64(0)) + case 8: + return reflect.TypeOf(int64(0)) + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return reflect.TypeOf(float64(0)) + case typeFltN: + switch ti.Size { + case 4: + return reflect.TypeOf(float64(0)) + case 8: + return reflect.TypeOf(float64(0)) + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return reflect.TypeOf([]byte{}) + case typeVarChar: + return reflect.TypeOf("") + case typeNVarChar: + return reflect.TypeOf("") + case typeBit, typeBitN: + return reflect.TypeOf(true) + case typeDecimalN, typeNumericN: + return reflect.TypeOf([]byte{}) + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return reflect.TypeOf([]byte{}) + case 8: + return reflect.TypeOf([]byte{}) + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return reflect.TypeOf(time.Time{}) + case typeDateTime: + return reflect.TypeOf(time.Time{}) + case typeDateTimeN: + switch ti.Size { + case 4: + return reflect.TypeOf(time.Time{}) + case 8: + return reflect.TypeOf(time.Time{}) + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return reflect.TypeOf(time.Time{}) + case typeDateN: + return reflect.TypeOf(time.Time{}) + case typeTimeN: + return reflect.TypeOf(time.Time{}) + case typeDateTimeOffsetN: + return reflect.TypeOf(time.Time{}) + case typeBigVarChar: + return reflect.TypeOf("") + case typeBigChar: + return reflect.TypeOf("") + case typeNChar: + return reflect.TypeOf("") + case typeGuid: + return reflect.TypeOf([]byte{}) + case typeXml: + return reflect.TypeOf("") + case typeText: + return reflect.TypeOf("") + case typeNText: + return reflect.TypeOf("") + case typeImage: + return reflect.TypeOf([]byte{}) + case typeBigBinary: + return reflect.TypeOf([]byte{}) + case typeVariant: + return reflect.TypeOf(nil) + default: + panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId)) + } } func makeDecl(ti typeInfo) string { switch ti.TypeId { + case typeNull: + // maybe we should use something else here + // this is tested in TestNull + return "nvarchar(1)" + case typeInt1: + return "tinyint" + case typeBigBinary: + return fmt.Sprintf("binary(%d)", ti.Size) + case typeInt2: + return "smallint" + case typeInt4: + return "int" case typeInt8: return "bigint" case typeFlt4: @@ -821,25 +1162,423 @@ func makeDecl(ti typeInfo) string { default: panic("invalid size of FLNNTYPE") } + case typeDecimal, typeDecimalN: + return fmt.Sprintf("decimal(%d, %d)", ti.Prec, ti.Scale) + case typeNumeric, typeNumericN: + return fmt.Sprintf("numeric(%d, %d)", ti.Prec, ti.Scale) + case typeMoney4: + return "smallmoney" + case typeMoney: + return "money" + case typeMoneyN: + switch ti.Size { + case 4: + return "smallmoney" + case 8: + return "money" + default: + panic("invalid size of MONEYNTYPE") + } case typeBigVarBin: if ti.Size > 8000 || ti.Size == 0 { - return fmt.Sprintf("varbinary(max)") + return "varbinary(max)" } else { return fmt.Sprintf("varbinary(%d)", ti.Size) } + case typeNChar: + return fmt.Sprintf("nchar(%d)", ti.Size/2) + case typeBigChar, typeChar: + return fmt.Sprintf("char(%d)", ti.Size) + case typeBigVarChar, typeVarChar: + if ti.Size > 4000 || ti.Size == 0 { + return fmt.Sprintf("varchar(max)") + } else { + return fmt.Sprintf("varchar(%d)", ti.Size) + } case typeNVarChar: if ti.Size > 8000 || ti.Size == 0 { - return fmt.Sprintf("nvarchar(max)") + return "nvarchar(max)" } else { return fmt.Sprintf("nvarchar(%d)", ti.Size/2) } case typeBit, typeBitN: return "bit" - case typeDateTimeN: + case typeDateN: + return "date" + case typeDateTim4: + return "smalldatetime" + case typeDateTime: return "datetime" + case typeDateTimeN: + switch ti.Size { + case 4: + return "smalldatetime" + case 8: + return "datetime" + default: + panic("invalid size of DATETIMNTYPE") + } + case typeTimeN: + return "time" + case typeDateTime2N: + return fmt.Sprintf("datetime2(%d)", ti.Scale) case typeDateTimeOffsetN: return fmt.Sprintf("datetimeoffset(%d)", ti.Scale) + case typeText: + return "text" + case typeNText: + return "ntext" + case typeUdt: + return ti.UdtInfo.TypeName + case typeGuid: + return "uniqueidentifier" + case typeTvp: + if ti.UdtInfo.SchemaName != "" { + return fmt.Sprintf("%s.%s READONLY", ti.UdtInfo.SchemaName, ti.UdtInfo.TypeName) + } + return fmt.Sprintf("%s READONLY", ti.UdtInfo.TypeName) + default: + panic(fmt.Sprintf("not implemented makeDecl for type %#x", ti.TypeId)) + } +} + +// makes go/sql type name as described below +// RowsColumnTypeDatabaseTypeName may be implemented by Rows. It should return the +// database system type name without the length. Type names should be uppercase. +// Examples of returned types: "VARCHAR", "NVARCHAR", "VARCHAR2", "CHAR", "TEXT", +// "DECIMAL", "SMALLINT", "INT", "BIGINT", "BOOL", "[]BIGINT", "JSONB", "XML", +// "TIMESTAMP". +func makeGoLangTypeName(ti typeInfo) string { + switch ti.TypeId { + case typeInt1: + return "TINYINT" + case typeInt2: + return "SMALLINT" + case typeInt4: + return "INT" + case typeInt8: + return "BIGINT" + case typeFlt4: + return "REAL" + case typeIntN: + switch ti.Size { + case 1: + return "TINYINT" + case 2: + return "SMALLINT" + case 4: + return "INT" + case 8: + return "BIGINT" + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return "FLOAT" + case typeFltN: + switch ti.Size { + case 4: + return "REAL" + case 8: + return "FLOAT" + default: + panic("invalid size of FLNNTYPE") + } + case typeBigVarBin: + return "VARBINARY" + case typeVarChar: + return "VARCHAR" + case typeNVarChar: + return "NVARCHAR" + case typeBit, typeBitN: + return "BIT" + case typeDecimalN, typeNumericN: + return "DECIMAL" + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return "SMALLMONEY" + case 8: + return "MONEY" + default: + panic("invalid size of MONEYN") + } + case typeDateTim4: + return "SMALLDATETIME" + case typeDateTime: + return "DATETIME" + case typeDateTimeN: + switch ti.Size { + case 4: + return "SMALLDATETIME" + case 8: + return "DATETIME" + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return "DATETIME2" + case typeDateN: + return "DATE" + case typeTimeN: + return "TIME" + case typeDateTimeOffsetN: + return "DATETIMEOFFSET" + case typeBigVarChar: + return "VARCHAR" + case typeBigChar: + return "CHAR" + case typeNChar: + return "NCHAR" + case typeGuid: + return "UNIQUEIDENTIFIER" + case typeXml: + return "XML" + case typeText: + return "TEXT" + case typeNText: + return "NTEXT" + case typeImage: + return "IMAGE" + case typeVariant: + return "SQL_VARIANT" + case typeBigBinary: + return "BINARY" + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId)) + } +} + +// makes go/sql type length as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypeLength(ti typeInfo) (int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, false + case typeInt2: + return 0, false + case typeInt4: + return 0, false + case typeInt8: + return 0, false + case typeFlt4: + return 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, false + case 2: + return 0, false + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, false + case typeDecimalN, typeNumericN: + return 0, false + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, false + case 8: + return 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, false + case typeDateN: + return 0, false + case typeTimeN: + return 0, false + case typeDateTimeOffsetN: + return 0, false + case typeBigVarBin: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeVarChar: + return int64(ti.Size), true + case typeBigVarChar: + if ti.Size == 0xffff { + return 2147483645, true + } else { + return int64(ti.Size), true + } + case typeBigChar: + return int64(ti.Size), true + case typeNVarChar: + if ti.Size == 0xffff { + return 2147483645 / 2, true + } else { + return int64(ti.Size) / 2, true + } + case typeNChar: + return int64(ti.Size) / 2, true + case typeGuid: + return 0, false + case typeXml: + return 1073741822, true + case typeText: + return 2147483647, true + case typeNText: + return 1073741823, true + case typeImage: + return 2147483647, true + case typeVariant: + return 0, false + case typeBigBinary: + return 0, false + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId)) + } +} + +// makes go/sql type precision and scale as described below +// It should return the length +// of the column type if the column is a variable length type. If the column is +// not a variable length type ok should return false. +// If length is not limited other than system limits, it should return math.MaxInt64. +// The following are examples of returned values for various types: +// TEXT (math.MaxInt64, true) +// varchar(10) (10, true) +// nvarchar(10) (10, true) +// decimal (0, false) +// int (0, false) +// bytea(30) (30, true) +func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { + switch ti.TypeId { + case typeInt1: + return 0, 0, false + case typeInt2: + return 0, 0, false + case typeInt4: + return 0, 0, false + case typeInt8: + return 0, 0, false + case typeFlt4: + return 0, 0, false + case typeIntN: + switch ti.Size { + case 1: + return 0, 0, false + case 2: + return 0, 0, false + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of INTNTYPE") + } + case typeFlt8: + return 0, 0, false + case typeFltN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of FLNNTYPE") + } + case typeBit, typeBitN: + return 0, 0, false + case typeDecimalN, typeNumericN: + return int64(ti.Prec), int64(ti.Scale), true + case typeMoney, typeMoney4, typeMoneyN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of MONEYN") + } + case typeDateTim4, typeDateTime: + return 0, 0, false + case typeDateTimeN: + switch ti.Size { + case 4: + return 0, 0, false + case 8: + return 0, 0, false + default: + panic("invalid size of DATETIMEN") + } + case typeDateTime2N: + return 0, 0, false + case typeDateN: + return 0, 0, false + case typeTimeN: + return 0, 0, false + case typeDateTimeOffsetN: + return 0, 0, false + case typeBigVarBin: + return 0, 0, false + case typeVarChar: + return 0, 0, false + case typeBigVarChar: + return 0, 0, false + case typeBigChar: + return 0, 0, false + case typeNVarChar: + return 0, 0, false + case typeNChar: + return 0, 0, false + case typeGuid: + return 0, 0, false + case typeXml: + return 0, 0, false + case typeText: + return 0, 0, false + case typeNText: + return 0, 0, false + case typeImage: + return 0, 0, false + case typeVariant: + return 0, 0, false + case typeBigBinary: + return 0, 0, false default: - panic(fmt.Sprintf("not implemented makeDecl for type %d", ti.TypeId)) + panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId)) } } diff --git a/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go new file mode 100644 index 0000000000000..c8ef3149b19f0 --- /dev/null +++ b/vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go @@ -0,0 +1,74 @@ +package mssql + +import ( + "database/sql/driver" + "encoding/hex" + "errors" + "fmt" +) + +type UniqueIdentifier [16]byte + +func (u *UniqueIdentifier) Scan(v interface{}) error { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + switch vt := v.(type) { + case []byte: + if len(vt) != 16 { + return errors.New("mssql: invalid UniqueIdentifier length") + } + + var raw UniqueIdentifier + + copy(raw[:], vt) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + *u = raw + + return nil + case string: + if len(vt) != 36 { + return errors.New("mssql: invalid UniqueIdentifier string length") + } + + b := []byte(vt) + for i, c := range b { + switch c { + case '-': + b = append(b[:i], b[i+1:]...) + } + } + + _, err := hex.Decode(u[:], []byte(b)) + return err + default: + return fmt.Errorf("mssql: cannot convert %T to UniqueIdentifier", v) + } +} + +func (u UniqueIdentifier) Value() (driver.Value, error) { + reverse := func(b []byte) { + for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 { + b[i], b[j] = b[j], b[i] + } + } + + raw := make([]byte, len(u)) + copy(raw, u[:]) + + reverse(raw[0:4]) + reverse(raw[4:6]) + reverse(raw[6:8]) + + return raw, nil +} + +func (u UniqueIdentifier) String() string { + return fmt.Sprintf("%X-%X-%X-%X-%X", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/collector.go b/vendor/github.com/prometheus/client_golang/prometheus/collector.go index c0d70b2faf169..1e839650d4d93 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/collector.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/collector.go @@ -79,7 +79,7 @@ type Collector interface { // of the Describe method. If a Collector sometimes collects no metrics at all // (for example vectors like CounterVec, GaugeVec, etc., which only collect // metrics after a metric with a fully specified label set has been accessed), -// it might even get registered as an unchecked Collecter (cf. the Register +// it might even get registered as an unchecked Collector (cf. the Register // method of the Registerer interface). Hence, only use this shortcut // implementation of Describe if you are certain to fulfill the contract. // diff --git a/vendor/github.com/prometheus/client_golang/prometheus/counter.go b/vendor/github.com/prometheus/client_golang/prometheus/counter.go index 765e4550c66ef..d463e36d3e98d 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/counter.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/counter.go @@ -136,7 +136,7 @@ func NewCounterVec(opts CounterOpts, labelNames []string) *CounterVec { return &CounterVec{ metricVec: newMetricVec(desc, func(lvs ...string) Metric { if len(lvs) != len(desc.variableLabels) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) } result := &counter{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/desc.go b/vendor/github.com/prometheus/client_golang/prometheus/desc.go index 7b8827ffbca95..1d034f871cb9c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/desc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/desc.go @@ -93,7 +93,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // First add only the const label names and sort them... for labelName := range constLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, labelName) @@ -115,7 +115,7 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) * // dimension with a different mix between preset and variable labels. for _, labelName := range variableLabels { if !checkLabelName(labelName) { - d.err = fmt.Errorf("%q is not a valid label name", labelName) + d.err = fmt.Errorf("%q is not a valid label name for metric %q", labelName, fqName) return d } labelNames = append(labelNames, "$"+labelName) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/doc.go b/vendor/github.com/prometheus/client_golang/prometheus/doc.go index 5d9525defc8df..1e0d578ee7a84 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/doc.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/doc.go @@ -122,13 +122,13 @@ // the Collect method. The Describe method has to return separate Desc // instances, representative of the “throw-away” metrics to be created later. // NewDesc comes in handy to create those Desc instances. Alternatively, you -// could return no Desc at all, which will marke the Collector “unchecked”. No -// checks are porformed at registration time, but metric consistency will still +// could return no Desc at all, which will mark the Collector “unchecked”. No +// checks are performed at registration time, but metric consistency will still // be ensured at scrape time, i.e. any inconsistencies will lead to scrape // errors. Thus, with unchecked Collectors, the responsibility to not collect // metrics that lead to inconsistencies in the total scrape result lies with the // implementer of the Collector. While this is not a desirable state, it is -// sometimes necessary. The typical use case is a situatios where the exact +// sometimes necessary. The typical use case is a situation where the exact // metrics to be returned by a Collector cannot be predicted at registration // time, but the implementer has sufficient knowledge of the whole system to // guarantee metric consistency. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go index 17c72d7eb0cc9..71d406bd92ab2 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/gauge.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/gauge.go @@ -147,7 +147,7 @@ func NewGaugeVec(opts GaugeOpts, labelNames []string) *GaugeVec { return &GaugeVec{ metricVec: newMetricVec(desc, func(lvs ...string) Metric { if len(lvs) != len(desc.variableLabels) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, lvs)) } result := &gauge{desc: desc, labelPairs: makeLabelPairs(desc, lvs)} result.init(result) // Init self-collection. diff --git a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go index 4d7fa976e47f7..20ee1afb5d49d 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/histogram.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/histogram.go @@ -165,7 +165,7 @@ func NewHistogram(opts HistogramOpts) Histogram { func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogram { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -204,8 +204,8 @@ func newHistogram(desc *Desc, opts HistogramOpts, labelValues ...string) Histogr } } } - // Finally we know the final length of h.upperBounds and can make counts - // for both states: + // Finally we know the final length of h.upperBounds and can make buckets + // for both counts: h.counts[0].buckets = make([]uint64, len(h.upperBounds)) h.counts[1].buckets = make([]uint64, len(h.upperBounds)) diff --git a/vendor/github.com/prometheus/client_golang/prometheus/http.go b/vendor/github.com/prometheus/client_golang/prometheus/http.go index 4b8e602733500..0fa339aec0ea3 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/http.go @@ -15,9 +15,7 @@ package prometheus import ( "bufio" - "bytes" "compress/gzip" - "fmt" "io" "net" "net/http" @@ -36,24 +34,14 @@ import ( const ( contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" contentEncodingHeader = "Content-Encoding" acceptEncodingHeader = "Accept-Encoding" ) -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, } // Handler returns an HTTP handler for the DefaultGatherer. It is @@ -71,58 +59,40 @@ func Handler() http.Handler { // Deprecated: Use promhttp.HandlerFor(DefaultGatherer, promhttp.HandlerOpts{}) // instead. See there for further documentation. func UninstrumentedHandler() http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + return http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { mfs, err := DefaultGatherer.Gather() if err != nil { - http.Error(w, "An error has occurred during metrics collection:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf) - enc := expfmt.NewEncoder(writer, contentType) - var lastErr error + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + for _, mf := range mfs { if err := enc.Encode(mf); err != nil { - lastErr = err - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - w.Write(buf.Bytes()) }) } -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer) (io.Writer, string) { - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") - for _, part := range parts { - part = strings.TrimSpace(part) - if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" - } - } - return writer, "" -} - var instLabels = []string{"method", "code"} type nower interface { @@ -503,3 +473,31 @@ func sanitizeCode(s int) string { return strconv.Itoa(s) } } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") + for _, part := range parts { + part = strings.TrimSpace(part) + if part == "gzip" || strings.HasPrefix(part, "gzip;") { + return true + } + } + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) +} diff --git a/vendor/github.com/prometheus/client_golang/prometheus/labels.go b/vendor/github.com/prometheus/client_golang/prometheus/labels.go index e68f132ecefee..2744443ac228b 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/labels.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/labels.go @@ -37,9 +37,22 @@ const reservedLabelPrefix = "__" var errInconsistentCardinality = errors.New("inconsistent label cardinality") +func makeInconsistentCardinalityError(fqName string, labels, labelValues []string) error { + return fmt.Errorf( + "%s: %q has %d variable labels named %q but %d values %q were provided", + errInconsistentCardinality, fqName, + len(labels), labels, + len(labelValues), labelValues, + ) +} + func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { if len(labels) != expectedNumberOfValues { - return errInconsistentCardinality + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(labels), labels, + ) } for name, val := range labels { @@ -53,7 +66,11 @@ func validateValuesInLabels(labels Labels, expectedNumberOfValues int) error { func validateLabelValues(vals []string, expectedNumberOfValues int) error { if len(vals) != expectedNumberOfValues { - return errInconsistentCardinality + return fmt.Errorf( + "%s: expected %d label values but got %d in %#v", + errInconsistentCardinality, expectedNumberOfValues, + len(vals), vals, + ) } for _, val := range vals { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go index 67b56d37cfd72..5de5bbc685a5c 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go @@ -38,7 +38,6 @@ type delegator interface { type responseWriterDelegator struct { http.ResponseWriter - handler, method string status int written int64 wroteHeader bool diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go index 01357374feb16..b137c883071a1 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/http.go @@ -32,7 +32,6 @@ package promhttp import ( - "bytes" "compress/gzip" "fmt" "io" @@ -48,24 +47,14 @@ import ( const ( contentTypeHeader = "Content-Type" - contentLengthHeader = "Content-Length" contentEncodingHeader = "Content-Encoding" acceptEncodingHeader = "Accept-Encoding" ) -var bufPool sync.Pool - -func getBuf() *bytes.Buffer { - buf := bufPool.Get() - if buf == nil { - return &bytes.Buffer{} - } - return buf.(*bytes.Buffer) -} - -func giveBuf(buf *bytes.Buffer) { - buf.Reset() - bufPool.Put(buf) +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, } // Handler returns an http.Handler for the prometheus.DefaultGatherer, using @@ -100,19 +89,18 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { inFlightSem = make(chan struct{}, opts.MaxRequestsInFlight) } - h := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) { if inFlightSem != nil { select { case inFlightSem <- struct{}{}: // All good, carry on. defer func() { <-inFlightSem }() default: - http.Error(w, fmt.Sprintf( + http.Error(rsp, fmt.Sprintf( "Limit of concurrent requests reached (%d), try again later.", opts.MaxRequestsInFlight, ), http.StatusServiceUnavailable) return } } - mfs, err := reg.Gather() if err != nil { if opts.ErrorLog != nil { @@ -123,26 +111,40 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { panic(err) case ContinueOnError: if len(mfs) == 0 { - http.Error(w, "No metrics gathered, last error:\n\n"+err.Error(), http.StatusInternalServerError) + // Still report the error if no metrics have been gathered. + httpError(rsp, err) return } case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics gathering:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } contentType := expfmt.Negotiate(req.Header) - buf := getBuf() - defer giveBuf(buf) - writer, encoding := decorateWriter(req, buf, opts.DisableCompression) - enc := expfmt.NewEncoder(writer, contentType) + header := rsp.Header() + header.Set(contentTypeHeader, string(contentType)) + + w := io.Writer(rsp) + if !opts.DisableCompression && gzipAccepted(req.Header) { + header.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + enc := expfmt.NewEncoder(w, contentType) + var lastErr error for _, mf := range mfs { if err := enc.Encode(mf); err != nil { lastErr = err if opts.ErrorLog != nil { - opts.ErrorLog.Println("error encoding metric family:", err) + opts.ErrorLog.Println("error encoding and sending metric family:", err) } switch opts.ErrorHandling { case PanicOnError: @@ -150,28 +152,15 @@ func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler { case ContinueOnError: // Handled later. case HTTPErrorOnError: - http.Error(w, "An error has occurred during metrics encoding:\n\n"+err.Error(), http.StatusInternalServerError) + httpError(rsp, err) return } } } - if closer, ok := writer.(io.Closer); ok { - closer.Close() - } - if lastErr != nil && buf.Len() == 0 { - http.Error(w, "No metrics encoded, last error:\n\n"+lastErr.Error(), http.StatusInternalServerError) - return - } - header := w.Header() - header.Set(contentTypeHeader, string(contentType)) - header.Set(contentLengthHeader, fmt.Sprint(buf.Len())) - if encoding != "" { - header.Set(contentEncodingHeader, encoding) - } - if _, err := w.Write(buf.Bytes()); err != nil && opts.ErrorLog != nil { - opts.ErrorLog.Println("error while sending encoded metrics:", err) + + if lastErr != nil { + httpError(rsp, lastErr) } - // TODO(beorn7): Consider streaming serving of metrics. }) if opts.Timeout <= 0 { @@ -292,20 +281,30 @@ type HandlerOpts struct { Timeout time.Duration } -// decorateWriter wraps a writer to handle gzip compression if requested. It -// returns the decorated writer and the appropriate "Content-Encoding" header -// (which is empty if no compression is enabled). -func decorateWriter(request *http.Request, writer io.Writer, compressionDisabled bool) (io.Writer, string) { - if compressionDisabled { - return writer, "" - } - header := request.Header.Get(acceptEncodingHeader) - parts := strings.Split(header, ",") +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(header http.Header) bool { + a := header.Get(acceptEncodingHeader) + parts := strings.Split(a, ",") for _, part := range parts { part = strings.TrimSpace(part) if part == "gzip" || strings.HasPrefix(part, "gzip;") { - return gzip.NewWriter(writer), "gzip" + return true } } - return writer, "" + return false +} + +// httpError removes any content-encoding header and then calls http.Error with +// the provided error and http.StatusInternalServerErrer. Error contents is +// supposed to be uncompressed plain text. However, same as with a plain +// http.Error, any header settings will be void if the header has already been +// sent. The error message will still be written to the writer, but it will +// probably be of limited use. +func httpError(rsp http.ResponseWriter, err error) { + rsp.Header().Del(contentEncodingHeader) + http.Error( + rsp, + "An error has occurred while serving metrics:\n\n"+err.Error(), + http.StatusInternalServerError, + ) } diff --git a/vendor/github.com/prometheus/client_golang/prometheus/registry.go b/vendor/github.com/prometheus/client_golang/prometheus/registry.go index e422ef3834cd6..f2fb67aeebd64 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/registry.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/registry.go @@ -16,6 +16,9 @@ package prometheus import ( "bytes" "fmt" + "io/ioutil" + "os" + "path/filepath" "runtime" "sort" "strings" @@ -23,6 +26,7 @@ import ( "unicode/utf8" "github.com/golang/protobuf/proto" + "github.com/prometheus/common/expfmt" dto "github.com/prometheus/client_model/go" @@ -533,6 +537,38 @@ func (r *Registry) Gather() ([]*dto.MetricFamily, error) { return internal.NormalizeMetricFamilies(metricFamiliesByName), errs.MaybeUnwrap() } +// WriteToTextfile calls Gather on the provided Gatherer, encodes the result in the +// Prometheus text format, and writes it to a temporary file. Upon success, the +// temporary file is renamed to the provided filename. +// +// This is intended for use with the textfile collector of the node exporter. +// Note that the node exporter expects the filename to be suffixed with ".prom". +func WriteToTextfile(filename string, g Gatherer) error { + tmp, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)) + if err != nil { + return err + } + defer os.Remove(tmp.Name()) + + mfs, err := g.Gather() + if err != nil { + return err + } + for _, mf := range mfs { + if _, err := expfmt.MetricFamilyToText(tmp, mf); err != nil { + return err + } + } + if err := tmp.Close(); err != nil { + return err + } + + if err := os.Chmod(tmp.Name(), 0644); err != nil { + return err + } + return os.Rename(tmp.Name(), filename) +} + // processMetric is an internal helper method only used by the Gather method. func processMetric( metric Metric, @@ -644,7 +680,7 @@ func processMetric( // Gatherers is a slice of Gatherer instances that implements the Gatherer // interface itself. Its Gather method calls Gather on all Gatherers in the // slice in order and returns the merged results. Errors returned from the -// Gather calles are all returned in a flattened MultiError. Duplicate and +// Gather calls are all returned in a flattened MultiError. Duplicate and // inconsistent Metrics are skipped (first occurrence in slice order wins) and // reported in the returned error. // @@ -836,7 +872,13 @@ func checkMetricConsistency( h = hashAddByte(h, separatorByte) // Make sure label pairs are sorted. We depend on it for the consistency // check. - sort.Sort(labelPairSorter(dtoMetric.Label)) + if !sort.IsSorted(labelPairSorter(dtoMetric.Label)) { + // We cannot sort dtoMetric.Label in place as it is immutable by contract. + copiedLabels := make([]*dto.LabelPair, len(dtoMetric.Label)) + copy(copiedLabels, dtoMetric.Label) + sort.Sort(labelPairSorter(copiedLabels)) + dtoMetric.Label = copiedLabels + } for _, lp := range dtoMetric.Label { h = hashAdd(h, lp.GetName()) h = hashAddByte(h, separatorByte) @@ -867,8 +909,8 @@ func checkDescConsistency( } // Is the desc consistent with the content of the metric? - lpsFromDesc := make([]*dto.LabelPair, 0, len(dtoMetric.Label)) - lpsFromDesc = append(lpsFromDesc, desc.constLabelPairs...) + lpsFromDesc := make([]*dto.LabelPair, len(desc.constLabelPairs), len(dtoMetric.Label)) + copy(lpsFromDesc, desc.constLabelPairs) for _, l := range desc.variableLabels { lpsFromDesc = append(lpsFromDesc, &dto.LabelPair{ Name: proto.String(l), diff --git a/vendor/github.com/prometheus/client_golang/prometheus/summary.go b/vendor/github.com/prometheus/client_golang/prometheus/summary.go index f7e92d8294507..e4c87145cb38d 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/summary.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/summary.go @@ -16,8 +16,10 @@ package prometheus import ( "fmt" "math" + "runtime" "sort" "sync" + "sync/atomic" "time" "github.com/beorn7/perks/quantile" @@ -151,7 +153,7 @@ type SummaryOpts struct { BufCap uint32 } -// Great fuck-up with the sliding-window decay algorithm... The Merge method of +// Problem with the sliding-window decay algorithm... The Merge method of // perk/quantile is actually not working as advertised - and it might be // unfixable, as the underlying algorithm is apparently not capable of merging // summaries in the first place. To avoid using Merge, we are currently adding @@ -181,7 +183,7 @@ func NewSummary(opts SummaryOpts) Summary { func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { if len(desc.variableLabels) != len(labelValues) { - panic(errInconsistentCardinality) + panic(makeInconsistentCardinalityError(desc.fqName, desc.variableLabels, labelValues)) } for _, n := range desc.variableLabels { @@ -214,6 +216,17 @@ func newSummary(desc *Desc, opts SummaryOpts, labelValues ...string) Summary { opts.BufCap = DefBufCap } + if len(opts.Objectives) == 0 { + // Use the lock-free implementation of a Summary without objectives. + s := &noObjectivesSummary{ + desc: desc, + labelPairs: makeLabelPairs(desc, labelValues), + counts: [2]*summaryCounts{&summaryCounts{}, &summaryCounts{}}, + } + s.init(s) // Init self-collection. + return s + } + s := &summary{ desc: desc, @@ -382,6 +395,142 @@ func (s *summary) swapBufs(now time.Time) { } } +type summaryCounts struct { + // sumBits contains the bits of the float64 representing the sum of all + // observations. sumBits and count have to go first in the struct to + // guarantee alignment for atomic operations. + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + sumBits uint64 + count uint64 +} + +type noObjectivesSummary struct { + // countAndHotIdx is a complicated one. For lock-free yet atomic + // observations, we need to save the total count of observations again, + // combined with the index of the currently-hot counts struct, so that + // we can perform the operation on both values atomically. The least + // significant bit defines the hot counts struct. The remaining 63 bits + // represent the total count of observations. This happens under the + // assumption that the 63bit count will never overflow. Rationale: An + // observations takes about 30ns. Let's assume it could happen in + // 10ns. Overflowing the counter will then take at least (2^63)*10ns, + // which is about 3000 years. + // + // This has to be first in the struct for 64bit alignment. See + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG + countAndHotIdx uint64 + + selfCollector + desc *Desc + writeMtx sync.Mutex // Only used in the Write method. + + // Two counts, one is "hot" for lock-free observations, the other is + // "cold" for writing out a dto.Metric. It has to be an array of + // pointers to guarantee 64bit alignment of the histogramCounts, see + // http://golang.org/pkg/sync/atomic/#pkg-note-BUG. + counts [2]*summaryCounts + hotIdx int // Index of currently-hot counts. Only used within Write. + + labelPairs []*dto.LabelPair +} + +func (s *noObjectivesSummary) Desc() *Desc { + return s.desc +} + +func (s *noObjectivesSummary) Observe(v float64) { + // We increment s.countAndHotIdx by 2 so that the counter in the upper + // 63 bits gets incremented by 1. At the same time, we get the new value + // back, which we can use to find the currently-hot counts. + n := atomic.AddUint64(&s.countAndHotIdx, 2) + hotCounts := s.counts[n%2] + + for { + oldBits := atomic.LoadUint64(&hotCounts.sumBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + v) + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { + break + } + } + // Increment count last as we take it as a signal that the observation + // is complete. + atomic.AddUint64(&hotCounts.count, 1) +} + +func (s *noObjectivesSummary) Write(out *dto.Metric) error { + var ( + sum = &dto.Summary{} + hotCounts, coldCounts *summaryCounts + count uint64 + ) + + // For simplicity, we mutex the rest of this method. It is not in the + // hot path, i.e. Observe is called much more often than Write. The + // complication of making Write lock-free isn't worth it. + s.writeMtx.Lock() + defer s.writeMtx.Unlock() + + // This is a bit arcane, which is why the following spells out this if + // clause in English: + // + // If the currently-hot counts struct is #0, we atomically increment + // s.countAndHotIdx by 1 so that from now on Observe will use the counts + // struct #1. Furthermore, the atomic increment gives us the new value, + // which, in its most significant 63 bits, tells us the count of + // observations done so far up to and including currently ongoing + // observations still using the counts struct just changed from hot to + // cold. To have a normal uint64 for the count, we bitshift by 1 and + // save the result in count. We also set s.hotIdx to 1 for the next + // Write call, and we will refer to counts #1 as hotCounts and to counts + // #0 as coldCounts. + // + // If the currently-hot counts struct is #1, we do the corresponding + // things the other way round. We have to _decrement_ s.countAndHotIdx + // (which is a bit arcane in itself, as we have to express -1 with an + // unsigned int...). + if s.hotIdx == 0 { + count = atomic.AddUint64(&s.countAndHotIdx, 1) >> 1 + s.hotIdx = 1 + hotCounts = s.counts[1] + coldCounts = s.counts[0] + } else { + count = atomic.AddUint64(&s.countAndHotIdx, ^uint64(0)) >> 1 // Decrement. + s.hotIdx = 0 + hotCounts = s.counts[0] + coldCounts = s.counts[1] + } + + // Now we have to wait for the now-declared-cold counts to actually cool + // down, i.e. wait for all observations still using it to finish. That's + // the case once the count in the cold counts struct is the same as the + // one atomically retrieved from the upper 63bits of s.countAndHotIdx. + for { + if count == atomic.LoadUint64(&coldCounts.count) { + break + } + runtime.Gosched() // Let observations get work done. + } + + sum.SampleCount = proto.Uint64(count) + sum.SampleSum = proto.Float64(math.Float64frombits(atomic.LoadUint64(&coldCounts.sumBits))) + + out.Summary = sum + out.Label = s.labelPairs + + // Finally add all the cold counts to the new hot counts and reset the cold counts. + atomic.AddUint64(&hotCounts.count, count) + atomic.StoreUint64(&coldCounts.count, 0) + for { + oldBits := atomic.LoadUint64(&hotCounts.sumBits) + newBits := math.Float64bits(math.Float64frombits(oldBits) + sum.GetSampleSum()) + if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) { + atomic.StoreUint64(&coldCounts.sumBits, 0) + break + } + } + return nil +} + type quantSort []*dto.Quantile func (s quantSort) Len() int { diff --git a/vendor/github.com/prometheus/client_golang/prometheus/timer.go b/vendor/github.com/prometheus/client_golang/prometheus/timer.go index b8fc5f18c853a..8d5f10523375a 100644 --- a/vendor/github.com/prometheus/client_golang/prometheus/timer.go +++ b/vendor/github.com/prometheus/client_golang/prometheus/timer.go @@ -39,13 +39,16 @@ func NewTimer(o Observer) *Timer { // ObserveDuration records the duration passed since the Timer was created with // NewTimer. It calls the Observe method of the Observer provided during -// construction with the duration in seconds as an argument. ObserveDuration is -// usually called with a defer statement. +// construction with the duration in seconds as an argument. The observed +// duration is also returned. ObserveDuration is usually called with a defer +// statement. // // Note that this method is only guaranteed to never observe negative durations // if used with Go1.9+. -func (t *Timer) ObserveDuration() { +func (t *Timer) ObserveDuration() time.Duration { + d := time.Since(t.begin) if t.observer != nil { - t.observer.Observe(time.Since(t.begin).Seconds()) + t.observer.Observe(d.Seconds()) } + return d } diff --git a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go index 648b38cb6546d..26e92288c7c09 100644 --- a/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go +++ b/vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg.go @@ -1,12 +1,12 @@ /* +Copyright (c) 2011, Open Knowledge Foundation Ltd. +All rights reserved. + HTTP Content-Type Autonegotiation. The functions in this package implement the behaviour specified in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html -Copyright (c) 2011, Open Knowledge Foundation Ltd. -All rights reserved. - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/vendor/github.com/prometheus/common/model/metric.go b/vendor/github.com/prometheus/common/model/metric.go index f7250909b9fd3..00804b7fedb02 100644 --- a/vendor/github.com/prometheus/common/model/metric.go +++ b/vendor/github.com/prometheus/common/model/metric.go @@ -21,7 +21,6 @@ import ( ) var ( - separator = []byte{0} // MetricNameRE is a regular expression matching valid metric // names. Note that the IsValidMetricName function performs the same // check but faster than a match with this regular expression. diff --git a/vendor/github.com/prometheus/procfs/MAINTAINERS.md b/vendor/github.com/prometheus/procfs/MAINTAINERS.md index 35993c41c277f..f1d3b9937b730 100644 --- a/vendor/github.com/prometheus/procfs/MAINTAINERS.md +++ b/vendor/github.com/prometheus/procfs/MAINTAINERS.md @@ -1 +1,2 @@ -* Tobias Schmidt +* Tobias Schmidt @grobie +* Johannes 'fish' Ziemke @discordianfish diff --git a/vendor/github.com/prometheus/procfs/Makefile b/vendor/github.com/prometheus/procfs/Makefile index 4d10983946675..947d7d8fa7179 100644 --- a/vendor/github.com/prometheus/procfs/Makefile +++ b/vendor/github.com/prometheus/procfs/Makefile @@ -11,49 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Ensure GOBIN is not set during build so that promu is installed to the correct path -unexport GOBIN - -GO ?= go -GOFMT ?= $(GO)fmt -FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) -STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck -pkgs = $(shell $(GO) list ./... | grep -v /vendor/) - -PREFIX ?= $(shell pwd) -BIN_DIR ?= $(shell pwd) - -ifdef DEBUG - bindata_flags = -debug -endif - -STATICCHECK_IGNORE = - -all: format staticcheck build test - -style: - @echo ">> checking code style" - @! $(GOFMT) -d $(shell find . -path ./vendor -prune -o -name '*.go' -print) | grep '^' - -check_license: - @echo ">> checking license header" - @./scripts/check_license.sh - -test: fixtures/.unpacked sysfs/fixtures/.unpacked - @echo ">> running all tests" - @$(GO) test -race $(shell $(GO) list ./... | grep -v /vendor/ | grep -v examples) - -format: - @echo ">> formatting code" - @$(GO) fmt $(pkgs) - -vet: - @echo ">> vetting code" - @$(GO) vet $(pkgs) - -staticcheck: $(STATICCHECK) - @echo ">> running staticcheck" - @$(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) +include Makefile.common %/.unpacked: %.ttar ./ttar -C $(dir $*) -x -f $*.ttar @@ -65,13 +23,8 @@ update_fixtures: fixtures.ttar sysfs/fixtures.ttar rm -v $(dir $*)fixtures/.unpacked ./ttar -C $(dir $*) -c -f $*fixtures.ttar fixtures/ -$(FIRST_GOPATH)/bin/staticcheck: - @GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck - -.PHONY: all style check_license format test vet staticcheck +.PHONY: build +build: -# Declaring the binaries at their default locations as PHONY targets is a hack -# to ensure the latest version is downloaded on every make execution. -# If this is not desired, copy/symlink these binaries to a different path and -# set the respective environment variables. -.PHONY: $(GOPATH)/bin/staticcheck +.PHONY: test +test: fixtures/.unpacked sysfs/fixtures/.unpacked common-test diff --git a/vendor/github.com/prometheus/procfs/Makefile.common b/vendor/github.com/prometheus/procfs/Makefile.common new file mode 100644 index 0000000000000..741579e60f27c --- /dev/null +++ b/vendor/github.com/prometheus/procfs/Makefile.common @@ -0,0 +1,223 @@ +# Copyright 2018 The Prometheus Authors +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# A common Makefile that includes rules to be reused in different prometheus projects. +# !!! Open PRs only against the prometheus/prometheus/Makefile.common repository! + +# Example usage : +# Create the main Makefile in the root project directory. +# include Makefile.common +# customTarget: +# @echo ">> Running customTarget" +# + +# Ensure GOBIN is not set during build so that promu is installed to the correct path +unexport GOBIN + +GO ?= go +GOFMT ?= $(GO)fmt +FIRST_GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) +GOOPTS ?= + +GO_VERSION ?= $(shell $(GO) version) +GO_VERSION_NUMBER ?= $(word 3, $(GO_VERSION)) +PRE_GO_111 ?= $(shell echo $(GO_VERSION_NUMBER) | grep -E 'go1\.(10|[0-9])\.') + +unexport GOVENDOR +ifeq (, $(PRE_GO_111)) + ifneq (,$(wildcard go.mod)) + # Enforce Go modules support just in case the directory is inside GOPATH (and for Travis CI). + GO111MODULE := on + + ifneq (,$(wildcard vendor)) + # Always use the local vendor/ directory to satisfy the dependencies. + GOOPTS := $(GOOPTS) -mod=vendor + endif + endif +else + ifneq (,$(wildcard go.mod)) + ifneq (,$(wildcard vendor)) +$(warning This repository requires Go >= 1.11 because of Go modules) +$(warning Some recipes may not work as expected as the current Go runtime is '$(GO_VERSION_NUMBER)') + endif + else + # This repository isn't using Go modules (yet). + GOVENDOR := $(FIRST_GOPATH)/bin/govendor + endif + + unexport GO111MODULE +endif +PROMU := $(FIRST_GOPATH)/bin/promu +STATICCHECK := $(FIRST_GOPATH)/bin/staticcheck +pkgs = ./... + +GO_VERSION ?= $(shell $(GO) version) +GO_BUILD_PLATFORM ?= $(subst /,-,$(lastword $(GO_VERSION))) + +PROMU_VERSION ?= 0.2.0 +PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz + +PREFIX ?= $(shell pwd) +BIN_DIR ?= $(shell pwd) +DOCKER_IMAGE_TAG ?= $(subst /,-,$(shell git rev-parse --abbrev-ref HEAD)) +DOCKER_REPO ?= prom + +.PHONY: all +all: precheck style staticcheck unused build test + +# This rule is used to forward a target like "build" to "common-build". This +# allows a new "build" target to be defined in a Makefile which includes this +# one and override "common-build" without override warnings. +%: common-% ; + +.PHONY: common-style +common-style: + @echo ">> checking code style" + @fmtRes=$$($(GOFMT) -d $$(find . -path ./vendor -prune -o -name '*.go' -print)); \ + if [ -n "$${fmtRes}" ]; then \ + echo "gofmt checking failed!"; echo "$${fmtRes}"; echo; \ + echo "Please ensure you are using $$($(GO) version) for formatting code."; \ + exit 1; \ + fi + +.PHONY: common-check_license +common-check_license: + @echo ">> checking license header" + @licRes=$$(for file in $$(find . -type f -iname '*.go' ! -path './vendor/*') ; do \ + awk 'NR<=3' $$file | grep -Eq "(Copyright|generated|GENERATED)" || echo $$file; \ + done); \ + if [ -n "$${licRes}" ]; then \ + echo "license header checking failed:"; echo "$${licRes}"; \ + exit 1; \ + fi + +.PHONY: common-test-short +common-test-short: + @echo ">> running short tests" + GO111MODULE=$(GO111MODULE) $(GO) test -short $(GOOPTS) $(pkgs) + +.PHONY: common-test +common-test: + @echo ">> running all tests" + GO111MODULE=$(GO111MODULE) $(GO) test -race $(GOOPTS) $(pkgs) + +.PHONY: common-format +common-format: + @echo ">> formatting code" + GO111MODULE=$(GO111MODULE) $(GO) fmt $(GOOPTS) $(pkgs) + +.PHONY: common-vet +common-vet: + @echo ">> vetting code" + GO111MODULE=$(GO111MODULE) $(GO) vet $(GOOPTS) $(pkgs) + +.PHONY: common-staticcheck +common-staticcheck: $(STATICCHECK) + @echo ">> running staticcheck" +ifdef GO111MODULE + GO111MODULE=$(GO111MODULE) $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" -checks "SA*" $(pkgs) +else + $(STATICCHECK) -ignore "$(STATICCHECK_IGNORE)" $(pkgs) +endif + +.PHONY: common-unused +common-unused: $(GOVENDOR) +ifdef GOVENDOR + @echo ">> running check for unused packages" + @$(GOVENDOR) list +unused | grep . && exit 1 || echo 'No unused packages' +else +ifdef GO111MODULE + @echo ">> running check for unused/missing packages in go.mod" + GO111MODULE=$(GO111MODULE) $(GO) mod tidy + @git diff --exit-code -- go.sum go.mod +ifneq (,$(wildcard vendor)) + @echo ">> running check for unused packages in vendor/" + GO111MODULE=$(GO111MODULE) $(GO) mod vendor + @git diff --exit-code -- go.sum go.mod vendor/ +endif +endif +endif + +.PHONY: common-build +common-build: promu + @echo ">> building binaries" + GO111MODULE=$(GO111MODULE) $(PROMU) build --prefix $(PREFIX) + +.PHONY: common-tarball +common-tarball: promu + @echo ">> building release tarball" + $(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR) + +.PHONY: common-docker +common-docker: + docker build -t "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" . + +.PHONY: common-docker-publish +common-docker-publish: + docker push "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)" + +.PHONY: common-docker-tag-latest +common-docker-tag-latest: + docker tag "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)" "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME):latest" + +.PHONY: promu +promu: $(PROMU) + +$(PROMU): + curl -s -L $(PROMU_URL) | tar -xvz -C /tmp + mkdir -v -p $(FIRST_GOPATH)/bin + cp -v /tmp/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM)/promu $(PROMU) + +.PHONY: proto +proto: + @echo ">> generating code from proto files" + @./scripts/genproto.sh + +.PHONY: $(STATICCHECK) +$(STATICCHECK): +ifdef GO111MODULE +# Get staticcheck from a temporary directory to avoid modifying the local go.{mod,sum}. +# See https://github.com/golang/go/issues/27643. +# For now, we are using the next branch of staticcheck because master isn't compatible yet with Go modules. + tmpModule=$$(mktemp -d 2>&1) && \ + mkdir -p $${tmpModule}/staticcheck && \ + cd "$${tmpModule}"/staticcheck && \ + GO111MODULE=on $(GO) mod init example.com/staticcheck && \ + GO111MODULE=on GOOS= GOARCH= $(GO) get -u honnef.co/go/tools/cmd/staticcheck@next && \ + rm -rf $${tmpModule}; +else + GOOS= GOARCH= GO111MODULE=off $(GO) get -u honnef.co/go/tools/cmd/staticcheck +endif + +ifdef GOVENDOR +.PHONY: $(GOVENDOR) +$(GOVENDOR): + GOOS= GOARCH= $(GO) get -u github.com/kardianos/govendor +endif + +.PHONY: precheck +precheck:: + +define PRECHECK_COMMAND_template = +precheck:: $(1)_precheck + + +PRECHECK_COMMAND_$(1) ?= $(1) $$(strip $$(PRECHECK_OPTIONS_$(1))) +.PHONY: $(1)_precheck +$(1)_precheck: + @if ! $$(PRECHECK_COMMAND_$(1)) 1>/dev/null 2>&1; then \ + echo "Execution of '$$(PRECHECK_COMMAND_$(1))' command failed. Is $(1) installed?"; \ + exit 1; \ + fi +endef diff --git a/vendor/github.com/prometheus/procfs/go.mod b/vendor/github.com/prometheus/procfs/go.mod new file mode 100644 index 0000000000000..e89ee6c90f608 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/go.mod @@ -0,0 +1 @@ +module github.com/prometheus/procfs diff --git a/vendor/github.com/prometheus/procfs/xfs/parse.go b/vendor/github.com/prometheus/procfs/xfs/parse.go index 2bc0ef3427d2c..b3d8634df3c01 100644 --- a/vendor/github.com/prometheus/procfs/xfs/parse.go +++ b/vendor/github.com/prometheus/procfs/xfs/parse.go @@ -43,15 +43,15 @@ func ParseStats(r io.Reader) (*Stats, error) { fieldXpc = "xpc" // Unimplemented at this time due to lack of documentation. - fieldPushAil = "push_ail" - fieldXstrat = "xstrat" - fieldAbtb2 = "abtb2" - fieldAbtc2 = "abtc2" - fieldBmbt2 = "bmbt2" - fieldIbt2 = "ibt2" - fieldFibt2 = "fibt2" - fieldQm = "qm" - fieldDebug = "debug" + // fieldPushAil = "push_ail" + // fieldXstrat = "xstrat" + // fieldAbtb2 = "abtb2" + // fieldAbtc2 = "abtc2" + // fieldBmbt2 = "bmbt2" + // fieldIbt2 = "ibt2" + // fieldFibt2 = "fibt2" + // fieldQm = "qm" + // fieldDebug = "debug" ) var xfss Stats diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go index 606cf1f972621..37dc0cfdb5b0d 100644 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go +++ b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go @@ -2,18 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build go1.7 - // Package ctxhttp provides helper functions for performing context-aware HTTP requests. package ctxhttp // import "golang.org/x/net/context/ctxhttp" import ( + "context" "io" "net/http" "net/url" "strings" - - "golang.org/x/net/context" ) // Do sends an HTTP request with the provided http.Client and returns diff --git a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go b/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go deleted file mode 100644 index 926870cc23fd6..0000000000000 --- a/vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !go1.7 - -package ctxhttp // import "golang.org/x/net/context/ctxhttp" - -import ( - "io" - "net/http" - "net/url" - "strings" - - "golang.org/x/net/context" -) - -func nop() {} - -var ( - testHookContextDoneBeforeHeaders = nop - testHookDoReturned = nop - testHookDidBodyClose = nop -) - -// Do sends an HTTP request with the provided http.Client and returns an HTTP response. -// If the client is nil, http.DefaultClient is used. -// If the context is canceled or times out, ctx.Err() will be returned. -func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { - if client == nil { - client = http.DefaultClient - } - - // TODO(djd): Respect any existing value of req.Cancel. - cancel := make(chan struct{}) - req.Cancel = cancel - - type responseAndError struct { - resp *http.Response - err error - } - result := make(chan responseAndError, 1) - - // Make local copies of test hooks closed over by goroutines below. - // Prevents data races in tests. - testHookDoReturned := testHookDoReturned - testHookDidBodyClose := testHookDidBodyClose - - go func() { - resp, err := client.Do(req) - testHookDoReturned() - result <- responseAndError{resp, err} - }() - - var resp *http.Response - - select { - case <-ctx.Done(): - testHookContextDoneBeforeHeaders() - close(cancel) - // Clean up after the goroutine calling client.Do: - go func() { - if r := <-result; r.resp != nil { - testHookDidBodyClose() - r.resp.Body.Close() - } - }() - return nil, ctx.Err() - case r := <-result: - var err error - resp, err = r.resp, r.err - if err != nil { - return resp, err - } - } - - c := make(chan struct{}) - go func() { - select { - case <-ctx.Done(): - close(cancel) - case <-c: - // The response's Body is closed. - } - }() - resp.Body = ¬ifyingReader{resp.Body, c} - - return resp, nil -} - -// Get issues a GET request via the Do function. -func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Head issues a HEAD request via the Do function. -func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) { - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - return Do(ctx, client, req) -} - -// Post issues a POST request via the Do function. -func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) { - req, err := http.NewRequest("POST", url, body) - if err != nil { - return nil, err - } - req.Header.Set("Content-Type", bodyType) - return Do(ctx, client, req) -} - -// PostForm issues a POST request via the Do function. -func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) { - return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) -} - -// notifyingReader is an io.ReadCloser that closes the notify channel after -// Close is called or a Read fails on the underlying ReadCloser. -type notifyingReader struct { - io.ReadCloser - notify chan<- struct{} -} - -func (r *notifyingReader) Read(p []byte) (int, error) { - n, err := r.ReadCloser.Read(p) - if err != nil && r.notify != nil { - close(r.notify) - r.notify = nil - } - return n, err -} - -func (r *notifyingReader) Close() error { - err := r.ReadCloser.Close() - if r.notify != nil { - close(r.notify) - r.notify = nil - } - return err -} diff --git a/vendor/golang.org/x/net/html/node.go b/vendor/golang.org/x/net/html/node.go index 2c1cade6070d3..633ee15dc55b5 100644 --- a/vendor/golang.org/x/net/html/node.go +++ b/vendor/golang.org/x/net/html/node.go @@ -177,7 +177,7 @@ func (s *nodeStack) index(n *Node) int { // contains returns whether a is within s. func (s *nodeStack) contains(a atom.Atom) bool { for _, n := range *s { - if n.DataAtom == a { + if n.DataAtom == a && n.Namespace == "" { return true } } diff --git a/vendor/golang.org/x/net/html/parse.go b/vendor/golang.org/x/net/html/parse.go index 64a5793725b9e..ca2cb5875b237 100644 --- a/vendor/golang.org/x/net/html/parse.go +++ b/vendor/golang.org/x/net/html/parse.go @@ -439,9 +439,6 @@ func (p *parser) resetInsertionMode() { case a.Select: if !last { for ancestor, first := n, p.oe[0]; ancestor != first; { - if ancestor == first { - break - } ancestor = p.oe[p.oe.index(ancestor)-1] switch ancestor.DataAtom { case a.Template: @@ -1719,8 +1716,12 @@ func inSelectIM(p *parser) bool { } p.addElement() case a.Select: - p.tok.Type = EndTagToken - return false + if p.popUntil(selectScope, a.Select) { + p.resetInsertionMode() + } else { + // Ignore the token. + return true + } case a.Input, a.Keygen, a.Textarea: if p.elementInScope(selectScope, a.Select) { p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) @@ -1750,6 +1751,9 @@ func inSelectIM(p *parser) bool { case a.Select: if p.popUntil(selectScope, a.Select) { p.resetInsertionMode() + } else { + // Ignore the token. + return true } case a.Template: return inHeadIM(p) @@ -1775,13 +1779,22 @@ func inSelectInTableIM(p *parser) bool { case StartTagToken, EndTagToken: switch p.tok.DataAtom { case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, a.Th: - if p.tok.Type == StartTagToken || p.elementInScope(tableScope, p.tok.DataAtom) { - p.parseImpliedToken(EndTagToken, a.Select, a.Select.String()) - return false - } else { + if p.tok.Type == EndTagToken && !p.elementInScope(tableScope, p.tok.DataAtom) { // Ignore the token. return true } + // This is like p.popUntil(selectScope, a.Select), but it also + // matches , not just