fix: update version of some dependencies (#20271)

Signed-off-by: Shengwen Yu <yshengwen@vmware.com>
This commit is contained in:
Shengwen YU 2024-04-12 16:59:47 +08:00 committed by GitHub
parent d75ff342f1
commit c090df9009
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
185 changed files with 4810 additions and 1280 deletions

View File

@ -38,8 +38,8 @@ require (
github.com/gorilla/handlers v1.5.1 github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/graph-gophers/dataloader v5.0.0+incompatible github.com/graph-gophers/dataloader v5.0.0+incompatible
github.com/jackc/pgconn v1.9.0 github.com/jackc/pgconn v1.14.3
github.com/jackc/pgx/v4 v4.12.0 github.com/jackc/pgx/v4 v4.18.2
github.com/jinzhu/gorm v1.9.8 // indirect github.com/jinzhu/gorm v1.9.8 // indirect
github.com/jpillora/backoff v1.0.0 github.com/jpillora/backoff v1.0.0
github.com/miekg/pkcs11 v1.1.1 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect
@ -65,8 +65,8 @@ require (
go.opentelemetry.io/otel/sdk v1.8.0 go.opentelemetry.io/otel/sdk v1.8.0
go.opentelemetry.io/otel/trace v1.19.0 go.opentelemetry.io/otel/trace v1.19.0
go.uber.org/ratelimit v0.2.0 go.uber.org/ratelimit v0.2.0
golang.org/x/crypto v0.17.0 golang.org/x/crypto v0.20.0
golang.org/x/net v0.17.0 golang.org/x/net v0.21.0
golang.org/x/oauth2 v0.10.0 golang.org/x/oauth2 v0.10.0
golang.org/x/time v0.3.0 golang.org/x/time v0.3.0
gopkg.in/h2non/gock.v1 v1.0.16 gopkg.in/h2non/gock.v1 v1.0.16
@ -103,6 +103,7 @@ require (
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bugsnag/bugsnag-go v1.5.2 // indirect github.com/bugsnag/bugsnag-go v1.5.2 // indirect
github.com/bugsnag/panicwrap v1.2.0 // indirect github.com/bugsnag/panicwrap v1.2.0 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cloudflare/cfssl v0.0.0-20190510060611-9c027c93ba9e // indirect github.com/cloudflare/cfssl v0.0.0-20190510060611-9c027c93ba9e // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
@ -135,9 +136,9 @@ require (
github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 // indirect github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.1.1 // indirect github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.8.0 // indirect github.com/jackc/pgtype v1.14.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
@ -172,8 +173,8 @@ require (
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.0 // indirect go.uber.org/zap v1.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.17.0 // indirect
golang.org/x/term v0.15.0 // indirect golang.org/x/term v0.17.0 // indirect
google.golang.org/api v0.126.0 // indirect google.golang.org/api v0.126.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8 // indirect

View File

@ -124,8 +124,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/Unknwon/goconfig v0.0.0-20160216183935-5f601ca6ef4d h1:RjxaKUAINjr+fYbaYjpdBUZc8R3+wF/Yr2XkDHho4Sg= github.com/Unknwon/goconfig v0.0.0-20160216183935-5f601ca6ef4d h1:RjxaKUAINjr+fYbaYjpdBUZc8R3+wF/Yr2XkDHho4Sg=
github.com/Unknwon/goconfig v0.0.0-20160216183935-5f601ca6ef4d/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw= github.com/Unknwon/goconfig v0.0.0-20160216183935-5f601ca6ef4d/go.mod h1:wngxua9XCNjvHjDiTiV26DaKDT+0c63QR6H5hjVUUxw=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI=
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
@ -143,24 +141,19 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY=
github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk= github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0=
github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU= github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU=
@ -216,7 +209,6 @@ github.com/bugsnag/panicwrap v1.2.0 h1:OzrKrRvXis8qEvOkfcxNcYbOd2O7xXS2nnKMEMABF
github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bugsnag/panicwrap v1.2.0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM= github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog= github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
@ -238,7 +230,6 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudevents/sdk-go/v2 v2.13.0 h1:2zxDS8RyY1/wVPULGGbdgniGXSzLaRJVl136fLXGsYw= github.com/cloudevents/sdk-go/v2 v2.13.0 h1:2zxDS8RyY1/wVPULGGbdgniGXSzLaRJVl136fLXGsYw=
github.com/cloudevents/sdk-go/v2 v2.13.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To= github.com/cloudevents/sdk-go/v2 v2.13.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To=
@ -256,7 +247,6 @@ 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/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE=
github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU=
github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
@ -412,7 +402,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= 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/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw= github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
@ -421,7 +410,6 @@ github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@ -440,8 +428,6 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
@ -468,7 +454,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U=
github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E= github.com/go-ldap/ldap/v3 v3.2.4 h1:PFavAq2xTgzo/loE8qNXcQaofAaqIpI4WgaLdv+1l3E=
github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-ldap/ldap/v3 v3.2.4/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
@ -600,7 +586,6 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@ -742,9 +727,7 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplb
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
@ -762,7 +745,6 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -775,7 +757,6 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
@ -784,7 +765,6 @@ github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
@ -797,16 +777,18 @@ github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g=
github.com/jackc/pgconn v1.9.0 h1:gqibKSTJup/ahCsNKyMZAniPuZEfIqfXFc8FOWVYR+Q=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w=
github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM=
github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 h1:WAvSpGf7MsFuzAtK4Vk7R4EVe+liW4x83r4oWu0WHKw= github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451 h1:WAvSpGf7MsFuzAtK4Vk7R4EVe+liW4x83r4oWu0WHKw=
github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgerrcode v0.0.0-20201024163028-a0d42d470451/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd h1:eDErF6V/JPJON/B7s68BxwHgfmyOntHJQ8IOaz0x4R8=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
@ -817,11 +799,13 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.0.7/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.7/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag=
github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
@ -829,9 +813,9 @@ github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4
github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po=
github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ=
github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig=
github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.8.0 h1:iFVCcVhYlw0PulYCVoguRGm0SE9guIcPcccnLzHj8bA= github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw=
github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE= github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
@ -839,9 +823,9 @@ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXg
github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o=
github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg=
github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA=
github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.12.0 h1:xiP3TdnkwyslWNp77yE5XAPfxAsU9RMFDe0c1SwN8h4= github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU=
github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
@ -870,7 +854,6 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
@ -925,9 +908,6 @@ github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
@ -1012,13 +992,6 @@ github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA= github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86wM1zFnC6/uDBfZGNwB65O+pR2OFi5q/YQaEUid1qA=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/ncw/swift v1.0.49 h1:eQaKIjSt/PXLKfYgzg01nevmO+CMXfXGRhB1gOhDs7E= github.com/ncw/swift v1.0.49 h1:eQaKIjSt/PXLKfYgzg01nevmO+CMXfXGRhB1gOhDs7E=
@ -1030,8 +1003,6 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
@ -1058,7 +1029,6 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg=
github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
@ -1083,17 +1053,9 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
@ -1102,11 +1064,9 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
@ -1116,7 +1076,6 @@ github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@ -1127,7 +1086,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
@ -1135,7 +1093,6 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
@ -1144,7 +1101,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
@ -1184,7 +1140,6 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
@ -1215,7 +1170,6 @@ github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snowflakedb/gosnowflake v1.6.3/go.mod h1:6hLajn6yxuJ4xUHZegMekpq9rnQbGJ7TMwXjgTmA6lg= github.com/snowflakedb/gosnowflake v1.6.3/go.mod h1:6hLajn6yxuJ4xUHZegMekpq9rnQbGJ7TMwXjgTmA6lg=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
@ -1241,9 +1195,6 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -1318,7 +1269,6 @@ gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
@ -1331,7 +1281,6 @@ go.mongodb.org/mongo-driver v1.7.0 h1:hHrvOBWlWB2c7+8Gh/Xi5jj82AgidK/t7KVXBZ+IyU
go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@ -1415,11 +1364,12 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1523,8 +1473,8 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211013171255-e13a2654a71e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/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-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1589,7 +1539,6 @@ golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1640,12 +1589,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210818153620-00dd8d7831e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1748,7 +1697,6 @@ google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff h1:mk5zS3XLqVUzdF/CQCZ5
google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 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.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/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
@ -1763,7 +1711,6 @@ google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
@ -1803,11 +1750,9 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 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= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
@ -1862,7 +1807,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg= gopkg.in/fatih/pool.v2 v2.0.0 h1:xIFeWtxifuQJGk/IEPKsTduEKcKvPmhoiVDGpC40nKg=
gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY= gopkg.in/fatih/pool.v2 v2.0.0/go.mod h1:8xVGeu1/2jr2wm5V9SPuMht2H5AEmf5aFMGSQixtjTY=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU= gopkg.in/gorethink/gorethink.v3 v3.0.5 h1:e2Uc/Xe+hpcVQFsj6MuHlYog3r0JYpnTzwDj/y2O4MU=
gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I= gopkg.in/gorethink/gorethink.v3 v3.0.5/go.mod h1:+3yIIHJUGMBK+wyPH+iN5TP+88ikFDfZdqTlK3Y9q8I=
@ -1883,7 +1827,6 @@ gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -1996,4 +1939,3 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@ -1,3 +1,62 @@
# 1.14.3 (March 4, 2024)
* Update golang.org/x/crypto and golang.org/x/text
# 1.14.2 (March 4, 2024)
* Fix CVE-2024-27304. SQL injection can occur if an attacker can cause a single query or bind message to exceed 4 GB in
size. An integer overflow in the calculated message size can cause the one large message to be sent as multiple messages
under the attacker's control.
# 1.14.1 (July 19, 2023)
* Fix: Enable failover efforts when pg_hba.conf disallows non-ssl connections (Brandon Kauffman)
* Fix: connect_timeout is not obeyed for sslmode=allow|prefer (smaher-edb)
* Optimize redundant pgpass parsing in case password is explicitly set (Aleksandr Alekseev)
# 1.14.0 (February 11, 2023)
* Fix: each connection attempt to new node gets own timeout (Nathan Giardina)
* Set SNI for SSL connections (Stas Kelvich)
* Fix: CopyFrom I/O race (Tommy Reilly)
* Minor dependency upgrades
# 1.13.0 (August 6, 2022)
* Add sslpassword support (Eric McCormack and yun.xu)
* Add prefer-standby target_session_attrs support (sergey.bashilov)
* Fix GSS ErrorResponse handling (Oliver Tan)
# 1.12.1 (May 7, 2022)
* Fix: setting krbspn and krbsrvname in connection string (sireax)
* Add support for Unix sockets on Windows (Eno Compton)
* Stop ignoring ErrorResponse during SCRAM auth (Rafi Shamim)
# 1.12.0 (April 21, 2022)
* Add pluggable GSSAPI support (Oliver Tan)
* Fix: Consider any "0A000" error a possible cached plan changed error due to locale
* Better match psql fallback behavior with multiple hosts
# 1.11.0 (February 7, 2022)
* Support port in ip from LookupFunc to override config (James Hartig)
* Fix TLS connection timeout (Blake Embrey)
* Add support for read-only, primary, standby, prefer-standby target_session_attributes (Oscar)
* Fix connect when receiving NoticeResponse
# 1.10.1 (November 20, 2021)
* Close without waiting for response (Kei Kamikawa)
* Save waiting for network round-trip in CopyFrom (Rueian)
* Fix concurrency issue with ContextWatcher
* LRU.Get always checks context for cancellation / expiration (Georges Varouchas)
# 1.10.0 (July 24, 2021)
* net.Timeout errors are no longer returned when a query is canceled via context. A wrapped context error is returned.
# 1.9.0 (July 10, 2021) # 1.9.0 (July 10, 2021)
* pgconn.Timeout only is true for errors originating in pgconn (Michael Darr) * pgconn.Timeout only is true for errors originating in pgconn (Michael Darr)

View File

@ -1,6 +1,12 @@
[![](https://godoc.org/github.com/jackc/pgconn?status.svg)](https://godoc.org/github.com/jackc/pgconn) [![](https://godoc.org/github.com/jackc/pgconn?status.svg)](https://godoc.org/github.com/jackc/pgconn)
![CI](https://github.com/jackc/pgconn/workflows/CI/badge.svg) ![CI](https://github.com/jackc/pgconn/workflows/CI/badge.svg)
---
This version is used with pgx `v4`. In pgx `v5` it is part of the https://github.com/jackc/pgx repository.
---
# pgconn # pgconn
Package pgconn is a low-level PostgreSQL database driver. It operates at nearly the same level as the C library libpq. Package pgconn is a low-level PostgreSQL database driver. It operates at nearly the same level as the C library libpq.

View File

@ -41,7 +41,11 @@ func (c *PgConn) scramAuth(serverAuthMechanisms []string) error {
AuthMechanism: "SCRAM-SHA-256", AuthMechanism: "SCRAM-SHA-256",
Data: sc.clientFirstMessage(), Data: sc.clientFirstMessage(),
} }
_, err = c.conn.Write(saslInitialResponse.Encode(nil)) buf, err := saslInitialResponse.Encode(nil)
if err != nil {
return err
}
_, err = c.conn.Write(buf)
if err != nil { if err != nil {
return err return err
} }
@ -60,7 +64,11 @@ func (c *PgConn) scramAuth(serverAuthMechanisms []string) error {
saslResponse := &pgproto3.SASLResponse{ saslResponse := &pgproto3.SASLResponse{
Data: []byte(sc.clientFinalMessage()), Data: []byte(sc.clientFinalMessage()),
} }
_, err = c.conn.Write(saslResponse.Encode(nil)) buf, err = saslResponse.Encode(nil)
if err != nil {
return err
}
_, err = c.conn.Write(buf)
if err != nil { if err != nil {
return err return err
} }
@ -78,12 +86,14 @@ func (c *PgConn) rxSASLContinue() (*pgproto3.AuthenticationSASLContinue, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
saslContinue, ok := msg.(*pgproto3.AuthenticationSASLContinue) switch m := msg.(type) {
if ok { case *pgproto3.AuthenticationSASLContinue:
return saslContinue, nil return m, nil
case *pgproto3.ErrorResponse:
return nil, ErrorResponseToPgError(m)
} }
return nil, errors.New("expected AuthenticationSASLContinue message but received unexpected message") return nil, fmt.Errorf("expected AuthenticationSASLContinue message but received unexpected message %T", msg)
} }
func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) { func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) {
@ -91,12 +101,14 @@ func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
saslFinal, ok := msg.(*pgproto3.AuthenticationSASLFinal) switch m := msg.(type) {
if ok { case *pgproto3.AuthenticationSASLFinal:
return saslFinal, nil return m, nil
case *pgproto3.ErrorResponse:
return nil, ErrorResponseToPgError(m)
} }
return nil, errors.New("expected AuthenticationSASLFinal message but received unexpected message") return nil, fmt.Errorf("expected AuthenticationSASLFinal message but received unexpected message %T", msg)
} }
type scramClient struct { type scramClient struct {

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/pem"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -25,6 +26,7 @@ import (
type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error
type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
type GetSSLPasswordFunc func(ctx context.Context) string
// Config is the settings used to establish a connection to a PostgreSQL server. It must be created by ParseConfig. A // Config is the settings used to establish a connection to a PostgreSQL server. It must be created by ParseConfig. A
// manually initialized Config will cause ConnectConfig to panic. // manually initialized Config will cause ConnectConfig to panic.
@ -41,7 +43,9 @@ type Config struct {
BuildFrontend BuildFrontendFunc BuildFrontend BuildFrontendFunc
RuntimeParams map[string]string // Run-time parameters to set on connection as session default values (e.g. search_path or application_name) RuntimeParams map[string]string // Run-time parameters to set on connection as session default values (e.g. search_path or application_name)
Fallbacks []*FallbackConfig KerberosSrvName string
KerberosSpn string
Fallbacks []*FallbackConfig
// ValidateConnect is called during a connection attempt after a successful authentication with the PostgreSQL server. // ValidateConnect is called during a connection attempt after a successful authentication with the PostgreSQL server.
// It can be used to validate that the server is acceptable. If this returns an error the connection is closed and the next // It can be used to validate that the server is acceptable. If this returns an error the connection is closed and the next
@ -61,6 +65,13 @@ type Config struct {
createdByParseConfig bool // Used to enforce created by ParseConfig rule. createdByParseConfig bool // Used to enforce created by ParseConfig rule.
} }
// ParseConfigOptions contains options that control how a config is built such as getsslpassword.
type ParseConfigOptions struct {
// GetSSLPassword gets the password to decrypt a SSL client certificate. This is analogous to the the libpq function
// PQsetSSLKeyPassHook_OpenSSL.
GetSSLPassword GetSSLPasswordFunc
}
// Copy returns a deep copy of the config that is safe to use and modify. // Copy returns a deep copy of the config that is safe to use and modify.
// The only exception is the TLSConfig field: // The only exception is the TLSConfig field:
// according to the tls.Config docs it must not be modified after creation. // according to the tls.Config docs it must not be modified after creation.
@ -98,10 +109,29 @@ type FallbackConfig struct {
TLSConfig *tls.Config // nil disables TLS TLSConfig *tls.Config // nil disables TLS
} }
// isAbsolutePath checks if the provided value is an absolute path either
// beginning with a forward slash (as on Linux-based systems) or with a capital
// letter A-Z followed by a colon and a backslash, e.g., "C:\", (as on Windows).
func isAbsolutePath(path string) bool {
isWindowsPath := func(p string) bool {
if len(p) < 3 {
return false
}
drive := p[0]
colon := p[1]
backslash := p[2]
if drive >= 'A' && drive <= 'Z' && colon == ':' && backslash == '\\' {
return true
}
return false
}
return strings.HasPrefix(path, "/") || isWindowsPath(path)
}
// NetworkAddress converts a PostgreSQL host and port into network and address suitable for use with // NetworkAddress converts a PostgreSQL host and port into network and address suitable for use with
// net.Dial. // net.Dial.
func NetworkAddress(host string, port uint16) (network, address string) { func NetworkAddress(host string, port uint16) (network, address string) {
if strings.HasPrefix(host, "/") { if isAbsolutePath(host) {
network = "unix" network = "unix"
address = filepath.Join(host, ".s.PGSQL.") + strconv.FormatInt(int64(port), 10) address = filepath.Join(host, ".s.PGSQL.") + strconv.FormatInt(int64(port), 10)
} else { } else {
@ -111,10 +141,10 @@ func NetworkAddress(host string, port uint16) (network, address string) {
return network, address return network, address
} }
// ParseConfig builds a *Config with similar behavior to the PostgreSQL standard C library libpq. It uses the same // ParseConfig builds a *Config from connString with similar behavior to the PostgreSQL standard C library libpq. It
// defaults as libpq (e.g. port=5432) and understands most PG* environment variables. ParseConfig closely matches // uses the same defaults as libpq (e.g. port=5432) and understands most PG* environment variables. ParseConfig closely
// the parsing behavior of libpq. connString may either be in URL format or keyword = value format (DSN style). See // matches the parsing behavior of libpq. connString may either be in URL format or keyword = value format (DSN style).
// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING for details. connString also may be // See https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING for details. connString also may be
// empty to only read from the environment. If a password is not supplied it will attempt to read the .pgpass file. // empty to only read from the environment. If a password is not supplied it will attempt to read the .pgpass file.
// //
// # Example DSN // # Example DSN
@ -138,21 +168,22 @@ func NetworkAddress(host string, port uint16) (network, address string) {
// ParseConfig currently recognizes the following environment variable and their parameter key word equivalents passed // ParseConfig currently recognizes the following environment variable and their parameter key word equivalents passed
// via database URL or DSN: // via database URL or DSN:
// //
// PGHOST // PGHOST
// PGPORT // PGPORT
// PGDATABASE // PGDATABASE
// PGUSER // PGUSER
// PGPASSWORD // PGPASSWORD
// PGPASSFILE // PGPASSFILE
// PGSERVICE // PGSERVICE
// PGSERVICEFILE // PGSERVICEFILE
// PGSSLMODE // PGSSLMODE
// PGSSLCERT // PGSSLCERT
// PGSSLKEY // PGSSLKEY
// PGSSLROOTCERT // PGSSLROOTCERT
// PGAPPNAME // PGSSLPASSWORD
// PGCONNECT_TIMEOUT // PGAPPNAME
// PGTARGETSESSIONATTRS // PGCONNECT_TIMEOUT
// PGTARGETSESSIONATTRS
// //
// See http://www.postgresql.org/docs/11/static/libpq-envars.html for details on the meaning of environment variables. // See http://www.postgresql.org/docs/11/static/libpq-envars.html for details on the meaning of environment variables.
// //
@ -172,23 +203,29 @@ func NetworkAddress(host string, port uint16) (network, address string) {
// sslmode "prefer" this means it will first try the main Config settings which use TLS, then it will try the fallback // sslmode "prefer" this means it will first try the main Config settings which use TLS, then it will try the fallback
// which does not use TLS. This can lead to an unexpected unencrypted connection if the main TLS config is manually // which does not use TLS. This can lead to an unexpected unencrypted connection if the main TLS config is manually
// changed later but the unencrypted fallback is present. Ensure there are no stale fallbacks when manually setting // changed later but the unencrypted fallback is present. Ensure there are no stale fallbacks when manually setting
// TLCConfig. // TLSConfig.
// //
// Other known differences with libpq: // Other known differences with libpq:
// //
// If a host name resolves into multiple addresses, libpq will try all addresses. pgconn will only try the first.
//
// When multiple hosts are specified, libpq allows them to have different passwords set via the .pgpass file. pgconn // When multiple hosts are specified, libpq allows them to have different passwords set via the .pgpass file. pgconn
// does not. // does not.
// //
// In addition, ParseConfig accepts the following options: // In addition, ParseConfig accepts the following options:
// //
// min_read_buffer_size // min_read_buffer_size
// The minimum size of the internal read buffer. Default 8192. // The minimum size of the internal read buffer. Default 8192.
// servicefile // servicefile
// libpq only reads servicefile from the PGSERVICEFILE environment variable. ParseConfig accepts servicefile as a // libpq only reads servicefile from the PGSERVICEFILE environment variable. ParseConfig accepts servicefile as a
// part of the connection string. // part of the connection string.
func ParseConfig(connString string) (*Config, error) { func ParseConfig(connString string) (*Config, error) {
var parseConfigOptions ParseConfigOptions
return ParseConfigWithOptions(connString, parseConfigOptions)
}
// ParseConfigWithOptions builds a *Config from connString and options with similar behavior to the PostgreSQL standard
// C library libpq. options contains settings that cannot be specified in a connString such as providing a function to
// get the SSL password.
func ParseConfigWithOptions(connString string, options ParseConfigOptions) (*Config, error) {
defaultSettings := defaultSettings() defaultSettings := defaultSettings()
envSettings := parseEnvSettings() envSettings := parseEnvSettings()
@ -248,21 +285,33 @@ func ParseConfig(connString string) (*Config, error) {
config.LookupFunc = makeDefaultResolver().LookupHost config.LookupFunc = makeDefaultResolver().LookupHost
notRuntimeParams := map[string]struct{}{ notRuntimeParams := map[string]struct{}{
"host": struct{}{}, "host": {},
"port": struct{}{}, "port": {},
"database": struct{}{}, "database": {},
"user": struct{}{}, "user": {},
"password": struct{}{}, "password": {},
"passfile": struct{}{}, "passfile": {},
"connect_timeout": struct{}{}, "connect_timeout": {},
"sslmode": struct{}{}, "sslmode": {},
"sslkey": struct{}{}, "sslkey": {},
"sslcert": struct{}{}, "sslcert": {},
"sslrootcert": struct{}{}, "sslrootcert": {},
"target_session_attrs": struct{}{}, "sslpassword": {},
"min_read_buffer_size": struct{}{}, "sslsni": {},
"service": struct{}{}, "krbspn": {},
"servicefile": struct{}{}, "krbsrvname": {},
"target_session_attrs": {},
"min_read_buffer_size": {},
"service": {},
"servicefile": {},
}
// Adding kerberos configuration
if _, present := settings["krbsrvname"]; present {
config.KerberosSrvName = settings["krbsrvname"]
}
if _, present := settings["krbspn"]; present {
config.KerberosSpn = settings["krbspn"]
} }
for k, v := range settings { for k, v := range settings {
@ -297,7 +346,7 @@ func ParseConfig(connString string) (*Config, error) {
tlsConfigs = append(tlsConfigs, nil) tlsConfigs = append(tlsConfigs, nil)
} else { } else {
var err error var err error
tlsConfigs, err = configTLS(settings, host) tlsConfigs, err = configTLS(settings, host, options)
if err != nil { if err != nil {
return nil, &parseConfigError{connString: connString, msg: "failed to configure TLS", err: err} return nil, &parseConfigError{connString: connString, msg: "failed to configure TLS", err: err}
} }
@ -317,9 +366,9 @@ func ParseConfig(connString string) (*Config, error) {
config.TLSConfig = fallbacks[0].TLSConfig config.TLSConfig = fallbacks[0].TLSConfig
config.Fallbacks = fallbacks[1:] config.Fallbacks = fallbacks[1:]
passfile, err := pgpassfile.ReadPassfile(settings["passfile"]) if config.Password == "" {
if err == nil { passfile, err := pgpassfile.ReadPassfile(settings["passfile"])
if config.Password == "" { if err == nil {
host := config.Host host := config.Host
if network, _ := NetworkAddress(config.Host, config.Port); network == "unix" { if network, _ := NetworkAddress(config.Host, config.Port); network == "unix" {
host = "localhost" host = "localhost"
@ -329,10 +378,21 @@ func ParseConfig(connString string) (*Config, error) {
} }
} }
if settings["target_session_attrs"] == "read-write" { switch tsa := settings["target_session_attrs"]; tsa {
case "read-write":
config.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite config.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite
} else if settings["target_session_attrs"] != "any" { case "read-only":
return nil, &parseConfigError{connString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", settings["target_session_attrs"])} config.ValidateConnect = ValidateConnectTargetSessionAttrsReadOnly
case "primary":
config.ValidateConnect = ValidateConnectTargetSessionAttrsPrimary
case "standby":
config.ValidateConnect = ValidateConnectTargetSessionAttrsStandby
case "prefer-standby":
config.ValidateConnect = ValidateConnectTargetSessionAttrsPreferStandby
case "any":
// do nothing
default:
return nil, &parseConfigError{connString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", tsa)}
} }
return config, nil return config, nil
@ -365,7 +425,9 @@ func parseEnvSettings() map[string]string {
"PGSSLMODE": "sslmode", "PGSSLMODE": "sslmode",
"PGSSLKEY": "sslkey", "PGSSLKEY": "sslkey",
"PGSSLCERT": "sslcert", "PGSSLCERT": "sslcert",
"PGSSLSNI": "sslsni",
"PGSSLROOTCERT": "sslrootcert", "PGSSLROOTCERT": "sslrootcert",
"PGSSLPASSWORD": "sslpassword",
"PGTARGETSESSIONATTRS": "target_session_attrs", "PGTARGETSESSIONATTRS": "target_session_attrs",
"PGSERVICE": "service", "PGSERVICE": "service",
"PGSERVICEFILE": "servicefile", "PGSERVICEFILE": "servicefile",
@ -552,17 +614,22 @@ func parseServiceSettings(servicefilePath, serviceName string) (map[string]strin
// configTLS uses libpq's TLS parameters to construct []*tls.Config. It is // configTLS uses libpq's TLS parameters to construct []*tls.Config. It is
// necessary to allow returning multiple TLS configs as sslmode "allow" and // necessary to allow returning multiple TLS configs as sslmode "allow" and
// "prefer" allow fallback. // "prefer" allow fallback.
func configTLS(settings map[string]string, thisHost string) ([]*tls.Config, error) { func configTLS(settings map[string]string, thisHost string, parseConfigOptions ParseConfigOptions) ([]*tls.Config, error) {
host := thisHost host := thisHost
sslmode := settings["sslmode"] sslmode := settings["sslmode"]
sslrootcert := settings["sslrootcert"] sslrootcert := settings["sslrootcert"]
sslcert := settings["sslcert"] sslcert := settings["sslcert"]
sslkey := settings["sslkey"] sslkey := settings["sslkey"]
sslpassword := settings["sslpassword"]
sslsni := settings["sslsni"]
// Match libpq default behavior // Match libpq default behavior
if sslmode == "" { if sslmode == "" {
sslmode = "prefer" sslmode = "prefer"
} }
if sslsni == "" {
sslsni = "1"
}
tlsConfig := &tls.Config{} tlsConfig := &tls.Config{}
@ -645,14 +712,63 @@ func configTLS(settings map[string]string, thisHost string) ([]*tls.Config, erro
} }
if sslcert != "" && sslkey != "" { if sslcert != "" && sslkey != "" {
cert, err := tls.LoadX509KeyPair(sslcert, sslkey) buf, err := ioutil.ReadFile(sslkey)
if err != nil {
return nil, fmt.Errorf("unable to read sslkey: %w", err)
}
block, _ := pem.Decode(buf)
var pemKey []byte
var decryptedKey []byte
var decryptedError error
// If PEM is encrypted, attempt to decrypt using pass phrase
if x509.IsEncryptedPEMBlock(block) {
// Attempt decryption with pass phrase
// NOTE: only supports RSA (PKCS#1)
if sslpassword != "" {
decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword))
}
//if sslpassword not provided or has decryption error when use it
//try to find sslpassword with callback function
if sslpassword == "" || decryptedError != nil {
if parseConfigOptions.GetSSLPassword != nil {
sslpassword = parseConfigOptions.GetSSLPassword(context.Background())
}
if sslpassword == "" {
return nil, fmt.Errorf("unable to find sslpassword")
}
}
decryptedKey, decryptedError = x509.DecryptPEMBlock(block, []byte(sslpassword))
// Should we also provide warning for PKCS#1 needed?
if decryptedError != nil {
return nil, fmt.Errorf("unable to decrypt key: %w", err)
}
pemBytes := pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: decryptedKey,
}
pemKey = pem.EncodeToMemory(&pemBytes)
} else {
pemKey = pem.EncodeToMemory(block)
}
certfile, err := ioutil.ReadFile(sslcert)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to read cert: %w", err) return nil, fmt.Errorf("unable to read cert: %w", err)
} }
cert, err := tls.X509KeyPair(certfile, pemKey)
if err != nil {
return nil, fmt.Errorf("unable to load cert: %w", err)
}
tlsConfig.Certificates = []tls.Certificate{cert} tlsConfig.Certificates = []tls.Certificate{cert}
} }
// Set Server Name Indication (SNI), if enabled by connection parameters.
// Per RFC 6066, do not set it if the host is a literal IP address (IPv4
// or IPv6).
if sslsni == "1" && net.ParseIP(host) == nil {
tlsConfig.ServerName = host
}
switch sslmode { switch sslmode {
case "allow": case "allow":
return []*tls.Config{nil, tlsConfig}, nil return []*tls.Config{nil, tlsConfig}, nil
@ -727,3 +843,63 @@ func ValidateConnectTargetSessionAttrsReadWrite(ctx context.Context, pgConn *PgC
return nil return nil
} }
// ValidateConnectTargetSessionAttrsReadOnly is an ValidateConnectFunc that implements libpq compatible
// target_session_attrs=read-only.
func ValidateConnectTargetSessionAttrsReadOnly(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "show transaction_read_only", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
}
if string(result.Rows[0][0]) != "on" {
return errors.New("connection is not read only")
}
return nil
}
// ValidateConnectTargetSessionAttrsStandby is an ValidateConnectFunc that implements libpq compatible
// target_session_attrs=standby.
func ValidateConnectTargetSessionAttrsStandby(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
}
if string(result.Rows[0][0]) != "t" {
return errors.New("server is not in hot standby mode")
}
return nil
}
// ValidateConnectTargetSessionAttrsPrimary is an ValidateConnectFunc that implements libpq compatible
// target_session_attrs=primary.
func ValidateConnectTargetSessionAttrsPrimary(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
}
if string(result.Rows[0][0]) == "t" {
return errors.New("server is in standby mode")
}
return nil
}
// ValidateConnectTargetSessionAttrsPreferStandby is an ValidateConnectFunc that implements libpq compatible
// target_session_attrs=prefer-standby.
func ValidateConnectTargetSessionAttrsPreferStandby(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
}
if string(result.Rows[0][0]) != "t" {
return &NotPreferredError{err: errors.New("server is not in hot standby mode")}
}
return nil
}

View File

@ -1,3 +1,4 @@
//go:build !windows
// +build !windows // +build !windows
package pgconn package pgconn

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"net"
"net/url" "net/url"
"regexp" "regexp"
"strings" "strings"
@ -105,6 +106,15 @@ func (e *parseConfigError) Unwrap() error {
return e.err return e.err
} }
// preferContextOverNetTimeoutError returns ctx.Err() if ctx.Err() is present and err is a net.Error with Timeout() ==
// true. Otherwise returns err.
func preferContextOverNetTimeoutError(ctx context.Context, err error) error {
if err, ok := err.(net.Error); ok && err.Timeout() && ctx.Err() != nil {
return &errTimeout{err: ctx.Err()}
}
return err
}
type pgconnError struct { type pgconnError struct {
msg string msg string
err error err error
@ -209,3 +219,20 @@ func redactURL(u *url.URL) string {
} }
return u.String() return u.String()
} }
type NotPreferredError struct {
err error
safeToRetry bool
}
func (e *NotPreferredError) Error() string {
return fmt.Sprintf("standby server not found: %s", e.err.Error())
}
func (e *NotPreferredError) SafeToRetry() bool {
return e.safeToRetry
}
func (e *NotPreferredError) Unwrap() error {
return e.err
}

View File

@ -2,6 +2,7 @@ package ctxwatch
import ( import (
"context" "context"
"sync"
) )
// ContextWatcher watches a context and performs an action when the context is canceled. It can watch one context at a // ContextWatcher watches a context and performs an action when the context is canceled. It can watch one context at a
@ -10,8 +11,10 @@ type ContextWatcher struct {
onCancel func() onCancel func()
onUnwatchAfterCancel func() onUnwatchAfterCancel func()
unwatchChan chan struct{} unwatchChan chan struct{}
watchInProgress bool
onCancelWasCalled bool lock sync.Mutex
watchInProgress bool
onCancelWasCalled bool
} }
// NewContextWatcher returns a ContextWatcher. onCancel will be called when a watched context is canceled. // NewContextWatcher returns a ContextWatcher. onCancel will be called when a watched context is canceled.
@ -29,6 +32,9 @@ func NewContextWatcher(onCancel func(), onUnwatchAfterCancel func()) *ContextWat
// Watch starts watching ctx. If ctx is canceled then the onCancel function passed to NewContextWatcher will be called. // Watch starts watching ctx. If ctx is canceled then the onCancel function passed to NewContextWatcher will be called.
func (cw *ContextWatcher) Watch(ctx context.Context) { func (cw *ContextWatcher) Watch(ctx context.Context) {
cw.lock.Lock()
defer cw.lock.Unlock()
if cw.watchInProgress { if cw.watchInProgress {
panic("Watch already in progress") panic("Watch already in progress")
} }
@ -54,6 +60,9 @@ func (cw *ContextWatcher) Watch(ctx context.Context) {
// Unwatch stops watching the previously watched context. If the onCancel function passed to NewContextWatcher was // Unwatch stops watching the previously watched context. If the onCancel function passed to NewContextWatcher was
// called then onUnwatchAfterCancel will also be called. // called then onUnwatchAfterCancel will also be called.
func (cw *ContextWatcher) Unwatch() { func (cw *ContextWatcher) Unwatch() {
cw.lock.Lock()
defer cw.lock.Unlock()
if cw.watchInProgress { if cw.watchInProgress {
cw.unwatchChan <- struct{}{} cw.unwatchChan <- struct{}{}
if cw.onCancelWasCalled { if cw.onCancelWasCalled {

103
src/vendor/github.com/jackc/pgconn/krb5.go generated vendored Normal file
View File

@ -0,0 +1,103 @@
package pgconn
import (
"errors"
"fmt"
"github.com/jackc/pgproto3/v2"
)
// NewGSSFunc creates a GSS authentication provider, for use with
// RegisterGSSProvider.
type NewGSSFunc func() (GSS, error)
var newGSS NewGSSFunc
// RegisterGSSProvider registers a GSS authentication provider. For example, if
// you need to use Kerberos to authenticate with your server, add this to your
// main package:
//
// import "github.com/otan/gopgkrb5"
//
// func init() {
// pgconn.RegisterGSSProvider(func() (pgconn.GSS, error) { return gopgkrb5.NewGSS() })
// }
func RegisterGSSProvider(newGSSArg NewGSSFunc) {
newGSS = newGSSArg
}
// GSS provides GSSAPI authentication (e.g., Kerberos).
type GSS interface {
GetInitToken(host string, service string) ([]byte, error)
GetInitTokenFromSPN(spn string) ([]byte, error)
Continue(inToken []byte) (done bool, outToken []byte, err error)
}
func (c *PgConn) gssAuth() error {
if newGSS == nil {
return errors.New("kerberos error: no GSSAPI provider registered, see https://github.com/otan/gopgkrb5")
}
cli, err := newGSS()
if err != nil {
return err
}
var nextData []byte
if c.config.KerberosSpn != "" {
// Use the supplied SPN if provided.
nextData, err = cli.GetInitTokenFromSPN(c.config.KerberosSpn)
} else {
// Allow the kerberos service name to be overridden
service := "postgres"
if c.config.KerberosSrvName != "" {
service = c.config.KerberosSrvName
}
nextData, err = cli.GetInitToken(c.config.Host, service)
}
if err != nil {
return err
}
for {
gssResponse := &pgproto3.GSSResponse{
Data: nextData,
}
buf, err := gssResponse.Encode(nil)
if err != nil {
return err
}
_, err = c.conn.Write(buf)
if err != nil {
return err
}
resp, err := c.rxGSSContinue()
if err != nil {
return err
}
var done bool
done, nextData, err = cli.Continue(resp.Data)
if err != nil {
return err
}
if done {
break
}
}
return nil
}
func (c *PgConn) rxGSSContinue() (*pgproto3.AuthenticationGSSContinue, error) {
msg, err := c.receiveMessage()
if err != nil {
return nil, err
}
switch m := msg.(type) {
case *pgproto3.AuthenticationGSSContinue:
return m, nil
case *pgproto3.ErrorResponse:
return nil, ErrorResponseToPgError(m)
}
return nil, fmt.Errorf("expected AuthenticationGSSContinue message but received unexpected message %T", msg)
}

View File

@ -11,6 +11,7 @@ import (
"io" "io"
"math" "math"
"net" "net"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
@ -44,7 +45,8 @@ type Notification struct {
// DialFunc is a function that can be used to connect to a PostgreSQL server. // DialFunc is a function that can be used to connect to a PostgreSQL server.
type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error)
// LookupFunc is a function that can be used to lookup IPs addrs from host. // LookupFunc is a function that can be used to lookup IPs addrs from host. Optionally an ip:port combination can be
// returned in order to override the connection string's port.
type LookupFunc func(ctx context.Context, host string) (addrs []string, err error) type LookupFunc func(ctx context.Context, host string) (addrs []string, err error)
// BuildFrontendFunc is a function that can be used to create Frontend implementation for connection. // BuildFrontendFunc is a function that can be used to create Frontend implementation for connection.
@ -97,7 +99,7 @@ type PgConn struct {
} }
// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format) // Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format)
// to provide configuration. See documention for ParseConfig for details. ctx can be used to cancel a connect attempt. // to provide configuration. See documentation for ParseConfig for details. ctx can be used to cancel a connect attempt.
func Connect(ctx context.Context, connString string) (*PgConn, error) { func Connect(ctx context.Context, connString string) (*PgConn, error) {
config, err := ParseConfig(connString) config, err := ParseConfig(connString)
if err != nil { if err != nil {
@ -107,6 +109,18 @@ func Connect(ctx context.Context, connString string) (*PgConn, error) {
return ConnectConfig(ctx, config) return ConnectConfig(ctx, config)
} }
// Connect establishes a connection to a PostgreSQL server using the environment and connString (in URL or DSN format)
// and ParseConfigOptions to provide additional configuration. See documentation for ParseConfig for details. ctx can be
// used to cancel a connect attempt.
func ConnectWithOptions(ctx context.Context, connString string, parseConfigOptions ParseConfigOptions) (*PgConn, error) {
config, err := ParseConfigWithOptions(connString, parseConfigOptions)
if err != nil {
return nil, err
}
return ConnectConfig(ctx, config)
}
// Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with // Connect establishes a connection to a PostgreSQL server using config. config must have been constructed with
// ParseConfig. ctx can be used to cancel a connect attempt. // ParseConfig. ctx can be used to cancel a connect attempt.
// //
@ -114,19 +128,13 @@ func Connect(ctx context.Context, connString string) (*PgConn, error) {
// authentication error will terminate the chain of attempts (like libpq: // authentication error will terminate the chain of attempts (like libpq:
// https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error. Otherwise, // https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS) and be returned as the error. Otherwise,
// if all attempts fail the last error is returned. // if all attempts fail the last error is returned.
func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err error) { func ConnectConfig(octx context.Context, config *Config) (pgConn *PgConn, err error) {
// Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from // Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
// zero values. // zero values.
if !config.createdByParseConfig { if !config.createdByParseConfig {
panic("config must be created by ParseConfig") panic("config must be created by ParseConfig")
} }
// ConnectTimeout restricts the whole connection process.
if config.ConnectTimeout != 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, config.ConnectTimeout)
defer cancel()
}
// Simplify usage by treating primary config and fallbacks the same. // Simplify usage by treating primary config and fallbacks the same.
fallbackConfigs := []*FallbackConfig{ fallbackConfigs := []*FallbackConfig{
{ {
@ -136,7 +144,7 @@ func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err err
}, },
} }
fallbackConfigs = append(fallbackConfigs, config.Fallbacks...) fallbackConfigs = append(fallbackConfigs, config.Fallbacks...)
ctx := octx
fallbackConfigs, err = expandWithIPs(ctx, config.LookupFunc, fallbackConfigs) fallbackConfigs, err = expandWithIPs(ctx, config.LookupFunc, fallbackConfigs)
if err != nil { if err != nil {
return nil, &connectError{config: config, msg: "hostname resolving error", err: err} return nil, &connectError{config: config, msg: "hostname resolving error", err: err}
@ -146,17 +154,47 @@ func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err err
return nil, &connectError{config: config, msg: "hostname resolving error", err: errors.New("ip addr wasn't found")} return nil, &connectError{config: config, msg: "hostname resolving error", err: errors.New("ip addr wasn't found")}
} }
for _, fc := range fallbackConfigs { foundBestServer := false
pgConn, err = connect(ctx, config, fc) var fallbackConfig *FallbackConfig
for i, fc := range fallbackConfigs {
// ConnectTimeout restricts the whole connection process.
if config.ConnectTimeout != 0 {
// create new context first time or when previous host was different
if i == 0 || (fallbackConfigs[i].Host != fallbackConfigs[i-1].Host) {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(octx, config.ConnectTimeout)
defer cancel()
}
} else {
ctx = octx
}
pgConn, err = connect(ctx, config, fc, false)
if err == nil { if err == nil {
foundBestServer = true
break break
} else if pgerr, ok := err.(*PgError); ok { } else if pgerr, ok := err.(*PgError); ok {
err = &connectError{config: config, msg: "server error", err: pgerr} err = &connectError{config: config, msg: "server error", err: pgerr}
ERRCODE_INVALID_PASSWORD := "28P01" // worng password const ERRCODE_INVALID_PASSWORD = "28P01" // wrong password
ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION := "28000" // db does not exist const ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION = "28000" // wrong password or bad pg_hba.conf settings
if pgerr.Code == ERRCODE_INVALID_PASSWORD || pgerr.Code == ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION { const ERRCODE_INVALID_CATALOG_NAME = "3D000" // db does not exist
const ERRCODE_INSUFFICIENT_PRIVILEGE = "42501" // missing connect privilege
if pgerr.Code == ERRCODE_INVALID_PASSWORD ||
pgerr.Code == ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION && fc.TLSConfig != nil ||
pgerr.Code == ERRCODE_INVALID_CATALOG_NAME ||
pgerr.Code == ERRCODE_INSUFFICIENT_PRIVILEGE {
break break
} }
} else if cerr, ok := err.(*connectError); ok {
if _, ok := cerr.err.(*NotPreferredError); ok {
fallbackConfig = fc
}
}
}
if !foundBestServer && fallbackConfig != nil {
pgConn, err = connect(ctx, config, fallbackConfig, true)
if pgerr, ok := err.(*PgError); ok {
err = &connectError{config: config, msg: "server error", err: pgerr}
} }
} }
@ -180,7 +218,7 @@ func expandWithIPs(ctx context.Context, lookupFn LookupFunc, fallbacks []*Fallba
for _, fb := range fallbacks { for _, fb := range fallbacks {
// skip resolve for unix sockets // skip resolve for unix sockets
if strings.HasPrefix(fb.Host, "/") { if isAbsolutePath(fb.Host) {
configs = append(configs, &FallbackConfig{ configs = append(configs, &FallbackConfig{
Host: fb.Host, Host: fb.Host,
Port: fb.Port, Port: fb.Port,
@ -196,18 +234,32 @@ func expandWithIPs(ctx context.Context, lookupFn LookupFunc, fallbacks []*Fallba
} }
for _, ip := range ips { for _, ip := range ips {
configs = append(configs, &FallbackConfig{ splitIP, splitPort, err := net.SplitHostPort(ip)
Host: ip, if err == nil {
Port: fb.Port, port, err := strconv.ParseUint(splitPort, 10, 16)
TLSConfig: fb.TLSConfig, if err != nil {
}) return nil, fmt.Errorf("error parsing port (%s) from lookup: %w", splitPort, err)
}
configs = append(configs, &FallbackConfig{
Host: splitIP,
Port: uint16(port),
TLSConfig: fb.TLSConfig,
})
} else {
configs = append(configs, &FallbackConfig{
Host: ip,
Port: fb.Port,
TLSConfig: fb.TLSConfig,
})
}
} }
} }
return configs, nil return configs, nil
} }
func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig) (*PgConn, error) { func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig,
ignoreNotPreferredErr bool) (*PgConn, error) {
pgConn := new(PgConn) pgConn := new(PgConn)
pgConn.config = config pgConn.config = config
pgConn.wbuf = make([]byte, 0, wbufLen) pgConn.wbuf = make([]byte, 0, wbufLen)
@ -215,7 +267,7 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
var err error var err error
network, address := NetworkAddress(fallbackConfig.Host, fallbackConfig.Port) network, address := NetworkAddress(fallbackConfig.Host, fallbackConfig.Port)
pgConn.conn, err = config.DialFunc(ctx, network, address) netConn, err := config.DialFunc(ctx, network, address)
if err != nil { if err != nil {
var netErr net.Error var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() { if errors.As(err, &netErr) && netErr.Timeout() {
@ -224,24 +276,27 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
return nil, &connectError{config: config, msg: "dial error", err: err} return nil, &connectError{config: config, msg: "dial error", err: err}
} }
pgConn.parameterStatuses = make(map[string]string) pgConn.conn = netConn
pgConn.contextWatcher = newContextWatcher(netConn)
pgConn.contextWatcher.Watch(ctx)
if fallbackConfig.TLSConfig != nil { if fallbackConfig.TLSConfig != nil {
if err := pgConn.startTLS(fallbackConfig.TLSConfig); err != nil { tlsConn, err := startTLS(netConn, fallbackConfig.TLSConfig)
pgConn.conn.Close() pgConn.contextWatcher.Unwatch() // Always unwatch `netConn` after TLS.
if err != nil {
netConn.Close()
return nil, &connectError{config: config, msg: "tls error", err: err} return nil, &connectError{config: config, msg: "tls error", err: err}
} }
pgConn.conn = tlsConn
pgConn.contextWatcher = newContextWatcher(tlsConn)
pgConn.contextWatcher.Watch(ctx)
} }
pgConn.status = connStatusConnecting
pgConn.contextWatcher = ctxwatch.NewContextWatcher(
func() { pgConn.conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) },
func() { pgConn.conn.SetDeadline(time.Time{}) },
)
pgConn.contextWatcher.Watch(ctx)
defer pgConn.contextWatcher.Unwatch() defer pgConn.contextWatcher.Unwatch()
pgConn.parameterStatuses = make(map[string]string)
pgConn.status = connStatusConnecting
pgConn.frontend = config.BuildFrontend(pgConn.conn, pgConn.conn) pgConn.frontend = config.BuildFrontend(pgConn.conn, pgConn.conn)
startupMsg := pgproto3.StartupMessage{ startupMsg := pgproto3.StartupMessage{
@ -259,7 +314,11 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
startupMsg.Parameters["database"] = config.Database startupMsg.Parameters["database"] = config.Database
} }
if _, err := pgConn.conn.Write(startupMsg.Encode(pgConn.wbuf)); err != nil { buf, err := startupMsg.Encode(pgConn.wbuf)
if err != nil {
return nil, &connectError{config: config, msg: "failed to write startup message", err: err}
}
if _, err := pgConn.conn.Write(buf); err != nil {
pgConn.conn.Close() pgConn.conn.Close()
return nil, &connectError{config: config, msg: "failed to write startup message", err: err} return nil, &connectError{config: config, msg: "failed to write startup message", err: err}
} }
@ -271,7 +330,7 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
if err, ok := err.(*PgError); ok { if err, ok := err.(*PgError); ok {
return nil, err return nil, err
} }
return nil, &connectError{config: config, msg: "failed to receive message", err: err} return nil, &connectError{config: config, msg: "failed to receive message", err: preferContextOverNetTimeoutError(ctx, err)}
} }
switch msg := msg.(type) { switch msg := msg.(type) {
@ -299,7 +358,12 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
pgConn.conn.Close() pgConn.conn.Close()
return nil, &connectError{config: config, msg: "failed SASL auth", err: err} return nil, &connectError{config: config, msg: "failed SASL auth", err: err}
} }
case *pgproto3.AuthenticationGSS:
err = pgConn.gssAuth()
if err != nil {
pgConn.conn.Close()
return nil, &connectError{config: config, msg: "failed GSS auth", err: err}
}
case *pgproto3.ReadyForQuery: case *pgproto3.ReadyForQuery:
pgConn.status = connStatusIdle pgConn.status = connStatusIdle
if config.ValidateConnect != nil { if config.ValidateConnect != nil {
@ -312,12 +376,15 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
err := config.ValidateConnect(ctx, pgConn) err := config.ValidateConnect(ctx, pgConn)
if err != nil { if err != nil {
if _, ok := err.(*NotPreferredError); ignoreNotPreferredErr && ok {
return pgConn, nil
}
pgConn.conn.Close() pgConn.conn.Close()
return nil, &connectError{config: config, msg: "ValidateConnect failed", err: err} return nil, &connectError{config: config, msg: "ValidateConnect failed", err: err}
} }
} }
return pgConn, nil return pgConn, nil
case *pgproto3.ParameterStatus: case *pgproto3.ParameterStatus, *pgproto3.NoticeResponse:
// handled by ReceiveMessage // handled by ReceiveMessage
case *pgproto3.ErrorResponse: case *pgproto3.ErrorResponse:
pgConn.conn.Close() pgConn.conn.Close()
@ -329,29 +396,38 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
} }
} }
func (pgConn *PgConn) startTLS(tlsConfig *tls.Config) (err error) { func newContextWatcher(conn net.Conn) *ctxwatch.ContextWatcher {
err = binary.Write(pgConn.conn, binary.BigEndian, []int32{8, 80877103}) return ctxwatch.NewContextWatcher(
func() { conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) },
func() { conn.SetDeadline(time.Time{}) },
)
}
func startTLS(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) {
err := binary.Write(conn, binary.BigEndian, []int32{8, 80877103})
if err != nil { if err != nil {
return return nil, err
} }
response := make([]byte, 1) response := make([]byte, 1)
if _, err = io.ReadFull(pgConn.conn, response); err != nil { if _, err = io.ReadFull(conn, response); err != nil {
return return nil, err
} }
if response[0] != 'S' { if response[0] != 'S' {
return errors.New("server refused TLS connection") return nil, errors.New("server refused TLS connection")
} }
pgConn.conn = tls.Client(pgConn.conn, tlsConfig) return tls.Client(conn, tlsConfig), nil
return nil
} }
func (pgConn *PgConn) txPasswordMessage(password string) (err error) { func (pgConn *PgConn) txPasswordMessage(password string) (err error) {
msg := &pgproto3.PasswordMessage{Password: password} msg := &pgproto3.PasswordMessage{Password: password}
_, err = pgConn.conn.Write(msg.Encode(pgConn.wbuf)) buf, err := msg.Encode(pgConn.wbuf)
if err != nil {
return err
}
_, err = pgConn.conn.Write(buf)
return err return err
} }
@ -434,7 +510,10 @@ func (pgConn *PgConn) ReceiveMessage(ctx context.Context) (pgproto3.BackendMessa
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
err = &pgconnError{msg: "receive message failed", err: err, safeToRetry: true} err = &pgconnError{
msg: "receive message failed",
err: preferContextOverNetTimeoutError(ctx, err),
safeToRetry: true}
} }
return msg, err return msg, err
} }
@ -469,8 +548,6 @@ func (pgConn *PgConn) peekMessage() (pgproto3.BackendMessage, error) {
isNetErr := errors.As(err, &netErr) isNetErr := errors.As(err, &netErr)
if !(isNetErr && netErr.Timeout()) { if !(isNetErr && netErr.Timeout()) {
pgConn.asyncClose() pgConn.asyncClose()
} else if isNetErr && netErr.Timeout() {
err = &errTimeout{err: err}
} }
return nil, err return nil, err
@ -489,8 +566,6 @@ func (pgConn *PgConn) receiveMessage() (pgproto3.BackendMessage, error) {
isNetErr := errors.As(err, &netErr) isNetErr := errors.As(err, &netErr)
if !(isNetErr && netErr.Timeout()) { if !(isNetErr && netErr.Timeout()) {
pgConn.asyncClose() pgConn.asyncClose()
} else if isNetErr && netErr.Timeout() {
err = &errTimeout{err: err}
} }
return nil, err return nil, err
@ -535,9 +610,10 @@ func (pgConn *PgConn) PID() uint32 {
// TxStatus returns the current TxStatus as reported by the server in the ReadyForQuery message. // TxStatus returns the current TxStatus as reported by the server in the ReadyForQuery message.
// //
// Possible return values: // Possible return values:
// 'I' - idle / not in transaction //
// 'T' - in a transaction // 'I' - idle / not in transaction
// 'E' - in a failed transaction // 'T' - in a transaction
// 'E' - in a failed transaction
// //
// See https://www.postgresql.org/docs/current/protocol-message-formats.html. // See https://www.postgresql.org/docs/current/protocol-message-formats.html.
func (pgConn *PgConn) TxStatus() byte { func (pgConn *PgConn) TxStatus() byte {
@ -579,7 +655,6 @@ func (pgConn *PgConn) Close(ctx context.Context) error {
// //
// See https://github.com/jackc/pgx/issues/637 // See https://github.com/jackc/pgx/issues/637
pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) pgConn.conn.Write([]byte{'X', 0, 0, 0, 4})
pgConn.conn.Read(make([]byte, 1))
return pgConn.conn.Close() return pgConn.conn.Close()
} }
@ -606,7 +681,6 @@ func (pgConn *PgConn) asyncClose() {
pgConn.conn.SetDeadline(deadline) pgConn.conn.SetDeadline(deadline)
pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) pgConn.conn.Write([]byte{'X', 0, 0, 0, 4})
pgConn.conn.Read(make([]byte, 1))
}() }()
} }
@ -766,9 +840,19 @@ func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs [
} }
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs}).Encode(buf) var err error
buf = (&pgproto3.Describe{ObjectType: 'S', Name: name}).Encode(buf) buf, err = (&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs}).Encode(buf)
buf = (&pgproto3.Sync{}).Encode(buf) if err != nil {
return nil, err
}
buf, err = (&pgproto3.Describe{ObjectType: 'S', Name: name}).Encode(buf)
if err != nil {
return nil, err
}
buf, err = (&pgproto3.Sync{}).Encode(buf)
if err != nil {
return nil, err
}
n, err := pgConn.conn.Write(buf) n, err := pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -785,7 +869,7 @@ readloop:
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
pgConn.asyncClose() pgConn.asyncClose()
return nil, err return nil, preferContextOverNetTimeoutError(ctx, err)
} }
switch msg := msg.(type) { switch msg := msg.(type) {
@ -888,7 +972,7 @@ func (pgConn *PgConn) WaitForNotification(ctx context.Context) error {
if ctx != context.Background() { if ctx != context.Background() {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return ctx.Err() return newContextAlreadyDoneError(ctx)
default: default:
} }
@ -899,7 +983,7 @@ func (pgConn *PgConn) WaitForNotification(ctx context.Context) error {
for { for {
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
return err return preferContextOverNetTimeoutError(ctx, err)
} }
switch msg.(type) { switch msg.(type) {
@ -940,7 +1024,14 @@ func (pgConn *PgConn) Exec(ctx context.Context, sql string) *MultiResultReader {
} }
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Query{String: sql}).Encode(buf) var err error
buf, err = (&pgproto3.Query{String: sql}).Encode(buf)
if err != nil {
return &MultiResultReader{
closed: true,
err: err,
}
}
n, err := pgConn.conn.Write(buf) n, err := pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -1014,8 +1105,24 @@ func (pgConn *PgConn) ExecParams(ctx context.Context, sql string, paramValues []
} }
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(buf) var err error
buf = (&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf) buf, err = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(buf)
if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return result
}
buf, err = (&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf)
if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return result
}
pgConn.execExtendedSuffix(buf, result) pgConn.execExtendedSuffix(buf, result)
@ -1041,7 +1148,15 @@ func (pgConn *PgConn) ExecPrepared(ctx context.Context, stmtName string, paramVa
} }
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf) var err error
buf, err = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf)
if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return result
}
pgConn.execExtendedSuffix(buf, result) pgConn.execExtendedSuffix(buf, result)
@ -1084,9 +1199,31 @@ func (pgConn *PgConn) execExtendedPrefix(ctx context.Context, paramValues [][]by
} }
func (pgConn *PgConn) execExtendedSuffix(buf []byte, result *ResultReader) { func (pgConn *PgConn) execExtendedSuffix(buf []byte, result *ResultReader) {
buf = (&pgproto3.Describe{ObjectType: 'P'}).Encode(buf) var err error
buf = (&pgproto3.Execute{}).Encode(buf) buf, err = (&pgproto3.Describe{ObjectType: 'P'}).Encode(buf)
buf = (&pgproto3.Sync{}).Encode(buf) if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return
}
buf, err = (&pgproto3.Execute{}).Encode(buf)
if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return
}
buf, err = (&pgproto3.Sync{}).Encode(buf)
if err != nil {
result.concludeCommand(nil, err)
pgConn.contextWatcher.Unwatch()
result.closed = true
pgConn.unlock()
return
}
n, err := pgConn.conn.Write(buf) n, err := pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -1120,7 +1257,12 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm
// Send copy to command // Send copy to command
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Query{String: sql}).Encode(buf) var err error
buf, err = (&pgproto3.Query{String: sql}).Encode(buf)
if err != nil {
pgConn.unlock()
return nil, err
}
n, err := pgConn.conn.Write(buf) n, err := pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -1136,7 +1278,7 @@ func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (Comm
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
pgConn.asyncClose() pgConn.asyncClose()
return nil, err return nil, preferContextOverNetTimeoutError(ctx, err)
} }
switch msg := msg.(type) { switch msg := msg.(type) {
@ -1180,7 +1322,12 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
// Send copy to command // Send copy to command
buf := pgConn.wbuf buf := pgConn.wbuf
buf = (&pgproto3.Query{String: sql}).Encode(buf) var err error
buf, err = (&pgproto3.Query{String: sql}).Encode(buf)
if err != nil {
pgConn.unlock()
return nil, err
}
n, err := pgConn.conn.Write(buf) n, err := pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -1188,33 +1335,15 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
return nil, &writeError{err: err, safeToRetry: n == 0} return nil, &writeError{err: err, safeToRetry: n == 0}
} }
// Read until copy in response or error.
var commandTag CommandTag
var pgErr error
pendingCopyInResponse := true
for pendingCopyInResponse {
msg, err := pgConn.receiveMessage()
if err != nil {
pgConn.asyncClose()
return nil, err
}
switch msg := msg.(type) {
case *pgproto3.CopyInResponse:
pendingCopyInResponse = false
case *pgproto3.ErrorResponse:
pgErr = ErrorResponseToPgError(msg)
case *pgproto3.ReadyForQuery:
return commandTag, pgErr
}
}
// Send copy data // Send copy data
abortCopyChan := make(chan struct{}) abortCopyChan := make(chan struct{})
copyErrChan := make(chan error, 1) copyErrChan := make(chan error, 1)
signalMessageChan := pgConn.signalMessage() signalMessageChan := pgConn.signalMessage()
var wg sync.WaitGroup
wg.Add(1)
go func() { go func() {
defer wg.Done()
buf := make([]byte, 0, 65536) buf := make([]byte, 0, 65536)
buf = append(buf, 'd') buf = append(buf, 'd')
sp := len(buf) sp := len(buf)
@ -1247,6 +1376,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
} }
}() }()
var pgErr error
var copyErr error var copyErr error
for copyErr == nil && pgErr == nil { for copyErr == nil && pgErr == nil {
select { select {
@ -1255,7 +1385,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
pgConn.asyncClose() pgConn.asyncClose()
return nil, err return nil, preferContextOverNetTimeoutError(ctx, err)
} }
switch msg := msg.(type) { switch msg := msg.(type) {
@ -1267,14 +1397,26 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
} }
} }
close(abortCopyChan) close(abortCopyChan)
// Make sure io goroutine finishes before writing.
wg.Wait()
buf = buf[:0] buf = buf[:0]
if copyErr == io.EOF || pgErr != nil { if copyErr == io.EOF || pgErr != nil {
copyDone := &pgproto3.CopyDone{} copyDone := &pgproto3.CopyDone{}
buf = copyDone.Encode(buf) var err error
buf, err = copyDone.Encode(buf)
if err != nil {
pgConn.asyncClose()
return nil, err
}
} else { } else {
copyFail := &pgproto3.CopyFail{Message: copyErr.Error()} copyFail := &pgproto3.CopyFail{Message: copyErr.Error()}
buf = copyFail.Encode(buf) var err error
buf, err = copyFail.Encode(buf)
if err != nil {
pgConn.asyncClose()
return nil, err
}
} }
_, err = pgConn.conn.Write(buf) _, err = pgConn.conn.Write(buf)
if err != nil { if err != nil {
@ -1283,11 +1425,12 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co
} }
// Read results // Read results
var commandTag CommandTag
for { for {
msg, err := pgConn.receiveMessage() msg, err := pgConn.receiveMessage()
if err != nil { if err != nil {
pgConn.asyncClose() pgConn.asyncClose()
return nil, err return nil, preferContextOverNetTimeoutError(ctx, err)
} }
switch msg := msg.(type) { switch msg := msg.(type) {
@ -1329,7 +1472,7 @@ func (mrr *MultiResultReader) receiveMessage() (pgproto3.BackendMessage, error)
if err != nil { if err != nil {
mrr.pgConn.contextWatcher.Unwatch() mrr.pgConn.contextWatcher.Unwatch()
mrr.err = err mrr.err = preferContextOverNetTimeoutError(mrr.ctx, err)
mrr.closed = true mrr.closed = true
mrr.pgConn.asyncClose() mrr.pgConn.asyncClose()
return nil, mrr.err return nil, mrr.err
@ -1536,6 +1679,7 @@ func (rr *ResultReader) receiveMessage() (msg pgproto3.BackendMessage, err error
} }
if err != nil { if err != nil {
err = preferContextOverNetTimeoutError(rr.ctx, err)
rr.concludeCommand(nil, err) rr.concludeCommand(nil, err)
rr.pgConn.contextWatcher.Unwatch() rr.pgConn.contextWatcher.Unwatch()
rr.closed = true rr.closed = true
@ -1579,24 +1723,54 @@ func (rr *ResultReader) concludeCommand(commandTag CommandTag, err error) {
// Batch is a collection of queries that can be sent to the PostgreSQL server in a single round-trip. // Batch is a collection of queries that can be sent to the PostgreSQL server in a single round-trip.
type Batch struct { type Batch struct {
buf []byte buf []byte
err error
} }
// ExecParams appends an ExecParams command to the batch. See PgConn.ExecParams for parameter descriptions. // ExecParams appends an ExecParams command to the batch. See PgConn.ExecParams for parameter descriptions.
func (batch *Batch) ExecParams(sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats []int16, resultFormats []int16) { func (batch *Batch) ExecParams(sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats []int16, resultFormats []int16) {
batch.buf = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(batch.buf) if batch.err != nil {
return
}
batch.buf, batch.err = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(batch.buf)
if batch.err != nil {
return
}
batch.ExecPrepared("", paramValues, paramFormats, resultFormats) batch.ExecPrepared("", paramValues, paramFormats, resultFormats)
} }
// ExecPrepared appends an ExecPrepared e command to the batch. See PgConn.ExecPrepared for parameter descriptions. // ExecPrepared appends an ExecPrepared e command to the batch. See PgConn.ExecPrepared for parameter descriptions.
func (batch *Batch) ExecPrepared(stmtName string, paramValues [][]byte, paramFormats []int16, resultFormats []int16) { func (batch *Batch) ExecPrepared(stmtName string, paramValues [][]byte, paramFormats []int16, resultFormats []int16) {
batch.buf = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(batch.buf) if batch.err != nil {
batch.buf = (&pgproto3.Describe{ObjectType: 'P'}).Encode(batch.buf) return
batch.buf = (&pgproto3.Execute{}).Encode(batch.buf) }
batch.buf, batch.err = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(batch.buf)
if batch.err != nil {
return
}
batch.buf, batch.err = (&pgproto3.Describe{ObjectType: 'P'}).Encode(batch.buf)
if batch.err != nil {
return
}
batch.buf, batch.err = (&pgproto3.Execute{}).Encode(batch.buf)
if batch.err != nil {
return
}
} }
// ExecBatch executes all the queries in batch in a single round-trip. Execution is implicitly transactional unless a // ExecBatch executes all the queries in batch in a single round-trip. Execution is implicitly transactional unless a
// transaction is already in progress or SQL contains transaction control statements. // transaction is already in progress or SQL contains transaction control statements.
func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultReader { func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultReader {
if batch.err != nil {
return &MultiResultReader{
closed: true,
err: batch.err,
}
}
if err := pgConn.lock(); err != nil { if err := pgConn.lock(); err != nil {
return &MultiResultReader{ return &MultiResultReader{
closed: true, closed: true,
@ -1622,7 +1796,13 @@ func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultR
pgConn.contextWatcher.Watch(ctx) pgConn.contextWatcher.Watch(ctx)
} }
batch.buf = (&pgproto3.Sync{}).Encode(batch.buf) batch.buf, batch.err = (&pgproto3.Sync{}).Encode(batch.buf)
if batch.err != nil {
multiResult.closed = true
multiResult.err = batch.err
pgConn.unlock()
return multiResult
}
// A large batch can deadlock without concurrent reading and writing. If the Write fails the underlying net.Conn is // A large batch can deadlock without concurrent reading and writing. If the Write fails the underlying net.Conn is
// closed. This is all that can be done without introducing a race condition or adding a concurrent safe communication // closed. This is all that can be done without introducing a race condition or adding a concurrent safe communication
@ -1715,10 +1895,7 @@ func Construct(hc *HijackedConn) (*PgConn, error) {
cleanupDone: make(chan struct{}), cleanupDone: make(chan struct{}),
} }
pgConn.contextWatcher = ctxwatch.NewContextWatcher( pgConn.contextWatcher = newContextWatcher(pgConn.conn)
func() { pgConn.conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) },
func() { pgConn.conn.SetDeadline(time.Time{}) },
)
return pgConn, nil return pgConn, nil
} }

View File

@ -42,6 +42,14 @@ func NewLRU(conn *pgconn.PgConn, mode int, cap int) *LRU {
// Get returns the prepared statement description for sql preparing or describing the sql on the server as needed. // Get returns the prepared statement description for sql preparing or describing the sql on the server as needed.
func (c *LRU) Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error) { func (c *LRU) Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error) {
if ctx != context.Background() {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
}
// flush an outstanding bad statements // flush an outstanding bad statements
txStatus := c.conn.TxStatus() txStatus := c.conn.TxStatus()
if (txStatus == 'I' || txStatus == 'T') && len(c.stmtsToClear) > 0 { if (txStatus == 'I' || txStatus == 'T') && len(c.stmtsToClear) > 0 {
@ -94,10 +102,14 @@ func (c *LRU) StatementErrored(sql string, err error) {
return return
} }
isInvalidCachedPlanError := pgErr.Severity == "ERROR" && // https://github.com/jackc/pgx/issues/1162
pgErr.Code == "0A000" && //
pgErr.Message == "cached plan must not change result type" // We used to look for the message "cached plan must not change result type". However, that message can be localized.
if isInvalidCachedPlanError { // Unfortunately, error code "0A000" - "FEATURE NOT SUPPORTED" is used for many different errors and the only way to
// tell the difference is by the message. But all that happens is we clear a statement that we otherwise wouldn't
// have so it should be safe.
possibleInvalidCachedPlanError := pgErr.Code == "0A000"
if possibleInvalidCachedPlanError {
c.stmtsToClear = append(c.stmtsToClear, sql) c.stmtsToClear = append(c.stmtsToClear, sql)
} }
} }

View File

@ -1,6 +1,12 @@
[![](https://godoc.org/github.com/jackc/pgproto3?status.svg)](https://godoc.org/github.com/jackc/pgproto3) [![](https://godoc.org/github.com/jackc/pgproto3?status.svg)](https://godoc.org/github.com/jackc/pgproto3)
[![Build Status](https://travis-ci.org/jackc/pgproto3.svg)](https://travis-ci.org/jackc/pgproto3) [![Build Status](https://travis-ci.org/jackc/pgproto3.svg)](https://travis-ci.org/jackc/pgproto3)
---
This version is used with pgx `v4`. In pgx `v5` it is part of the https://github.com/jackc/pgx repository.
---
# pgproto3 # pgproto3
Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3. Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3.

View File

@ -35,11 +35,10 @@ func (dst *AuthenticationCleartextPassword) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationCleartextPassword) Encode(dst []byte) []byte { func (src *AuthenticationCleartextPassword) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendInt32(dst, 8)
dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword) dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword)
return dst return finishMessage(dst, sp)
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -0,0 +1,58 @@
package pgproto3
import (
"encoding/binary"
"encoding/json"
"errors"
"github.com/jackc/pgio"
)
type AuthenticationGSS struct{}
func (a *AuthenticationGSS) Backend() {}
func (a *AuthenticationGSS) AuthenticationResponse() {}
func (a *AuthenticationGSS) Decode(src []byte) error {
if len(src) < 4 {
return errors.New("authentication message too short")
}
authType := binary.BigEndian.Uint32(src)
if authType != AuthTypeGSS {
return errors.New("bad auth type")
}
return nil
}
func (a *AuthenticationGSS) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendUint32(dst, AuthTypeGSS)
return finishMessage(dst, sp)
}
func (a *AuthenticationGSS) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Data []byte
}{
Type: "AuthenticationGSS",
})
}
func (a *AuthenticationGSS) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
return nil
}
var msg struct {
Type string
}
if err := json.Unmarshal(data, &msg); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,67 @@
package pgproto3
import (
"encoding/binary"
"encoding/json"
"errors"
"github.com/jackc/pgio"
)
type AuthenticationGSSContinue struct {
Data []byte
}
func (a *AuthenticationGSSContinue) Backend() {}
func (a *AuthenticationGSSContinue) AuthenticationResponse() {}
func (a *AuthenticationGSSContinue) Decode(src []byte) error {
if len(src) < 4 {
return errors.New("authentication message too short")
}
authType := binary.BigEndian.Uint32(src)
if authType != AuthTypeGSSCont {
return errors.New("bad auth type")
}
a.Data = src[4:]
return nil
}
func (a *AuthenticationGSSContinue) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendUint32(dst, AuthTypeGSSCont)
dst = append(dst, a.Data...)
return finishMessage(dst, sp)
}
func (a *AuthenticationGSSContinue) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Data []byte
}{
Type: "AuthenticationGSSContinue",
Data: a.Data,
})
}
func (a *AuthenticationGSSContinue) UnmarshalJSON(data []byte) error {
// Ignore null, like in the main JSON package.
if string(data) == "null" {
return nil
}
var msg struct {
Type string
Data []byte
}
if err := json.Unmarshal(data, &msg); err != nil {
return err
}
a.Data = msg.Data
return nil
}

View File

@ -38,12 +38,11 @@ func (dst *AuthenticationMD5Password) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationMD5Password) Encode(dst []byte) []byte { func (src *AuthenticationMD5Password) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendInt32(dst, 12)
dst = pgio.AppendUint32(dst, AuthTypeMD5Password) dst = pgio.AppendUint32(dst, AuthTypeMD5Password)
dst = append(dst, src.Salt[:]...) dst = append(dst, src.Salt[:]...)
return dst return finishMessage(dst, sp)
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -35,11 +35,10 @@ func (dst *AuthenticationOk) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationOk) Encode(dst []byte) []byte { func (src *AuthenticationOk) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
dst = pgio.AppendInt32(dst, 8)
dst = pgio.AppendUint32(dst, AuthTypeOk) dst = pgio.AppendUint32(dst, AuthTypeOk)
return dst return finishMessage(dst, sp)
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -46,10 +46,8 @@ func (dst *AuthenticationSASL) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationSASL) Encode(dst []byte) []byte { func (src *AuthenticationSASL) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = pgio.AppendUint32(dst, AuthTypeSASL) dst = pgio.AppendUint32(dst, AuthTypeSASL)
for _, s := range src.AuthMechanisms { for _, s := range src.AuthMechanisms {
@ -58,9 +56,7 @@ func (src *AuthenticationSASL) Encode(dst []byte) []byte {
} }
dst = append(dst, 0) dst = append(dst, 0)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -38,17 +38,11 @@ func (dst *AuthenticationSASLContinue) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationSASLContinue) Encode(dst []byte) []byte { func (src *AuthenticationSASLContinue) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = pgio.AppendUint32(dst, AuthTypeSASLContinue) dst = pgio.AppendUint32(dst, AuthTypeSASLContinue)
dst = append(dst, src.Data...) dst = append(dst, src.Data...)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -38,17 +38,11 @@ func (dst *AuthenticationSASLFinal) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *AuthenticationSASLFinal) Encode(dst []byte) []byte { func (src *AuthenticationSASLFinal) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'R') dst, sp := beginMessage(dst, 'R')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = pgio.AppendUint32(dst, AuthTypeSASLFinal) dst = pgio.AppendUint32(dst, AuthTypeSASLFinal)
dst = append(dst, src.Data...) dst = append(dst, src.Data...)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Unmarshaler. // MarshalJSON implements encoding/json.Unmarshaler.

View File

@ -2,6 +2,7 @@ package pgproto3
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"io" "io"
) )
@ -21,6 +22,7 @@ type Backend struct {
describe Describe describe Describe
execute Execute execute Execute
flush Flush flush Flush
functionCall FunctionCall
gssEncRequest GSSEncRequest gssEncRequest GSSEncRequest
parse Parse parse Parse
query Query query Query
@ -47,7 +49,12 @@ func NewBackend(cr ChunkReader, w io.Writer) *Backend {
// Send sends a message to the frontend. // Send sends a message to the frontend.
func (b *Backend) Send(msg BackendMessage) error { func (b *Backend) Send(msg BackendMessage) error {
_, err := b.w.Write(msg.Encode(nil)) buf, err := msg.Encode(nil)
if err != nil {
return err
}
_, err = b.w.Write(buf)
return err return err
} }
@ -113,6 +120,9 @@ func (b *Backend) Receive() (FrontendMessage, error) {
b.msgType = header[0] b.msgType = header[0]
b.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4 b.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
b.partialMsg = true b.partialMsg = true
if b.bodyLen < 0 {
return nil, errors.New("invalid message with negative body length received")
}
} }
var msg FrontendMessage var msg FrontendMessage
@ -125,6 +135,8 @@ func (b *Backend) Receive() (FrontendMessage, error) {
msg = &b.describe msg = &b.describe
case 'E': case 'E':
msg = &b.execute msg = &b.execute
case 'F':
msg = &b.functionCall
case 'f': case 'f':
msg = &b.copyFail msg = &b.copyFail
case 'd': case 'd':
@ -143,6 +155,8 @@ func (b *Backend) Receive() (FrontendMessage, error) {
msg = &SASLResponse{} msg = &SASLResponse{}
case AuthTypeSASLFinal: case AuthTypeSASLFinal:
msg = &SASLResponse{} msg = &SASLResponse{}
case AuthTypeGSS, AuthTypeGSSCont:
msg = &GSSResponse{}
case AuthTypeCleartextPassword, AuthTypeMD5Password: case AuthTypeCleartextPassword, AuthTypeMD5Password:
fallthrough fallthrough
default: default:
@ -175,11 +189,11 @@ func (b *Backend) Receive() (FrontendMessage, error) {
// contextual identification of FrontendMessages. For example, in the // contextual identification of FrontendMessages. For example, in the
// PG message flow documentation for PasswordMessage: // PG message flow documentation for PasswordMessage:
// //
// Byte1('p') // Byte1('p')
// //
// Identifies the message as a password response. Note that this is also used for // Identifies the message as a password response. Note that this is also used for
// GSSAPI, SSPI and SASL response messages. The exact message type can be deduced from // GSSAPI, SSPI and SASL response messages. The exact message type can be deduced from
// the context. // the context.
// //
// Since the Frontend does not know about the state of a backend, it is important // Since the Frontend does not know about the state of a backend, it is important
// to call SetAuthType() after an authentication request is received by the Frontend. // to call SetAuthType() after an authentication request is received by the Frontend.

View File

@ -29,12 +29,11 @@ func (dst *BackendKeyData) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *BackendKeyData) Encode(dst []byte) []byte { func (src *BackendKeyData) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'K') dst, sp := beginMessage(dst, 'K')
dst = pgio.AppendUint32(dst, 12)
dst = pgio.AppendUint32(dst, src.ProcessID) dst = pgio.AppendUint32(dst, src.ProcessID)
dst = pgio.AppendUint32(dst, src.SecretKey) dst = pgio.AppendUint32(dst, src.SecretKey)
return dst return finishMessage(dst, sp)
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -5,7 +5,9 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -108,21 +110,25 @@ func (dst *Bind) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Bind) Encode(dst []byte) []byte { func (src *Bind) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'B') dst, sp := beginMessage(dst, 'B')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.DestinationPortal...) dst = append(dst, src.DestinationPortal...)
dst = append(dst, 0) dst = append(dst, 0)
dst = append(dst, src.PreparedStatement...) dst = append(dst, src.PreparedStatement...)
dst = append(dst, 0) dst = append(dst, 0)
if len(src.ParameterFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many parameter format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes))) dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes)))
for _, fc := range src.ParameterFormatCodes { for _, fc := range src.ParameterFormatCodes {
dst = pgio.AppendInt16(dst, fc) dst = pgio.AppendInt16(dst, fc)
} }
if len(src.Parameters) > math.MaxUint16 {
return nil, errors.New("too many parameters")
}
dst = pgio.AppendUint16(dst, uint16(len(src.Parameters))) dst = pgio.AppendUint16(dst, uint16(len(src.Parameters)))
for _, p := range src.Parameters { for _, p := range src.Parameters {
if p == nil { if p == nil {
@ -134,14 +140,15 @@ func (src *Bind) Encode(dst []byte) []byte {
dst = append(dst, p...) dst = append(dst, p...)
} }
if len(src.ResultFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many result format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ResultFormatCodes))) dst = pgio.AppendUint16(dst, uint16(len(src.ResultFormatCodes)))
for _, fc := range src.ResultFormatCodes { for _, fc := range src.ResultFormatCodes {
dst = pgio.AppendInt16(dst, fc) dst = pgio.AppendInt16(dst, fc)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *BindComplete) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *BindComplete) Encode(dst []byte) []byte { func (src *BindComplete) Encode(dst []byte) ([]byte, error) {
return append(dst, '2', 0, 0, 0, 4) return append(dst, '2', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -36,12 +36,12 @@ func (dst *CancelRequest) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 4 byte message length. // Encode encodes src into dst. dst will include the 4 byte message length.
func (src *CancelRequest) Encode(dst []byte) []byte { func (src *CancelRequest) Encode(dst []byte) ([]byte, error) {
dst = pgio.AppendInt32(dst, 16) dst = pgio.AppendInt32(dst, 16)
dst = pgio.AppendInt32(dst, cancelRequestCode) dst = pgio.AppendInt32(dst, cancelRequestCode)
dst = pgio.AppendUint32(dst, src.ProcessID) dst = pgio.AppendUint32(dst, src.ProcessID)
dst = pgio.AppendUint32(dst, src.SecretKey) dst = pgio.AppendUint32(dst, src.SecretKey)
return dst return dst, nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/jackc/pgio"
) )
type Close struct { type Close struct {
@ -37,18 +35,12 @@ func (dst *Close) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Close) Encode(dst []byte) []byte { func (src *Close) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'C') dst, sp := beginMessage(dst, 'C')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.ObjectType) dst = append(dst, src.ObjectType)
dst = append(dst, src.Name...) dst = append(dst, src.Name...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *CloseComplete) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CloseComplete) Encode(dst []byte) []byte { func (src *CloseComplete) Encode(dst []byte) ([]byte, error) {
return append(dst, '3', 0, 0, 0, 4) return append(dst, '3', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type CommandComplete struct { type CommandComplete struct {
@ -28,17 +26,11 @@ func (dst *CommandComplete) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CommandComplete) Encode(dst []byte) []byte { func (src *CommandComplete) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'C') dst, sp := beginMessage(dst, 'C')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.CommandTag...) dst = append(dst, src.CommandTag...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -44,19 +45,18 @@ func (dst *CopyBothResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyBothResponse) Encode(dst []byte) []byte { func (src *CopyBothResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'W') dst, sp := beginMessage(dst, 'W')
sp := len(dst) dst = append(dst, src.OverallFormat)
dst = pgio.AppendInt32(dst, -1) if len(src.ColumnFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many column format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
for _, fc := range src.ColumnFormatCodes { for _, fc := range src.ColumnFormatCodes {
dst = pgio.AppendUint16(dst, fc) dst = pgio.AppendUint16(dst, fc)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type CopyData struct { type CopyData struct {
@ -25,11 +23,10 @@ func (dst *CopyData) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyData) Encode(dst []byte) []byte { func (src *CopyData) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'd') dst, sp := beginMessage(dst, 'd')
dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))
dst = append(dst, src.Data...) dst = append(dst, src.Data...)
return dst return finishMessage(dst, sp)
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -24,8 +24,8 @@ func (dst *CopyDone) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyDone) Encode(dst []byte) []byte { func (src *CopyDone) Encode(dst []byte) ([]byte, error) {
return append(dst, 'c', 0, 0, 0, 4) return append(dst, 'c', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type CopyFail struct { type CopyFail struct {
@ -28,17 +26,11 @@ func (dst *CopyFail) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyFail) Encode(dst []byte) []byte { func (src *CopyFail) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'f') dst, sp := beginMessage(dst, 'f')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.Message...) dst = append(dst, src.Message...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -44,20 +45,19 @@ func (dst *CopyInResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyInResponse) Encode(dst []byte) []byte { func (src *CopyInResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'G') dst, sp := beginMessage(dst, 'G')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.OverallFormat) dst = append(dst, src.OverallFormat)
if len(src.ColumnFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many column format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
for _, fc := range src.ColumnFormatCodes { for _, fc := range src.ColumnFormatCodes {
dst = pgio.AppendUint16(dst, fc) dst = pgio.AppendUint16(dst, fc)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors" "errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -43,21 +44,20 @@ func (dst *CopyOutResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *CopyOutResponse) Encode(dst []byte) []byte { func (src *CopyOutResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'H') dst, sp := beginMessage(dst, 'H')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.OverallFormat) dst = append(dst, src.OverallFormat)
if len(src.ColumnFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many column format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes))) dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
for _, fc := range src.ColumnFormatCodes { for _, fc := range src.ColumnFormatCodes {
dst = pgio.AppendUint16(dst, fc) dst = pgio.AppendUint16(dst, fc)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,6 +4,8 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -63,11 +65,12 @@ func (dst *DataRow) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *DataRow) Encode(dst []byte) []byte { func (src *DataRow) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'D') dst, sp := beginMessage(dst, 'D')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
if len(src.Values) > math.MaxUint16 {
return nil, errors.New("too many values")
}
dst = pgio.AppendUint16(dst, uint16(len(src.Values))) dst = pgio.AppendUint16(dst, uint16(len(src.Values)))
for _, v := range src.Values { for _, v := range src.Values {
if v == nil { if v == nil {
@ -79,9 +82,7 @@ func (src *DataRow) Encode(dst []byte) []byte {
dst = append(dst, v...) dst = append(dst, v...)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,8 +4,6 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"github.com/jackc/pgio"
) )
type Describe struct { type Describe struct {
@ -37,18 +35,12 @@ func (dst *Describe) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Describe) Encode(dst []byte) []byte { func (src *Describe) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'D') dst, sp := beginMessage(dst, 'D')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.ObjectType) dst = append(dst, src.ObjectType)
dst = append(dst, src.Name...) dst = append(dst, src.Name...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *EmptyQueryResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *EmptyQueryResponse) Encode(dst []byte) []byte { func (src *EmptyQueryResponse) Encode(dst []byte) ([]byte, error) {
return append(dst, 'I', 0, 0, 0, 4) return append(dst, 'I', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -2,7 +2,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/binary"
"encoding/json" "encoding/json"
"strconv" "strconv"
) )
@ -111,120 +110,113 @@ func (dst *ErrorResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *ErrorResponse) Encode(dst []byte) []byte { func (src *ErrorResponse) Encode(dst []byte) ([]byte, error) {
return append(dst, src.marshalBinary('E')...) dst, sp := beginMessage(dst, 'E')
dst = src.appendFields(dst)
return finishMessage(dst, sp)
} }
func (src *ErrorResponse) marshalBinary(typeByte byte) []byte { func (src *ErrorResponse) appendFields(dst []byte) []byte {
var bigEndian BigEndianBuf
buf := &bytes.Buffer{}
buf.WriteByte(typeByte)
buf.Write(bigEndian.Uint32(0))
if src.Severity != "" { if src.Severity != "" {
buf.WriteByte('S') dst = append(dst, 'S')
buf.WriteString(src.Severity) dst = append(dst, src.Severity...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.SeverityUnlocalized != "" { if src.SeverityUnlocalized != "" {
buf.WriteByte('V') dst = append(dst, 'V')
buf.WriteString(src.SeverityUnlocalized) dst = append(dst, src.SeverityUnlocalized...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Code != "" { if src.Code != "" {
buf.WriteByte('C') dst = append(dst, 'C')
buf.WriteString(src.Code) dst = append(dst, src.Code...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Message != "" { if src.Message != "" {
buf.WriteByte('M') dst = append(dst, 'M')
buf.WriteString(src.Message) dst = append(dst, src.Message...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Detail != "" { if src.Detail != "" {
buf.WriteByte('D') dst = append(dst, 'D')
buf.WriteString(src.Detail) dst = append(dst, src.Detail...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Hint != "" { if src.Hint != "" {
buf.WriteByte('H') dst = append(dst, 'H')
buf.WriteString(src.Hint) dst = append(dst, src.Hint...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Position != 0 { if src.Position != 0 {
buf.WriteByte('P') dst = append(dst, 'P')
buf.WriteString(strconv.Itoa(int(src.Position))) dst = append(dst, strconv.Itoa(int(src.Position))...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.InternalPosition != 0 { if src.InternalPosition != 0 {
buf.WriteByte('p') dst = append(dst, 'p')
buf.WriteString(strconv.Itoa(int(src.InternalPosition))) dst = append(dst, strconv.Itoa(int(src.InternalPosition))...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.InternalQuery != "" { if src.InternalQuery != "" {
buf.WriteByte('q') dst = append(dst, 'q')
buf.WriteString(src.InternalQuery) dst = append(dst, src.InternalQuery...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Where != "" { if src.Where != "" {
buf.WriteByte('W') dst = append(dst, 'W')
buf.WriteString(src.Where) dst = append(dst, src.Where...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.SchemaName != "" { if src.SchemaName != "" {
buf.WriteByte('s') dst = append(dst, 's')
buf.WriteString(src.SchemaName) dst = append(dst, src.SchemaName...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.TableName != "" { if src.TableName != "" {
buf.WriteByte('t') dst = append(dst, 't')
buf.WriteString(src.TableName) dst = append(dst, src.TableName...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.ColumnName != "" { if src.ColumnName != "" {
buf.WriteByte('c') dst = append(dst, 'c')
buf.WriteString(src.ColumnName) dst = append(dst, src.ColumnName...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.DataTypeName != "" { if src.DataTypeName != "" {
buf.WriteByte('d') dst = append(dst, 'd')
buf.WriteString(src.DataTypeName) dst = append(dst, src.DataTypeName...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.ConstraintName != "" { if src.ConstraintName != "" {
buf.WriteByte('n') dst = append(dst, 'n')
buf.WriteString(src.ConstraintName) dst = append(dst, src.ConstraintName...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.File != "" { if src.File != "" {
buf.WriteByte('F') dst = append(dst, 'F')
buf.WriteString(src.File) dst = append(dst, src.File...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Line != 0 { if src.Line != 0 {
buf.WriteByte('L') dst = append(dst, 'L')
buf.WriteString(strconv.Itoa(int(src.Line))) dst = append(dst, strconv.Itoa(int(src.Line))...)
buf.WriteByte(0) dst = append(dst, 0)
} }
if src.Routine != "" { if src.Routine != "" {
buf.WriteByte('R') dst = append(dst, 'R')
buf.WriteString(src.Routine) dst = append(dst, src.Routine...)
buf.WriteByte(0) dst = append(dst, 0)
} }
for k, v := range src.UnknownFields { for k, v := range src.UnknownFields {
buf.WriteByte(k) dst = append(dst, k)
buf.WriteByte(0) dst = append(dst, v...)
buf.WriteString(v) dst = append(dst, 0)
buf.WriteByte(0)
} }
buf.WriteByte(0) dst = append(dst, 0)
binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1)) return dst
return buf.Bytes()
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -36,19 +36,12 @@ func (dst *Execute) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Execute) Encode(dst []byte) []byte { func (src *Execute) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'E') dst, sp := beginMessage(dst, 'E')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.Portal...) dst = append(dst, src.Portal...)
dst = append(dst, 0) dst = append(dst, 0)
dst = pgio.AppendUint32(dst, src.MaxRows) dst = pgio.AppendUint32(dst, src.MaxRows)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *Flush) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Flush) Encode(dst []byte) []byte { func (src *Flush) Encode(dst []byte) ([]byte, error) {
return append(dst, 'H', 0, 0, 0, 4) return append(dst, 'H', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -16,6 +16,8 @@ type Frontend struct {
authenticationOk AuthenticationOk authenticationOk AuthenticationOk
authenticationCleartextPassword AuthenticationCleartextPassword authenticationCleartextPassword AuthenticationCleartextPassword
authenticationMD5Password AuthenticationMD5Password authenticationMD5Password AuthenticationMD5Password
authenticationGSS AuthenticationGSS
authenticationGSSContinue AuthenticationGSSContinue
authenticationSASL AuthenticationSASL authenticationSASL AuthenticationSASL
authenticationSASLContinue AuthenticationSASLContinue authenticationSASLContinue AuthenticationSASLContinue
authenticationSASLFinal AuthenticationSASLFinal authenticationSASLFinal AuthenticationSASLFinal
@ -55,7 +57,11 @@ func NewFrontend(cr ChunkReader, w io.Writer) *Frontend {
// Send sends a message to the backend. // Send sends a message to the backend.
func (f *Frontend) Send(msg FrontendMessage) error { func (f *Frontend) Send(msg FrontendMessage) error {
_, err := f.w.Write(msg.Encode(nil)) buf, err := msg.Encode(nil)
if err != nil {
return err
}
_, err = f.w.Write(buf)
return err return err
} }
@ -77,6 +83,9 @@ func (f *Frontend) Receive() (BackendMessage, error) {
f.msgType = header[0] f.msgType = header[0]
f.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4 f.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
f.partialMsg = true f.partialMsg = true
if f.bodyLen < 0 {
return nil, errors.New("invalid message with negative body length received")
}
} }
msgBody, err := f.cr.Next(f.bodyLen) msgBody, err := f.cr.Next(f.bodyLen)
@ -178,9 +187,9 @@ func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, er
case AuthTypeSCMCreds: case AuthTypeSCMCreds:
return nil, errors.New("AuthTypeSCMCreds is unimplemented") return nil, errors.New("AuthTypeSCMCreds is unimplemented")
case AuthTypeGSS: case AuthTypeGSS:
return nil, errors.New("AuthTypeGSS is unimplemented") return &f.authenticationGSS, nil
case AuthTypeGSSCont: case AuthTypeGSSCont:
return nil, errors.New("AuthTypeGSSCont is unimplemented") return &f.authenticationGSSContinue, nil
case AuthTypeSSPI: case AuthTypeSSPI:
return nil, errors.New("AuthTypeSSPI is unimplemented") return nil, errors.New("AuthTypeSSPI is unimplemented")
case AuthTypeSASL: case AuthTypeSASL:

View File

@ -0,0 +1,102 @@
package pgproto3
import (
"encoding/binary"
"errors"
"math"
"github.com/jackc/pgio"
)
type FunctionCall struct {
Function uint32
ArgFormatCodes []uint16
Arguments [][]byte
ResultFormatCode uint16
}
// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (*FunctionCall) Frontend() {}
// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func (dst *FunctionCall) Decode(src []byte) error {
*dst = FunctionCall{}
rp := 0
// Specifies the object ID of the function to call.
dst.Function = binary.BigEndian.Uint32(src[rp:])
rp += 4
// The number of argument format codes that follow (denoted C below).
// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
// or one, in which case the specified format code is applied to all arguments;
// or it can equal the actual number of arguments.
nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
rp += 2
argumentCodes := make([]uint16, nArgumentCodes)
for i := 0; i < nArgumentCodes; i++ {
// The argument format codes. Each must presently be zero (text) or one (binary).
ac := binary.BigEndian.Uint16(src[rp:])
if ac != 0 && ac != 1 {
return &invalidMessageFormatErr{messageType: "FunctionCall"}
}
argumentCodes[i] = ac
rp += 2
}
dst.ArgFormatCodes = argumentCodes
// Specifies the number of arguments being supplied to the function.
nArguments := int(binary.BigEndian.Uint16(src[rp:]))
rp += 2
arguments := make([][]byte, nArguments)
for i := 0; i < nArguments; i++ {
// The length of the argument value, in bytes (this count does not include itself). Can be zero.
// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
argumentLength := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if argumentLength == -1 {
arguments[i] = nil
} else {
// The value of the argument, in the format indicated by the associated format code. n is the above length.
argumentValue := src[rp : rp+argumentLength]
rp += argumentLength
arguments[i] = argumentValue
}
}
dst.Arguments = arguments
// The format code for the function result. Must presently be zero (text) or one (binary).
resultFormatCode := binary.BigEndian.Uint16(src[rp:])
if resultFormatCode != 0 && resultFormatCode != 1 {
return &invalidMessageFormatErr{messageType: "FunctionCall"}
}
dst.ResultFormatCode = resultFormatCode
return nil
}
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *FunctionCall) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'F')
dst = pgio.AppendUint32(dst, src.Function)
if len(src.ArgFormatCodes) > math.MaxUint16 {
return nil, errors.New("too many arg format codes")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
for _, argFormatCode := range src.ArgFormatCodes {
dst = pgio.AppendUint16(dst, argFormatCode)
}
if len(src.Arguments) > math.MaxUint16 {
return nil, errors.New("too many arguments")
}
dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
for _, argument := range src.Arguments {
if argument == nil {
dst = pgio.AppendInt32(dst, -1)
} else {
dst = pgio.AppendInt32(dst, int32(len(argument)))
dst = append(dst, argument...)
}
}
dst = pgio.AppendUint16(dst, src.ResultFormatCode)
return finishMessage(dst, sp)
}

View File

@ -39,10 +39,8 @@ func (dst *FunctionCallResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *FunctionCallResponse) Encode(dst []byte) []byte { func (src *FunctionCallResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'V') dst, sp := beginMessage(dst, 'V')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
if src.Result == nil { if src.Result == nil {
dst = pgio.AppendInt32(dst, -1) dst = pgio.AppendInt32(dst, -1)
@ -51,9 +49,7 @@ func (src *FunctionCallResponse) Encode(dst []byte) []byte {
dst = append(dst, src.Result...) dst = append(dst, src.Result...)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -31,10 +31,10 @@ func (dst *GSSEncRequest) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 4 byte message length. // Encode encodes src into dst. dst will include the 4 byte message length.
func (src *GSSEncRequest) Encode(dst []byte) []byte { func (src *GSSEncRequest) Encode(dst []byte) ([]byte, error) {
dst = pgio.AppendInt32(dst, 8) dst = pgio.AppendInt32(dst, 8)
dst = pgio.AppendInt32(dst, gssEncReqNumber) dst = pgio.AppendInt32(dst, gssEncReqNumber)
return dst return dst, nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -0,0 +1,46 @@
package pgproto3
import (
"encoding/json"
)
type GSSResponse struct {
Data []byte
}
// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (g *GSSResponse) Frontend() {}
func (g *GSSResponse) Decode(data []byte) error {
g.Data = data
return nil
}
func (g *GSSResponse) Encode(dst []byte) ([]byte, error) {
dst, sp := beginMessage(dst, 'p')
dst = append(dst, g.Data...)
return finishMessage(dst, sp)
}
// MarshalJSON implements encoding/json.Marshaler.
func (g *GSSResponse) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Type string
Data []byte
}{
Type: "GSSResponse",
Data: g.Data,
})
}
// UnmarshalJSON implements encoding/json.Unmarshaler.
func (g *GSSResponse) UnmarshalJSON(data []byte) error {
var msg struct {
Data []byte
}
if err := json.Unmarshal(data, &msg); err != nil {
return err
}
g.Data = msg.Data
return nil
}

View File

@ -20,8 +20,8 @@ func (dst *NoData) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *NoData) Encode(dst []byte) []byte { func (src *NoData) Encode(dst []byte) ([]byte, error) {
return append(dst, 'n', 0, 0, 0, 4) return append(dst, 'n', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -12,6 +12,8 @@ func (dst *NoticeResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *NoticeResponse) Encode(dst []byte) []byte { func (src *NoticeResponse) Encode(dst []byte) ([]byte, error) {
return append(dst, (*ErrorResponse)(src).marshalBinary('N')...) dst, sp := beginMessage(dst, 'N')
dst = (*ErrorResponse)(src).appendFields(dst)
return finishMessage(dst, sp)
} }

View File

@ -41,20 +41,14 @@ func (dst *NotificationResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *NotificationResponse) Encode(dst []byte) []byte { func (src *NotificationResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'A') dst, sp := beginMessage(dst, 'A')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = pgio.AppendUint32(dst, src.PID) dst = pgio.AppendUint32(dst, src.PID)
dst = append(dst, src.Channel...) dst = append(dst, src.Channel...)
dst = append(dst, 0) dst = append(dst, 0)
dst = append(dst, src.Payload...) dst = append(dst, src.Payload...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -39,19 +41,18 @@ func (dst *ParameterDescription) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *ParameterDescription) Encode(dst []byte) []byte { func (src *ParameterDescription) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 't') dst, sp := beginMessage(dst, 't')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
if len(src.ParameterOIDs) > math.MaxUint16 {
return nil, errors.New("too many parameter oids")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs))) dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
for _, oid := range src.ParameterOIDs { for _, oid := range src.ParameterOIDs {
dst = pgio.AppendUint32(dst, oid) dst = pgio.AppendUint32(dst, oid)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type ParameterStatus struct { type ParameterStatus struct {
@ -37,19 +35,13 @@ func (dst *ParameterStatus) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *ParameterStatus) Encode(dst []byte) []byte { func (src *ParameterStatus) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'S') dst, sp := beginMessage(dst, 'S')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.Name...) dst = append(dst, src.Name...)
dst = append(dst, 0) dst = append(dst, 0)
dst = append(dst, src.Value...) dst = append(dst, src.Value...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -52,24 +54,23 @@ func (dst *Parse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Parse) Encode(dst []byte) []byte { func (src *Parse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'P') dst, sp := beginMessage(dst, 'P')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, src.Name...) dst = append(dst, src.Name...)
dst = append(dst, 0) dst = append(dst, 0)
dst = append(dst, src.Query...) dst = append(dst, src.Query...)
dst = append(dst, 0) dst = append(dst, 0)
if len(src.ParameterOIDs) > math.MaxUint16 {
return nil, errors.New("too many parameter oids")
}
dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs))) dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
for _, oid := range src.ParameterOIDs { for _, oid := range src.ParameterOIDs {
dst = pgio.AppendUint32(dst, oid) dst = pgio.AppendUint32(dst, oid)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *ParseComplete) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *ParseComplete) Encode(dst []byte) []byte { func (src *ParseComplete) Encode(dst []byte) ([]byte, error) {
return append(dst, '1', 0, 0, 0, 4) return append(dst, '1', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type PasswordMessage struct { type PasswordMessage struct {
@ -32,14 +30,11 @@ func (dst *PasswordMessage) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *PasswordMessage) Encode(dst []byte) []byte { func (src *PasswordMessage) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'p') dst, sp := beginMessage(dst, 'p')
dst = pgio.AppendInt32(dst, int32(4+len(src.Password)+1))
dst = append(dst, src.Password...) dst = append(dst, src.Password...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,8 +4,14 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"github.com/jackc/pgio"
) )
// maxMessageBodyLen is the maximum length of a message body in bytes. See PG_LARGE_MESSAGE_LIMIT in the PostgreSQL
// source. It is defined as (MaxAllocSize - 1). MaxAllocSize is defined as 0x3fffffff.
const maxMessageBodyLen = (0x3fffffff - 1)
// Message is the interface implemented by an object that can decode and encode // Message is the interface implemented by an object that can decode and encode
// a particular PostgreSQL message. // a particular PostgreSQL message.
type Message interface { type Message interface {
@ -14,7 +20,7 @@ type Message interface {
Decode(data []byte) error Decode(data []byte) error
// Encode appends itself to dst and returns the new buffer. // Encode appends itself to dst and returns the new buffer.
Encode(dst []byte) []byte Encode(dst []byte) ([]byte, error)
} }
type FrontendMessage interface { type FrontendMessage interface {
@ -63,3 +69,23 @@ func getValueFromJSON(v map[string]string) ([]byte, error) {
} }
return nil, errors.New("unknown protocol representation") return nil, errors.New("unknown protocol representation")
} }
// beginMessage begines a new message of type t. It appends the message type and a placeholder for the message length to
// dst. It returns the new buffer and the position of the message length placeholder.
func beginMessage(dst []byte, t byte) ([]byte, int) {
dst = append(dst, t)
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
return dst, sp
}
// finishMessage finishes a message that was started with beginMessage. It computes the message length and writes it to
// dst[sp]. If the message length is too large it returns an error. Otherwise it returns the final message buffer.
func finishMessage(dst []byte, sp int) ([]byte, error) {
messageBodyLen := len(dst[sp:])
if messageBodyLen > maxMessageBodyLen {
return nil, errors.New("message body too large")
}
pgio.SetInt32(dst[sp:], int32(messageBodyLen))
return dst, nil
}

View File

@ -20,8 +20,8 @@ func (dst *PortalSuspended) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *PortalSuspended) Encode(dst []byte) []byte { func (src *PortalSuspended) Encode(dst []byte) ([]byte, error) {
return append(dst, 's', 0, 0, 0, 4) return append(dst, 's', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -3,8 +3,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type Query struct { type Query struct {
@ -28,14 +26,11 @@ func (dst *Query) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Query) Encode(dst []byte) []byte { func (src *Query) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'Q') dst, sp := beginMessage(dst, 'Q')
dst = pgio.AppendInt32(dst, int32(4+len(src.String)+1))
dst = append(dst, src.String...) dst = append(dst, src.String...)
dst = append(dst, 0) dst = append(dst, 0)
return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -25,8 +25,8 @@ func (dst *ReadyForQuery) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *ReadyForQuery) Encode(dst []byte) []byte { func (src *ReadyForQuery) Encode(dst []byte) ([]byte, error) {
return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus) return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"errors"
"math"
"github.com/jackc/pgio" "github.com/jackc/pgio"
) )
@ -99,11 +101,12 @@ func (dst *RowDescription) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *RowDescription) Encode(dst []byte) []byte { func (src *RowDescription) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'T') dst, sp := beginMessage(dst, 'T')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
if len(src.Fields) > math.MaxUint16 {
return nil, errors.New("too many fields")
}
dst = pgio.AppendUint16(dst, uint16(len(src.Fields))) dst = pgio.AppendUint16(dst, uint16(len(src.Fields)))
for _, fd := range src.Fields { for _, fd := range src.Fields {
dst = append(dst, fd.Name...) dst = append(dst, fd.Name...)
@ -117,9 +120,7 @@ func (src *RowDescription) Encode(dst []byte) []byte {
dst = pgio.AppendInt16(dst, fd.Format) dst = pgio.AppendInt16(dst, fd.Format)
} }
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -2,7 +2,6 @@ package pgproto3
import ( import (
"bytes" "bytes"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
@ -39,10 +38,8 @@ func (dst *SASLInitialResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *SASLInitialResponse) Encode(dst []byte) []byte { func (src *SASLInitialResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'p') dst, sp := beginMessage(dst, 'p')
sp := len(dst)
dst = pgio.AppendInt32(dst, -1)
dst = append(dst, []byte(src.AuthMechanism)...) dst = append(dst, []byte(src.AuthMechanism)...)
dst = append(dst, 0) dst = append(dst, 0)
@ -50,9 +47,7 @@ func (src *SASLInitialResponse) Encode(dst []byte) []byte {
dst = pgio.AppendInt32(dst, int32(len(src.Data))) dst = pgio.AppendInt32(dst, int32(len(src.Data)))
dst = append(dst, src.Data...) dst = append(dst, src.Data...)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.
@ -64,7 +59,7 @@ func (src SASLInitialResponse) MarshalJSON() ([]byte, error) {
}{ }{
Type: "SASLInitialResponse", Type: "SASLInitialResponse",
AuthMechanism: src.AuthMechanism, AuthMechanism: src.AuthMechanism,
Data: hex.EncodeToString(src.Data), Data: string(src.Data),
}) })
} }
@ -83,12 +78,6 @@ func (dst *SASLInitialResponse) UnmarshalJSON(data []byte) error {
return err return err
} }
dst.AuthMechanism = msg.AuthMechanism dst.AuthMechanism = msg.AuthMechanism
if msg.Data != "" { dst.Data = []byte(msg.Data)
decoded, err := hex.DecodeString(msg.Data)
if err != nil {
return err
}
dst.Data = decoded
}
return nil return nil
} }

View File

@ -1,10 +1,7 @@
package pgproto3 package pgproto3
import ( import (
"encoding/hex"
"encoding/json" "encoding/json"
"github.com/jackc/pgio"
) )
type SASLResponse struct { type SASLResponse struct {
@ -22,13 +19,10 @@ func (dst *SASLResponse) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *SASLResponse) Encode(dst []byte) []byte { func (src *SASLResponse) Encode(dst []byte) ([]byte, error) {
dst = append(dst, 'p') dst, sp := beginMessage(dst, 'p')
dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))
dst = append(dst, src.Data...) dst = append(dst, src.Data...)
return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.
@ -38,7 +32,7 @@ func (src SASLResponse) MarshalJSON() ([]byte, error) {
Data string Data string
}{ }{
Type: "SASLResponse", Type: "SASLResponse",
Data: hex.EncodeToString(src.Data), Data: string(src.Data),
}) })
} }
@ -50,12 +44,6 @@ func (dst *SASLResponse) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &msg); err != nil { if err := json.Unmarshal(data, &msg); err != nil {
return err return err
} }
if msg.Data != "" { dst.Data = []byte(msg.Data)
decoded, err := hex.DecodeString(msg.Data)
if err != nil {
return err
}
dst.Data = decoded
}
return nil return nil
} }

View File

@ -31,10 +31,10 @@ func (dst *SSLRequest) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 4 byte message length. // Encode encodes src into dst. dst will include the 4 byte message length.
func (src *SSLRequest) Encode(dst []byte) []byte { func (src *SSLRequest) Encode(dst []byte) ([]byte, error) {
dst = pgio.AppendInt32(dst, 8) dst = pgio.AppendInt32(dst, 8)
dst = pgio.AppendInt32(dst, sslRequestNumber) dst = pgio.AppendInt32(dst, sslRequestNumber)
return dst return dst, nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -64,7 +64,7 @@ func (dst *StartupMessage) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *StartupMessage) Encode(dst []byte) []byte { func (src *StartupMessage) Encode(dst []byte) ([]byte, error) {
sp := len(dst) sp := len(dst)
dst = pgio.AppendInt32(dst, -1) dst = pgio.AppendInt32(dst, -1)
@ -77,9 +77,7 @@ func (src *StartupMessage) Encode(dst []byte) []byte {
} }
dst = append(dst, 0) dst = append(dst, 0)
pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) return finishMessage(dst, sp)
return dst
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *Sync) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Sync) Encode(dst []byte) []byte { func (src *Sync) Encode(dst []byte) ([]byte, error) {
return append(dst, 'S', 0, 0, 0, 4) return append(dst, 'S', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -20,8 +20,8 @@ func (dst *Terminate) Decode(src []byte) error {
} }
// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *Terminate) Encode(dst []byte) []byte { func (src *Terminate) Encode(dst []byte) ([]byte, error) {
return append(dst, 'X', 0, 0, 0, 4) return append(dst, 'X', 0, 0, 0, 4), nil
} }
// MarshalJSON implements encoding/json.Marshaler. // MarshalJSON implements encoding/json.Marshaler.

View File

@ -1,34 +0,0 @@
# source: https://github.com/jackc/pgx/blob/master/.travis.yml
language: go
go:
- 1.14.x
- 1.13.x
- tip
# Derived from https://github.com/lib/pq/blob/master/.travis.yml
before_install:
- ./travis/before_install.bash
env:
global:
- GO111MODULE=on
- PGX_TEST_DATABASE=postgres://pgx_md5:secret@127.0.0.1/pgx_test
matrix:
- PGVERSION=12
- PGVERSION=11
- PGVERSION=10
- PGVERSION=9.6
- PGVERSION=9.5
before_script:
- ./travis/before_script.bash
script:
- ./travis/script.bash
matrix:
allow_failures:
- go: tip

View File

@ -1,3 +1,68 @@
# 1.14.0 (February 11, 2023)
* Fix: BC timestamp text format support (jozeflami)
* Add Scanner and Valuer interfaces to CIDR (Yurii Popivniak)
* Fix crash when nilifying pointer to sql.Scanner
# 1.13.0 (December 1, 2022)
* Fix: Reset jsonb before unmarshal (Tomas Odinas)
* Fix: return correct zero value when UUID conversion fails (ndrpnt)
* Fix: EncodeText for Lseg includes [ and ]
* Support sql Value and Scan for custom date type (Hubert Krauze)
* Support Ltree binary encoding (AmineChikhaoui)
* Fix: dates with "BC" (jozeflami)
# 1.12.0 (August 6, 2022)
* Add JSONArray (Jakob Ackermann)
* Support Inet from fmt.Stringer and encoding.TextMarshaler (Ville Skyttä)
* Support UUID from fmt.Stringer interface (Lasse Hyldahl Jensen)
* Fix: shopspring-numeric extension does not panic on NaN
* Numeric can be assigned to string
* Fix: Do not send IPv4 networks as IPv4-mapped IPv6 (William Storey)
* Fix: PlanScan for interface{}(nil) (James Hartig)
* Fix: *sql.Scanner for NULL handling (James Hartig)
* Timestamp[tz].Set() supports string (Harmen)
* Fix: Hstore AssignTo with map of *string (Diego Becciolini)
# 1.11.0 (April 21, 2022)
* Add multirange for numeric, int4, and int8 (Vu)
* JSONBArray now supports json.RawMessage (Jens Emil Schulz Østergaard)
* Add RecordArray (WGH)
* Add UnmarshalJSON to pgtype.Int2
* Hstore.Set accepts map[string]Text
# 1.10.0 (February 7, 2022)
* Normalize UTC timestamps to comply with stdlib (Torkel Rogstad)
* Assign Numeric to *big.Rat (Oleg Lomaka)
* Fix typo in float8 error message (Pinank Solanki)
* Scan type aliases for floating point types (Collin Forsyth)
# 1.9.1 (November 28, 2021)
* Fix: binary timestamp is assumed to be in UTC (restored behavior changed in v1.9.0)
# 1.9.0 (November 20, 2021)
* Fix binary hstore null decoding
* Add shopspring/decimal.NullDecimal support to integration (Eli Treuherz)
* Inet.Set supports bare IP address (Carl Dunham)
* Add zeronull.Float8
* Fix NULL being lost when scanning unknown OID into sql.Scanner
* Fix BPChar.AssignTo **rune
* Add support for fmt.Stringer and driver.Valuer in String fields encoding (Jan Dubsky)
* Fix really big timestamp(tz)s binary format parsing (e.g. year 294276) (Jim Tsao)
* Support `map[string]*string` as hstore (Adrian Sieger)
* Fix parsing text array with negative bounds
* Add infinity support for numeric (Jim Tsao)
# 1.8.1 (July 24, 2021)
* Cleaned up Go module dependency chain
# 1.8.0 (July 10, 2021) # 1.8.0 (July 10, 2021)
* Maintain host bits for inet types (Cameron Daniel) * Maintain host bits for inet types (Cameron Daniel)

View File

@ -1,6 +1,12 @@
[![](https://godoc.org/github.com/jackc/pgtype?status.svg)](https://godoc.org/github.com/jackc/pgtype) [![](https://godoc.org/github.com/jackc/pgtype?status.svg)](https://godoc.org/github.com/jackc/pgtype)
![CI](https://github.com/jackc/pgtype/workflows/CI/badge.svg) ![CI](https://github.com/jackc/pgtype/workflows/CI/badge.svg)
---
This version is used with pgx `v4`. In pgx `v5` it is part of the https://github.com/jackc/pgx repository.
---
# pgtype # pgtype
pgtype implements Go types for over 70 PostgreSQL types. pgtype is the type system underlying the pgtype implements Go types for over 70 PostgreSQL types. pgtype is the type system underlying the

View File

@ -305,7 +305,7 @@ func arrayParseInteger(buf *bytes.Buffer) (int32, error) {
return 0, err return 0, err
} }
if '0' <= r && r <= '9' { if ('0' <= r && r <= '9') || r == '-' {
s.WriteRune(r) s.WriteRune(r)
} else { } else {
buf.UnreadRune() buf.UnreadRune()

View File

@ -11,7 +11,7 @@ import (
// ArrayType represents an array type. While it implements Value, this is only in service of its type conversion duties // ArrayType represents an array type. While it implements Value, this is only in service of its type conversion duties
// when registered as a data type in a ConnType. It should not be used directly as a Value. ArrayType is a convenience // when registered as a data type in a ConnType. It should not be used directly as a Value. ArrayType is a convenience
// type for types that do not have an concrete array type. // type for types that do not have a concrete array type.
type ArrayType struct { type ArrayType struct {
elements []ValueTranscoder elements []ValueTranscoder
dimensions []ArrayDimension dimensions []ArrayDimension

View File

@ -2,6 +2,7 @@ package pgtype
import ( import (
"database/sql/driver" "database/sql/driver"
"fmt"
) )
// BPChar is fixed-length, blank padded char type // BPChar is fixed-length, blank padded char type
@ -20,7 +21,8 @@ func (dst BPChar) Get() interface{} {
// AssignTo assigns from src to dst. // AssignTo assigns from src to dst.
func (src *BPChar) AssignTo(dst interface{}) error { func (src *BPChar) AssignTo(dst interface{}) error {
if src.Status == Present { switch src.Status {
case Present:
switch v := dst.(type) { switch v := dst.(type) {
case *rune: case *rune:
runes := []rune(src.String) runes := []rune(src.String)
@ -28,9 +30,24 @@ func (src *BPChar) AssignTo(dst interface{}) error {
*v = runes[0] *v = runes[0]
return nil return nil
} }
case *string:
*v = src.String
return nil
case *[]byte:
*v = make([]byte, len(src.String))
copy(*v, src.String)
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
} }
case Null:
return NullAssignTo(dst)
} }
return (*Text)(src).AssignTo(dst)
return fmt.Errorf("cannot decode %#v into %T", src, dst)
} }
func (BPChar) PreferredResultFormat() int16 { func (BPChar) PreferredResultFormat() int16 {

View File

@ -1,5 +1,7 @@
package pgtype package pgtype
import "database/sql/driver"
type CIDR Inet type CIDR Inet
func (dst *CIDR) Set(src interface{}) error { func (dst *CIDR) Set(src interface{}) error {
@ -29,3 +31,13 @@ func (src CIDR) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
func (src CIDR) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) { func (src CIDR) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Inet)(src).EncodeBinary(ci, buf) return (Inet)(src).EncodeBinary(ci, buf)
} }
// Scan implements the database/sql Scanner interface.
func (dst *CIDR) Scan(src interface{}) error {
return (*Inet)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src CIDR) Value() (driver.Value, error) {
return (Inet)(src).Value()
}

View File

@ -172,7 +172,7 @@ func underlyingUUIDType(val interface{}) (interface{}, bool) {
switch refVal.Kind() { switch refVal.Kind() {
case reflect.Ptr: case reflect.Ptr:
if refVal.IsNil() { if refVal.IsNil() {
return time.Time{}, false return nil, false
} }
convVal := refVal.Elem().Interface() convVal := refVal.Elem().Interface()
return convVal, true return convVal, true
@ -337,6 +337,10 @@ func float64AssignTo(srcVal float64, srcStatus Status, dst interface{}) error {
if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr { if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
el := v.Elem() el := v.Elem()
switch el.Kind() { switch el.Kind() {
// if dst is a type alias of a float32 or 64, set dst val
case reflect.Float32, reflect.Float64:
el.SetFloat(srcVal)
return nil
// if dst is a pointer to pointer, strip the pointer and try again // if dst is a pointer to pointer, strip the pointer and try again
case reflect.Ptr: case reflect.Ptr:
if el.IsNil() { if el.IsNil() {

View File

@ -1,10 +1,12 @@
package pgtype package pgtype
import ( import (
"database/sql"
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"fmt" "fmt"
"strings"
"time" "time"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@ -34,17 +36,25 @@ func (dst *Date) Set(src interface{}) error {
} }
} }
if value, ok := src.(interface{ Value() (driver.Value, error) }); ok {
v, err := value.Value()
if err != nil {
return fmt.Errorf("cannot get value %v for Date: %v", value, err)
}
return dst.Set(v)
}
switch value := src.(type) { switch value := src.(type) {
case time.Time: case time.Time:
*dst = Date{Time: value, Status: Present} *dst = Date{Time: value, Status: Present}
case string:
return dst.DecodeText(nil, []byte(value))
case *time.Time: case *time.Time:
if value == nil { if value == nil {
*dst = Date{Status: Null} *dst = Date{Status: Null}
} else { } else {
return dst.Set(*value) return dst.Set(*value)
} }
case string:
return dst.DecodeText(nil, []byte(value))
case *string: case *string:
if value == nil { if value == nil {
*dst = Date{Status: Null} *dst = Date{Status: Null}
@ -76,6 +86,24 @@ func (dst Date) Get() interface{} {
} }
func (src *Date) AssignTo(dst interface{}) error { func (src *Date) AssignTo(dst interface{}) error {
if scanner, ok := dst.(sql.Scanner); ok {
var err error
switch src.Status {
case Present:
if src.InfinityModifier != None {
err = scanner.Scan(src.InfinityModifier.String())
} else {
err = scanner.Scan(src.Time)
}
case Null:
err = scanner.Scan(nil)
}
if err != nil {
return fmt.Errorf("unable assign %v to %T: %s", src, dst, err)
}
return nil
}
switch src.Status { switch src.Status {
case Present: case Present:
switch v := dst.(type) { switch v := dst.(type) {
@ -111,6 +139,15 @@ func (dst *Date) DecodeText(ci *ConnInfo, src []byte) error {
case "-infinity": case "-infinity":
*dst = Date{Status: Present, InfinityModifier: -Infinity} *dst = Date{Status: Present, InfinityModifier: -Infinity}
default: default:
if strings.HasSuffix(sbuf, " BC") {
t, err := time.ParseInLocation("2006-01-02", strings.TrimRight(sbuf, " BC"), time.UTC)
t2 := time.Date(1-t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
if err != nil {
return err
}
*dst = Date{Time: t2, Status: Present}
return nil
}
t, err := time.ParseInLocation("2006-01-02", sbuf, time.UTC) t, err := time.ParseInLocation("2006-01-02", sbuf, time.UTC)
if err != nil { if err != nil {
return err return err

View File

@ -2,7 +2,7 @@ package pgtype
import "fmt" import "fmt"
// EnumType represents a enum type. While it implements Value, this is only in service of its type conversion duties // EnumType represents an enum type. While it implements Value, this is only in service of its type conversion duties
// when registered as a data type in a ConnType. It should not be used directly as a Value. // when registered as a data type in a ConnType. It should not be used directly as a Value.
type EnumType struct { type EnumType struct {
value string value string

View File

@ -204,7 +204,7 @@ func (dst *Float8) DecodeBinary(ci *ConnInfo, src []byte) error {
} }
if len(src) != 8 { if len(src) != 8 {
return fmt.Errorf("invalid length for float4: %v", len(src)) return fmt.Errorf("invalid length for float8: %v", len(src))
} }
n := int64(binary.BigEndian.Uint64(src)) n := int64(binary.BigEndian.Uint64(src))

View File

@ -40,6 +40,18 @@ func (dst *Hstore) Set(src interface{}) error {
m[k] = Text{String: v, Status: Present} m[k] = Text{String: v, Status: Present}
} }
*dst = Hstore{Map: m, Status: Present} *dst = Hstore{Map: m, Status: Present}
case map[string]*string:
m := make(map[string]Text, len(value))
for k, v := range value {
if v == nil {
m[k] = Text{Status: Null}
} else {
m[k] = Text{String: *v, Status: Present}
}
}
*dst = Hstore{Map: m, Status: Present}
case map[string]Text:
*dst = Hstore{Map: value, Status: Present}
default: default:
return fmt.Errorf("cannot convert %v to Hstore", src) return fmt.Errorf("cannot convert %v to Hstore", src)
} }
@ -71,6 +83,20 @@ func (src *Hstore) AssignTo(dst interface{}) error {
(*v)[k] = val.String (*v)[k] = val.String
} }
return nil return nil
case *map[string]*string:
*v = make(map[string]*string, len(src.Map))
for k, val := range src.Map {
switch val.Status {
case Null:
(*v)[k] = nil
case Present:
str := val.String
(*v)[k] = &str
default:
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
}
return nil
default: default:
if nextDst, retry := GetAssignToDstType(dst); retry { if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst) return src.AssignTo(nextDst)
@ -142,8 +168,8 @@ func (dst *Hstore) DecodeBinary(ci *ConnInfo, src []byte) error {
var valueBuf []byte var valueBuf []byte
if valueLen >= 0 { if valueLen >= 0 {
valueBuf = src[rp : rp+valueLen] valueBuf = src[rp : rp+valueLen]
rp += valueLen
} }
rp += valueLen
var value Text var value Text
err := value.DecodeBinary(ci, valueBuf) err := value.DecodeBinary(ci, valueBuf)
@ -388,7 +414,7 @@ func parseHstore(s string) (k []string, v []Text, err error) {
r, end = p.Consume() r, end = p.Consume()
switch { switch {
case end: case end:
err = errors.New("Found EOS after ',', expcting space") err = errors.New("Found EOS after ',', expecting space")
case (unicode.IsSpace(r)): case (unicode.IsSpace(r)):
r, end = p.Consume() r, end = p.Consume()
state = hsKey state = hsKey

View File

@ -2,8 +2,10 @@ package pgtype
import ( import (
"database/sql/driver" "database/sql/driver"
"encoding"
"fmt" "fmt"
"net" "net"
"strings"
) )
// Network address family is dependent on server socket.h value for AF_INET. // Network address family is dependent on server socket.h value for AF_INET.
@ -47,9 +49,26 @@ func (dst *Inet) Set(src interface{}) error {
case string: case string:
ip, ipnet, err := net.ParseCIDR(value) ip, ipnet, err := net.ParseCIDR(value)
if err != nil { if err != nil {
return err ip := net.ParseIP(value)
if ip == nil {
return fmt.Errorf("unable to parse inet address: %s", value)
}
if ipv4 := maybeGetIPv4(value, ip); ipv4 != nil {
ipnet = &net.IPNet{IP: ipv4, Mask: net.CIDRMask(32, 32)}
} else {
ipnet = &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}
}
} else {
ipnet.IP = ip
if ipv4 := maybeGetIPv4(value, ipnet.IP); ipv4 != nil {
ipnet.IP = ipv4
if len(ipnet.Mask) == 16 {
ipnet.Mask = ipnet.Mask[12:] // Not sure this is ever needed.
}
}
} }
ipnet.IP = ip
*dst = Inet{IPNet: ipnet, Status: Present} *dst = Inet{IPNet: ipnet, Status: Present}
case *net.IPNet: case *net.IPNet:
if value == nil { if value == nil {
@ -70,6 +89,16 @@ func (dst *Inet) Set(src interface{}) error {
return dst.Set(*value) return dst.Set(*value)
} }
default: default:
if tv, ok := src.(encoding.TextMarshaler); ok {
text, err := tv.MarshalText()
if err != nil {
return fmt.Errorf("cannot marshal %v: %w", value, err)
}
return dst.Set(string(text))
}
if sv, ok := src.(fmt.Stringer); ok {
return dst.Set(sv.String())
}
if originalSrc, ok := underlyingPtrType(src); ok { if originalSrc, ok := underlyingPtrType(src); ok {
return dst.Set(originalSrc) return dst.Set(originalSrc)
} }
@ -79,6 +108,25 @@ func (dst *Inet) Set(src interface{}) error {
return nil return nil
} }
// Convert the net.IP to IPv4, if appropriate.
//
// When parsing a string to a net.IP using net.ParseIP() and the like, we get a
// 16 byte slice for IPv4 addresses as well as IPv6 addresses. This function
// calls To4() to convert them to a 4 byte slice. This is useful as it allows
// users of the net.IP check for IPv4 addresses based on the length and makes
// it clear we are handling IPv4 as opposed to IPv6 or IPv4-mapped IPv6
// addresses.
func maybeGetIPv4(input string, ip net.IP) net.IP {
// Do not do this if the provided input looks like IPv6. This is because
// To4() on IPv4-mapped IPv6 addresses converts them to IPv4, which behave
// different in some cases.
if strings.Contains(input, ":") {
return nil
}
return ip.To4()
}
func (dst Inet) Get() interface{} { func (dst Inet) Get() interface{} {
switch dst.Status { switch dst.Status {
case Present: case Present:
@ -110,6 +158,12 @@ func (src *Inet) AssignTo(dst interface{}) error {
copy(*v, src.IPNet.IP) copy(*v, src.IPNet.IP)
return nil return nil
default: default:
if tv, ok := dst.(encoding.TextUnmarshaler); ok {
if err := tv.UnmarshalText([]byte(src.IPNet.String())); err != nil {
return fmt.Errorf("cannot unmarshal %v to %T: %w", src, dst, err)
}
return nil
}
if nextDst, retry := GetAssignToDstType(dst); retry { if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst) return src.AssignTo(nextDst)
} }
@ -161,7 +215,7 @@ func (dst *Inet) DecodeBinary(ci *ConnInfo, src []byte) error {
} }
if len(src) != 8 && len(src) != 20 { if len(src) != 8 && len(src) != 20 {
return fmt.Errorf("Received an invalid size for a inet: %d", len(src)) return fmt.Errorf("Received an invalid size for an inet: %d", len(src))
} }
// ignore family // ignore family

View File

@ -3,6 +3,7 @@ package pgtype
import ( import (
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"encoding/json"
"fmt" "fmt"
"math" "math"
"strconv" "strconv"
@ -302,3 +303,19 @@ func (src Int2) MarshalJSON() ([]byte, error) {
return nil, errBadStatus return nil, errBadStatus
} }
func (dst *Int2) UnmarshalJSON(b []byte) error {
var n *int16
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
if n == nil {
*dst = Int2{Status: Null}
} else {
*dst = Int2{Int: *n, Status: Present}
}
return nil
}

239
src/vendor/github.com/jackc/pgtype/int4_multirange.go generated vendored Normal file
View File

@ -0,0 +1,239 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Int4multirange struct {
Ranges []Int4range
Status Status
}
func (dst *Int4multirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
switch value := src.(type) {
case Int4multirange:
*dst = value
case *Int4multirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Int4range:
if value == nil {
*dst = Int4multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int4multirange{Status: Present}
} else {
elements := make([]Int4range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4multirange{
Ranges: elements,
Status: Present,
}
}
case []*Int4range:
if value == nil {
*dst = Int4multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int4multirange{Status: Present}
} else {
elements := make([]Int4range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4multirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Int4multirange", src)
}
return nil
}
func (dst Int4multirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int4multirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int4multirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Int4range
if len(utmr.Elements) > 0 {
elements = make([]Int4range, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Int4range
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int4multirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Int4multirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Int4multirange{Status: Present}
return nil
}
elements := make([]Int4range, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int4multirange{Ranges: elements, Status: Present}
return nil
}
func (src Int4multirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Int4multirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4multirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4multirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

239
src/vendor/github.com/jackc/pgtype/int8_multirange.go generated vendored Normal file
View File

@ -0,0 +1,239 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Int8multirange struct {
Ranges []Int8range
Status Status
}
func (dst *Int8multirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
switch value := src.(type) {
case Int8multirange:
*dst = value
case *Int8multirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Int8range:
if value == nil {
*dst = Int8multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int8multirange{Status: Present}
} else {
elements := make([]Int8range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8multirange{
Ranges: elements,
Status: Present,
}
}
case []*Int8range:
if value == nil {
*dst = Int8multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int8multirange{Status: Present}
} else {
elements := make([]Int8range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8multirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Int8multirange", src)
}
return nil
}
func (dst Int8multirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int8multirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int8multirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Int8range
if len(utmr.Elements) > 0 {
elements = make([]Int8range, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Int8range
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int8multirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Int8multirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Int8multirange{Status: Present}
return nil
}
elements := make([]Int8range, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int8multirange{Ranges: elements, Status: Present}
return nil
}
func (src Int8multirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Int8multirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8multirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8multirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -174,7 +174,7 @@ func (dst *Interval) DecodeBinary(ci *ConnInfo, src []byte) error {
} }
if len(src) != 16 { if len(src) != 16 {
return fmt.Errorf("Received an invalid size for a interval: %d", len(src)) return fmt.Errorf("Received an invalid size for an interval: %d", len(src))
} }
microseconds := int64(binary.BigEndian.Uint64(src)) microseconds := int64(binary.BigEndian.Uint64(src))

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"reflect"
) )
type JSON struct { type JSON struct {
@ -107,6 +108,9 @@ func (src *JSON) AssignTo(dst interface{}) error {
data = []byte("null") data = []byte("null")
} }
p := reflect.ValueOf(dst).Elem()
p.Set(reflect.Zero(p.Type()))
return json.Unmarshal(data, dst) return json.Unmarshal(data, dst)
} }

546
src/vendor/github.com/jackc/pgtype/json_array.go generated vendored Normal file
View File

@ -0,0 +1,546 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type JSONArray struct {
Elements []JSON
Dimensions []ArrayDimension
Status Status
}
func (dst *JSONArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case [][]byte:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []json.RawMessage:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []JSON:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
*dst = JSONArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = JSONArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for JSONArray", src)
}
if elementsLength == 0 {
*dst = JSONArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to JSONArray", src)
}
*dst = JSONArray{
Elements: make([]JSON, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]JSON, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to JSONArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *JSONArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to JSONArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in JSONArray", err)
}
index++
return index, nil
}
func (dst JSONArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *JSONArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[][]byte:
*v = make([][]byte, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]json.RawMessage:
*v = make([]json.RawMessage, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *JSONArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from JSONArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from JSONArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *JSONArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []JSON
if len(uta.Elements) > 0 {
elements = make([]JSON, len(uta.Elements))
for i, s := range uta.Elements {
var elem JSON
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = JSONArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *JSONArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = JSONArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]JSON, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = JSONArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src JSONArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src JSONArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("json"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "json")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *JSONArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src JSONArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}

View File

@ -5,6 +5,7 @@ package pgtype
import ( import (
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"encoding/json"
"fmt" "fmt"
"reflect" "reflect"
@ -72,6 +73,25 @@ func (dst *JSONBArray) Set(src interface{}) error {
} }
} }
case []json.RawMessage:
if value == nil {
*dst = JSONBArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONBArray{Status: Present}
} else {
elements := make([]JSONB, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONBArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []JSONB: case []JSONB:
if value == nil { if value == nil {
*dst = JSONBArray{Status: Null} *dst = JSONBArray{Status: Null}
@ -214,6 +234,15 @@ func (src *JSONBArray) AssignTo(dst interface{}) error {
} }
return nil return nil
case *[]json.RawMessage:
*v = make([]json.RawMessage, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
} }
} }

View File

@ -115,7 +115,7 @@ func (src Lseg) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return nil, errUndefined return nil, errUndefined
} }
buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`, buf = append(buf, fmt.Sprintf(`[(%s,%s),(%s,%s)]`,
strconv.FormatFloat(src.P[0].X, 'f', -1, 64), strconv.FormatFloat(src.P[0].X, 'f', -1, 64),
strconv.FormatFloat(src.P[0].Y, 'f', -1, 64), strconv.FormatFloat(src.P[0].Y, 'f', -1, 64),
strconv.FormatFloat(src.P[1].X, 'f', -1, 64), strconv.FormatFloat(src.P[1].X, 'f', -1, 64),

72
src/vendor/github.com/jackc/pgtype/ltree.go generated vendored Normal file
View File

@ -0,0 +1,72 @@
package pgtype
import (
"database/sql/driver"
"fmt"
)
type Ltree Text
func (dst *Ltree) Set(src interface{}) error {
return (*Text)(dst).Set(src)
}
func (dst Ltree) Get() interface{} {
return (Text)(dst).Get()
}
func (src *Ltree) AssignTo(dst interface{}) error {
return (*Text)(src).AssignTo(dst)
}
func (src Ltree) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeText(ci, buf)
}
func (src Ltree) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, 1)
return append(buf, src.String...), nil
}
func (Ltree) PreferredResultFormat() int16 {
return TextFormatCode
}
func (dst *Ltree) DecodeText(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeText(ci, src)
}
func (dst *Ltree) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Ltree{Status: Null}
return nil
}
// Get Ltree version, only 1 is allowed
version := src[0]
if version != 1 {
return fmt.Errorf("unsupported ltree version %d", version)
}
ltreeStr := string(src[1:])
*dst = Ltree{String: ltreeStr, Status: Present}
return nil
}
func (Ltree) PreferredParamFormat() int16 {
return TextFormatCode
}
func (dst *Ltree) Scan(src interface{}) error {
return (*Text)(dst).Scan(src)
}
func (src Ltree) Value() (driver.Value, error) {
return (Text)(src).Value()
}

83
src/vendor/github.com/jackc/pgtype/multirange.go generated vendored Normal file
View File

@ -0,0 +1,83 @@
package pgtype
import (
"bytes"
"fmt"
)
type UntypedTextMultirange struct {
Elements []string
}
func ParseUntypedTextMultirange(src string) (*UntypedTextMultirange, error) {
utmr := &UntypedTextMultirange{}
utmr.Elements = make([]string, 0)
buf := bytes.NewBufferString(src)
skipWhitespace(buf)
r, _, err := buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid array: %v", err)
}
if r != '{' {
return nil, fmt.Errorf("invalid multirange, expected '{': %v", err)
}
parseValueLoop:
for {
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid multirange: %v", err)
}
switch r {
case ',': // skip range separator
case '}':
break parseValueLoop
default:
buf.UnreadRune()
value, err := parseRange(buf)
if err != nil {
return nil, fmt.Errorf("invalid multirange value: %v", err)
}
utmr.Elements = append(utmr.Elements, value)
}
}
skipWhitespace(buf)
if buf.Len() > 0 {
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
}
return utmr, nil
}
func parseRange(buf *bytes.Buffer) (string, error) {
s := &bytes.Buffer{}
boundSepRead := false
for {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
switch r {
case ',', '}':
if r == ',' && !boundSepRead {
boundSepRead = true
break
}
buf.UnreadRune()
return s.String(), nil
}
s.WriteRune(r)
}
}

239
src/vendor/github.com/jackc/pgtype/num_multirange.go generated vendored Normal file
View File

@ -0,0 +1,239 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Nummultirange struct {
Ranges []Numrange
Status Status
}
func (dst *Nummultirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
switch value := src.(type) {
case Nummultirange:
*dst = value
case *Nummultirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Numrange:
if value == nil {
*dst = Nummultirange{Status: Null}
} else if len(value) == 0 {
*dst = Nummultirange{Status: Present}
} else {
elements := make([]Numrange, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Nummultirange{
Ranges: elements,
Status: Present,
}
}
case []*Numrange:
if value == nil {
*dst = Nummultirange{Status: Null}
} else if len(value) == 0 {
*dst = Nummultirange{Status: Present}
} else {
elements := make([]Numrange, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Nummultirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Nummultirange", src)
}
return nil
}
func (dst Nummultirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Nummultirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Nummultirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Numrange
if len(utmr.Elements) > 0 {
elements = make([]Numrange, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Numrange
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Nummultirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Nummultirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Nummultirange{Status: Present}
return nil
}
elements := make([]Numrange, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Nummultirange{Ranges: elements, Status: Present}
return nil
}
func (src Nummultirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Nummultirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Nummultirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Nummultirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -1,6 +1,7 @@
package pgtype package pgtype
import ( import (
"bytes"
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
@ -18,6 +19,12 @@ const nbase = 10000
const ( const (
pgNumericNaN = 0x00000000c0000000 pgNumericNaN = 0x00000000c0000000
pgNumericNaNSign = 0xc000 pgNumericNaNSign = 0xc000
pgNumericPosInf = 0x00000000d0000000
pgNumericPosInfSign = 0xd000
pgNumericNegInf = 0x00000000f0000000
pgNumericNegInfSign = 0xf000
) )
var big0 *big.Int = big.NewInt(0) var big0 *big.Int = big.NewInt(0)
@ -49,10 +56,11 @@ var bigNBaseX3 *big.Int = big.NewInt(nbase * nbase * nbase)
var bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase) var bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase)
type Numeric struct { type Numeric struct {
Int *big.Int Int *big.Int
Exp int32 Exp int32
Status Status Status Status
NaN bool NaN bool
InfinityModifier InfinityModifier
} }
func (dst *Numeric) Set(src interface{}) error { func (dst *Numeric) Set(src interface{}) error {
@ -73,6 +81,12 @@ func (dst *Numeric) Set(src interface{}) error {
if math.IsNaN(float64(value)) { if math.IsNaN(float64(value)) {
*dst = Numeric{Status: Present, NaN: true} *dst = Numeric{Status: Present, NaN: true}
return nil return nil
} else if math.IsInf(float64(value), 1) {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if math.IsInf(float64(value), -1) {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
} }
num, exp, err := parseNumericString(strconv.FormatFloat(float64(value), 'f', -1, 64)) num, exp, err := parseNumericString(strconv.FormatFloat(float64(value), 'f', -1, 64))
if err != nil { if err != nil {
@ -83,6 +97,12 @@ func (dst *Numeric) Set(src interface{}) error {
if math.IsNaN(value) { if math.IsNaN(value) {
*dst = Numeric{Status: Present, NaN: true} *dst = Numeric{Status: Present, NaN: true}
return nil return nil
} else if math.IsInf(value, 1) {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if math.IsInf(value, -1) {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
} }
num, exp, err := parseNumericString(strconv.FormatFloat(value, 'f', -1, 64)) num, exp, err := parseNumericString(strconv.FormatFloat(value, 'f', -1, 64))
if err != nil { if err != nil {
@ -193,6 +213,8 @@ func (dst *Numeric) Set(src interface{}) error {
} else { } else {
return dst.Set(*value) return dst.Set(*value)
} }
case InfinityModifier:
*dst = Numeric{InfinityModifier: value, Status: Present}
default: default:
if originalSrc, ok := underlyingNumberType(src); ok { if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc) return dst.Set(originalSrc)
@ -206,6 +228,9 @@ func (dst *Numeric) Set(src interface{}) error {
func (dst Numeric) Get() interface{} { func (dst Numeric) Get() interface{} {
switch dst.Status { switch dst.Status {
case Present: case Present:
if dst.InfinityModifier != None {
return dst.InfinityModifier
}
return dst return dst
case Null: case Null:
return nil return nil
@ -345,6 +370,18 @@ func (src *Numeric) AssignTo(dst interface{}) error {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v) return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
} }
*v = normalizedInt.Uint64() *v = normalizedInt.Uint64()
case *big.Rat:
rat, err := src.toBigRat()
if err != nil {
return err
}
v.Set(rat)
case *string:
buf, err := encodeNumericText(*src, nil)
if err != nil {
return err
}
*v = string(buf)
default: default:
if nextDst, retry := GetAssignToDstType(dst); retry { if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst) return src.AssignTo(nextDst)
@ -382,9 +419,33 @@ func (dst *Numeric) toBigInt() (*big.Int, error) {
return num, nil return num, nil
} }
func (dst *Numeric) toBigRat() (*big.Rat, error) {
if dst.NaN {
return nil, fmt.Errorf("%v is not a number", dst)
} else if dst.InfinityModifier == Infinity {
return nil, fmt.Errorf("%v is infinity", dst)
} else if dst.InfinityModifier == NegativeInfinity {
return nil, fmt.Errorf("%v is -infinity", dst)
}
num := new(big.Rat).SetInt(dst.Int)
if dst.Exp > 0 {
mul := new(big.Int).Exp(big10, big.NewInt(int64(dst.Exp)), nil)
num.Mul(num, new(big.Rat).SetInt(mul))
} else if dst.Exp < 0 {
mul := new(big.Int).Exp(big10, big.NewInt(int64(-dst.Exp)), nil)
num.Quo(num, new(big.Rat).SetInt(mul))
}
return num, nil
}
func (src *Numeric) toFloat64() (float64, error) { func (src *Numeric) toFloat64() (float64, error) {
if src.NaN { if src.NaN {
return math.NaN(), nil return math.NaN(), nil
} else if src.InfinityModifier == Infinity {
return math.Inf(1), nil
} else if src.InfinityModifier == NegativeInfinity {
return math.Inf(-1), nil
} }
buf := make([]byte, 0, 32) buf := make([]byte, 0, 32)
@ -409,6 +470,12 @@ func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error {
if string(src) == "NaN" { if string(src) == "NaN" {
*dst = Numeric{Status: Present, NaN: true} *dst = Numeric{Status: Present, NaN: true}
return nil return nil
} else if string(src) == "Infinity" {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if string(src) == "-Infinity" {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
} }
num, exp, err := parseNumericString(string(src)) num, exp, err := parseNumericString(string(src))
@ -452,11 +519,11 @@ func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
} }
rp := 0 rp := 0
ndigits := int16(binary.BigEndian.Uint16(src[rp:])) ndigits := binary.BigEndian.Uint16(src[rp:])
rp += 2 rp += 2
weight := int16(binary.BigEndian.Uint16(src[rp:])) weight := int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2 rp += 2
sign := uint16(binary.BigEndian.Uint16(src[rp:])) sign := binary.BigEndian.Uint16(src[rp:])
rp += 2 rp += 2
dscale := int16(binary.BigEndian.Uint16(src[rp:])) dscale := int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2 rp += 2
@ -464,6 +531,12 @@ func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
if sign == pgNumericNaNSign { if sign == pgNumericNaNSign {
*dst = Numeric{Status: Present, NaN: true} *dst = Numeric{Status: Present, NaN: true}
return nil return nil
} else if sign == pgNumericPosInfSign {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if sign == pgNumericNegInfSign {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
} }
if ndigits == 0 { if ndigits == 0 {
@ -504,7 +577,7 @@ func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
exp := (int32(weight) - int32(ndigits) + 1) * 4 exp := (int32(weight) - int32(ndigits) + 1) * 4
if dscale > 0 { if dscale > 0 {
fracNBaseDigits := ndigits - weight - 1 fracNBaseDigits := int16(int32(ndigits) - int32(weight) - 1)
fracDecimalDigits := fracNBaseDigits * 4 fracDecimalDigits := fracNBaseDigits * 4
if dscale > fracDecimalDigits { if dscale > fracDecimalDigits {
@ -575,6 +648,12 @@ func (src Numeric) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
if src.NaN { if src.NaN {
buf = append(buf, "NaN"...) buf = append(buf, "NaN"...)
return buf, nil return buf, nil
} else if src.InfinityModifier == Infinity {
buf = append(buf, "Infinity"...)
return buf, nil
} else if src.InfinityModifier == NegativeInfinity {
buf = append(buf, "-Infinity"...)
return buf, nil
} }
buf = append(buf, src.Int.String()...) buf = append(buf, src.Int.String()...)
@ -594,6 +673,12 @@ func (src Numeric) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
if src.NaN { if src.NaN {
buf = pgio.AppendUint64(buf, pgNumericNaN) buf = pgio.AppendUint64(buf, pgNumericNaN)
return buf, nil return buf, nil
} else if src.InfinityModifier == Infinity {
buf = pgio.AppendUint64(buf, pgNumericPosInf)
return buf, nil
} else if src.InfinityModifier == NegativeInfinity {
buf = pgio.AppendUint64(buf, pgNumericNegInf)
return buf, nil
} }
var sign int16 var sign int16
@ -714,3 +799,55 @@ func (src Numeric) Value() (driver.Value, error) {
return nil, errUndefined return nil, errUndefined
} }
} }
func encodeNumericText(n Numeric, buf []byte) (newBuf []byte, err error) {
// if !n.Valid {
// return nil, nil
// }
if n.NaN {
buf = append(buf, "NaN"...)
return buf, nil
} else if n.InfinityModifier == Infinity {
buf = append(buf, "Infinity"...)
return buf, nil
} else if n.InfinityModifier == NegativeInfinity {
buf = append(buf, "-Infinity"...)
return buf, nil
}
buf = append(buf, n.numberTextBytes()...)
return buf, nil
}
// numberString returns a string of the number. undefined if NaN, infinite, or NULL
func (n Numeric) numberTextBytes() []byte {
intStr := n.Int.String()
buf := &bytes.Buffer{}
exp := int(n.Exp)
if exp > 0 {
buf.WriteString(intStr)
for i := 0; i < exp; i++ {
buf.WriteByte('0')
}
} else if exp < 0 {
if len(intStr) <= -exp {
buf.WriteString("0.")
leadingZeros := -exp - len(intStr)
for i := 0; i < leadingZeros; i++ {
buf.WriteByte('0')
}
buf.WriteString(intStr)
} else if len(intStr) > -exp {
dpPos := len(intStr) + exp
buf.WriteString(intStr[:dpPos])
buf.WriteByte('.')
buf.WriteString(intStr[dpPos:])
}
} else {
buf.WriteString(intStr)
}
return buf.Bytes()
}

View File

@ -26,6 +26,7 @@ const (
XIDOID = 28 XIDOID = 28
CIDOID = 29 CIDOID = 29
JSONOID = 114 JSONOID = 114
JSONArrayOID = 199
PointOID = 600 PointOID = 600
LsegOID = 601 LsegOID = 601
PathOID = 602 PathOID = 602
@ -74,12 +75,15 @@ const (
JSONBArrayOID = 3807 JSONBArrayOID = 3807
DaterangeOID = 3912 DaterangeOID = 3912
Int4rangeOID = 3904 Int4rangeOID = 3904
Int4multirangeOID = 4451
NumrangeOID = 3906 NumrangeOID = 3906
NummultirangeOID = 4532
TsrangeOID = 3908 TsrangeOID = 3908
TsrangeArrayOID = 3909 TsrangeArrayOID = 3909
TstzrangeOID = 3910 TstzrangeOID = 3910
TstzrangeArrayOID = 3911 TstzrangeArrayOID = 3911
Int8rangeOID = 3926 Int8rangeOID = 3926
Int8multirangeOID = 4536
) )
type Status byte type Status byte
@ -288,10 +292,13 @@ func NewConnInfo() *ConnInfo {
ci.RegisterDataType(DataType{Value: &Int2{}, Name: "int2", OID: Int2OID}) ci.RegisterDataType(DataType{Value: &Int2{}, Name: "int2", OID: Int2OID})
ci.RegisterDataType(DataType{Value: &Int4{}, Name: "int4", OID: Int4OID}) ci.RegisterDataType(DataType{Value: &Int4{}, Name: "int4", OID: Int4OID})
ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID}) ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID})
ci.RegisterDataType(DataType{Value: &Int4multirange{}, Name: "int4multirange", OID: Int4multirangeOID})
ci.RegisterDataType(DataType{Value: &Int8{}, Name: "int8", OID: Int8OID}) ci.RegisterDataType(DataType{Value: &Int8{}, Name: "int8", OID: Int8OID})
ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID}) ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID})
ci.RegisterDataType(DataType{Value: &Int8multirange{}, Name: "int8multirange", OID: Int8multirangeOID})
ci.RegisterDataType(DataType{Value: &Interval{}, Name: "interval", OID: IntervalOID}) ci.RegisterDataType(DataType{Value: &Interval{}, Name: "interval", OID: IntervalOID})
ci.RegisterDataType(DataType{Value: &JSON{}, Name: "json", OID: JSONOID}) ci.RegisterDataType(DataType{Value: &JSON{}, Name: "json", OID: JSONOID})
ci.RegisterDataType(DataType{Value: &JSONArray{}, Name: "_json", OID: JSONArrayOID})
ci.RegisterDataType(DataType{Value: &JSONB{}, Name: "jsonb", OID: JSONBOID}) ci.RegisterDataType(DataType{Value: &JSONB{}, Name: "jsonb", OID: JSONBOID})
ci.RegisterDataType(DataType{Value: &JSONBArray{}, Name: "_jsonb", OID: JSONBArrayOID}) ci.RegisterDataType(DataType{Value: &JSONBArray{}, Name: "_jsonb", OID: JSONBArrayOID})
ci.RegisterDataType(DataType{Value: &Line{}, Name: "line", OID: LineOID}) ci.RegisterDataType(DataType{Value: &Line{}, Name: "line", OID: LineOID})
@ -300,6 +307,7 @@ func NewConnInfo() *ConnInfo {
ci.RegisterDataType(DataType{Value: &Name{}, Name: "name", OID: NameOID}) ci.RegisterDataType(DataType{Value: &Name{}, Name: "name", OID: NameOID})
ci.RegisterDataType(DataType{Value: &Numeric{}, Name: "numeric", OID: NumericOID}) ci.RegisterDataType(DataType{Value: &Numeric{}, Name: "numeric", OID: NumericOID})
ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID}) ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID})
ci.RegisterDataType(DataType{Value: &Nummultirange{}, Name: "nummultirange", OID: NummultirangeOID})
ci.RegisterDataType(DataType{Value: &OIDValue{}, Name: "oid", OID: OIDOID}) ci.RegisterDataType(DataType{Value: &OIDValue{}, Name: "oid", OID: OIDOID})
ci.RegisterDataType(DataType{Value: &Path{}, Name: "path", OID: PathOID}) ci.RegisterDataType(DataType{Value: &Path{}, Name: "path", OID: PathOID})
ci.RegisterDataType(DataType{Value: &Point{}, Name: "point", OID: PointOID}) ci.RegisterDataType(DataType{Value: &Point{}, Name: "point", OID: PointOID})
@ -527,8 +535,22 @@ type scanPlanDataTypeSQLScanner DataType
func (plan *scanPlanDataTypeSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { func (plan *scanPlanDataTypeSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
scanner, ok := dst.(sql.Scanner) scanner, ok := dst.(sql.Scanner)
if !ok { if !ok {
newPlan := ci.PlanScan(oid, formatCode, dst) dv := reflect.ValueOf(dst)
return newPlan.Scan(ci, oid, formatCode, src, dst) if dv.Kind() != reflect.Ptr || !dv.Type().Elem().Implements(scannerType) {
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
if src == nil {
// Ensure the pointer points to a zero version of the value
dv.Elem().Set(reflect.Zero(dv.Type().Elem()))
return nil
}
dv = dv.Elem()
// If the pointer is to a nil pointer then set that before scanning
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(dv.Type().Elem()))
}
scanner = dv.Interface().(sql.Scanner)
} }
dt := (*DataType)(plan) dt := (*DataType)(plan)
@ -587,8 +609,30 @@ func (plan *scanPlanDataTypeAssignTo) Scan(ci *ConnInfo, oid uint32, formatCode
type scanPlanSQLScanner struct{} type scanPlanSQLScanner struct{}
func (scanPlanSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error { func (scanPlanSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
scanner := dst.(sql.Scanner) scanner, ok := dst.(sql.Scanner)
if formatCode == BinaryFormatCode { if !ok {
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || !dv.Type().Elem().Implements(scannerType) {
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
if src == nil {
// Ensure the pointer points to a zero version of the value
dv.Elem().Set(reflect.Zero(dv.Elem().Type()))
return nil
}
dv = dv.Elem()
// If the pointer is to a nil pointer then set that before scanning
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(dv.Type().Elem()))
}
scanner = dv.Interface().(sql.Scanner)
}
if src == nil {
// This is necessary because interface value []byte:nil does not equal nil:nil for the binary format path and the
// text format path would be converted to empty string.
return scanner.Scan(nil)
} else if formatCode == BinaryFormatCode {
return scanner.Scan(src) return scanner.Scan(src)
} else { } else {
return scanner.Scan(string(src)) return scanner.Scan(string(src))
@ -751,6 +795,18 @@ func (scanPlanString) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byt
return newPlan.Scan(ci, oid, formatCode, src, dst) return newPlan.Scan(ci, oid, formatCode, src, dst)
} }
var scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
func isScanner(dst interface{}) bool {
if _, ok := dst.(sql.Scanner); ok {
return true
}
if t := reflect.TypeOf(dst); t != nil && t.Kind() == reflect.Ptr && t.Elem().Implements(scannerType) {
return true
}
return false
}
// PlanScan prepares a plan to scan a value into dst. // PlanScan prepares a plan to scan a value into dst.
func (ci *ConnInfo) PlanScan(oid uint32, formatCode int16, dst interface{}) ScanPlan { func (ci *ConnInfo) PlanScan(oid uint32, formatCode int16, dst interface{}) ScanPlan {
switch formatCode { switch formatCode {
@ -815,13 +871,13 @@ func (ci *ConnInfo) PlanScan(oid uint32, formatCode int16, dst interface{}) Scan
} }
if dt != nil { if dt != nil {
if _, ok := dst.(sql.Scanner); ok { if isScanner(dst) {
return (*scanPlanDataTypeSQLScanner)(dt) return (*scanPlanDataTypeSQLScanner)(dt)
} }
return (*scanPlanDataTypeAssignTo)(dt) return (*scanPlanDataTypeAssignTo)(dt)
} }
if _, ok := dst.(sql.Scanner); ok { if isScanner(dst) {
return scanPlanSQLScanner{} return scanPlanSQLScanner{}
} }
@ -869,72 +925,77 @@ var nameValues map[string]Value
func init() { func init() {
nameValues = map[string]Value{ nameValues = map[string]Value{
"_aclitem": &ACLItemArray{}, "_aclitem": &ACLItemArray{},
"_bool": &BoolArray{}, "_bool": &BoolArray{},
"_bpchar": &BPCharArray{}, "_bpchar": &BPCharArray{},
"_bytea": &ByteaArray{}, "_bytea": &ByteaArray{},
"_cidr": &CIDRArray{}, "_cidr": &CIDRArray{},
"_date": &DateArray{}, "_date": &DateArray{},
"_float4": &Float4Array{}, "_float4": &Float4Array{},
"_float8": &Float8Array{}, "_float8": &Float8Array{},
"_inet": &InetArray{}, "_inet": &InetArray{},
"_int2": &Int2Array{}, "_int2": &Int2Array{},
"_int4": &Int4Array{}, "_int4": &Int4Array{},
"_int8": &Int8Array{}, "_int8": &Int8Array{},
"_numeric": &NumericArray{}, "_numeric": &NumericArray{},
"_text": &TextArray{}, "_text": &TextArray{},
"_timestamp": &TimestampArray{}, "_timestamp": &TimestampArray{},
"_timestamptz": &TimestamptzArray{}, "_timestamptz": &TimestamptzArray{},
"_uuid": &UUIDArray{}, "_uuid": &UUIDArray{},
"_varchar": &VarcharArray{}, "_varchar": &VarcharArray{},
"_jsonb": &JSONBArray{}, "_json": &JSONArray{},
"aclitem": &ACLItem{}, "_jsonb": &JSONBArray{},
"bit": &Bit{}, "aclitem": &ACLItem{},
"bool": &Bool{}, "bit": &Bit{},
"box": &Box{}, "bool": &Bool{},
"bpchar": &BPChar{}, "box": &Box{},
"bytea": &Bytea{}, "bpchar": &BPChar{},
"char": &QChar{}, "bytea": &Bytea{},
"cid": &CID{}, "char": &QChar{},
"cidr": &CIDR{}, "cid": &CID{},
"circle": &Circle{}, "cidr": &CIDR{},
"date": &Date{}, "circle": &Circle{},
"daterange": &Daterange{}, "date": &Date{},
"float4": &Float4{}, "daterange": &Daterange{},
"float8": &Float8{}, "float4": &Float4{},
"hstore": &Hstore{}, "float8": &Float8{},
"inet": &Inet{}, "hstore": &Hstore{},
"int2": &Int2{}, "inet": &Inet{},
"int4": &Int4{}, "int2": &Int2{},
"int4range": &Int4range{}, "int4": &Int4{},
"int8": &Int8{}, "int4range": &Int4range{},
"int8range": &Int8range{}, "int4multirange": &Int4multirange{},
"interval": &Interval{}, "int8": &Int8{},
"json": &JSON{}, "int8range": &Int8range{},
"jsonb": &JSONB{}, "int8multirange": &Int8multirange{},
"line": &Line{}, "interval": &Interval{},
"lseg": &Lseg{}, "json": &JSON{},
"macaddr": &Macaddr{}, "jsonb": &JSONB{},
"name": &Name{}, "line": &Line{},
"numeric": &Numeric{}, "lseg": &Lseg{},
"numrange": &Numrange{}, "ltree": &Ltree{},
"oid": &OIDValue{}, "macaddr": &Macaddr{},
"path": &Path{}, "name": &Name{},
"point": &Point{}, "numeric": &Numeric{},
"polygon": &Polygon{}, "numrange": &Numrange{},
"record": &Record{}, "nummultirange": &Nummultirange{},
"text": &Text{}, "oid": &OIDValue{},
"tid": &TID{}, "path": &Path{},
"timestamp": &Timestamp{}, "point": &Point{},
"timestamptz": &Timestamptz{}, "polygon": &Polygon{},
"tsrange": &Tsrange{}, "record": &Record{},
"_tsrange": &TsrangeArray{}, "text": &Text{},
"tstzrange": &Tstzrange{}, "tid": &TID{},
"_tstzrange": &TstzrangeArray{}, "timestamp": &Timestamp{},
"unknown": &Unknown{}, "timestamptz": &Timestamptz{},
"uuid": &UUID{}, "tsrange": &Tsrange{},
"varbit": &Varbit{}, "_tsrange": &TsrangeArray{},
"varchar": &Varchar{}, "tstzrange": &Tstzrange{},
"xid": &XID{}, "_tstzrange": &TstzrangeArray{},
"unknown": &Unknown{},
"uuid": &UUID{},
"varbit": &Varbit{},
"varchar": &Varchar{},
"xid": &XID{},
} }
} }

View File

@ -6,7 +6,7 @@ import (
) )
// Record is the generic PostgreSQL record type such as is created with the // Record is the generic PostgreSQL record type such as is created with the
// "row" function. Record only implements BinaryEncoder and Value. The text // "row" function. Record only implements BinaryDecoder and Value. The text
// format output format from PostgreSQL does not include type information and is // format output format from PostgreSQL does not include type information and is
// therefore impossible to decode. No encoders are implemented because // therefore impossible to decode. No encoders are implemented because
// PostgreSQL does not support input of generic records. // PostgreSQL does not support input of generic records.

318
src/vendor/github.com/jackc/pgtype/record_array.go generated vendored Normal file
View File

@ -0,0 +1,318 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"encoding/binary"
"fmt"
"reflect"
)
type RecordArray struct {
Elements []Record
Dimensions []ArrayDimension
Status Status
}
func (dst *RecordArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = RecordArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case [][]Value:
if value == nil {
*dst = RecordArray{Status: Null}
} else if len(value) == 0 {
*dst = RecordArray{Status: Present}
} else {
elements := make([]Record, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = RecordArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Record:
if value == nil {
*dst = RecordArray{Status: Null}
} else if len(value) == 0 {
*dst = RecordArray{Status: Present}
} else {
*dst = RecordArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = RecordArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for RecordArray", src)
}
if elementsLength == 0 {
*dst = RecordArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to RecordArray", src)
}
*dst = RecordArray{
Elements: make([]Record, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Record, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to RecordArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *RecordArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to RecordArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in RecordArray", err)
}
index++
return index, nil
}
func (dst RecordArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *RecordArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[][]Value:
*v = make([][]Value, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *RecordArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from RecordArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from RecordArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *RecordArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = RecordArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = RecordArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Record, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = RecordArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}

View File

@ -39,7 +39,37 @@ func (dst *Text) Set(src interface{}) error {
} else { } else {
*dst = Text{String: string(value), Status: Present} *dst = Text{String: string(value), Status: Present}
} }
case fmt.Stringer:
if value == fmt.Stringer(nil) {
*dst = Text{Status: Null}
} else {
*dst = Text{String: value.String(), Status: Present}
}
default: default:
// Cannot be part of the switch: If Value() returns nil on
// non-string, we should still try to checks the underlying type
// using reflection.
//
// For example the struct might implement driver.Valuer with
// pointer receiver and fmt.Stringer with value receiver.
if value, ok := src.(driver.Valuer); ok {
if value == driver.Valuer(nil) {
*dst = Text{Status: Null}
return nil
} else {
v, err := value.Value()
if err != nil {
return fmt.Errorf("driver.Valuer Value() method failed: %w", err)
}
// Handles also v == nil case.
if s, ok := v.(string); ok {
*dst = Text{String: s, Status: Present}
return nil
}
}
}
if originalSrc, ok := underlyingStringType(src); ok { if originalSrc, ok := underlyingStringType(src); ok {
return dst.Set(originalSrc) return dst.Set(originalSrc)
} }

View File

@ -4,6 +4,7 @@ import (
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"strings"
"time" "time"
"github.com/jackc/pgio" "github.com/jackc/pgio"
@ -46,6 +47,14 @@ func (dst *Timestamp) Set(src interface{}) error {
} else { } else {
return dst.Set(*value) return dst.Set(*value)
} }
case string:
return dst.DecodeText(nil, []byte(value))
case *string:
if value == nil {
*dst = Timestamp{Status: Null}
} else {
return dst.Set(*value)
}
case InfinityModifier: case InfinityModifier:
*dst = Timestamp{InfinityModifier: value, Status: Present} *dst = Timestamp{InfinityModifier: value, Status: Present}
default: default:
@ -110,6 +119,15 @@ func (dst *Timestamp) DecodeText(ci *ConnInfo, src []byte) error {
case "-infinity": case "-infinity":
*dst = Timestamp{Status: Present, InfinityModifier: -Infinity} *dst = Timestamp{Status: Present, InfinityModifier: -Infinity}
default: default:
if strings.HasSuffix(sbuf, " BC") {
t, err := time.Parse(pgTimestampFormat, strings.TrimRight(sbuf, " BC"))
t2 := time.Date(1-t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
if err != nil {
return err
}
*dst = Timestamp{Time: t2, Status: Present}
return nil
}
tim, err := time.Parse(pgTimestampFormat, sbuf) tim, err := time.Parse(pgTimestampFormat, sbuf)
if err != nil { if err != nil {
return err return err
@ -141,8 +159,10 @@ func (dst *Timestamp) DecodeBinary(ci *ConnInfo, src []byte) error {
case negativeInfinityMicrosecondOffset: case negativeInfinityMicrosecondOffset:
*dst = Timestamp{Status: Present, InfinityModifier: -Infinity} *dst = Timestamp{Status: Present, InfinityModifier: -Infinity}
default: default:
microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K tim := time.Unix(
tim := time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000).UTC() microsecFromUnixEpochToY2K/1000000+microsecSinceY2K/1000000,
(microsecFromUnixEpochToY2K%1000000*1000)+(microsecSinceY2K%1000000*1000),
).UTC()
*dst = Timestamp{Time: tim, Status: Present} *dst = Timestamp{Time: tim, Status: Present}
} }

View File

@ -48,6 +48,14 @@ func (dst *Timestamptz) Set(src interface{}) error {
} else { } else {
return dst.Set(*value) return dst.Set(*value)
} }
case string:
return dst.DecodeText(nil, []byte(value))
case *string:
if value == nil {
*dst = Timestamptz{Status: Null}
} else {
return dst.Set(*value)
}
case InfinityModifier: case InfinityModifier:
*dst = Timestamptz{InfinityModifier: value, Status: Present} *dst = Timestamptz{InfinityModifier: value, Status: Present}
default: default:
@ -124,7 +132,7 @@ func (dst *Timestamptz) DecodeText(ci *ConnInfo, src []byte) error {
return err return err
} }
*dst = Timestamptz{Time: tim, Status: Present} *dst = Timestamptz{Time: normalizePotentialUTC(tim), Status: Present}
} }
return nil return nil
@ -148,8 +156,10 @@ func (dst *Timestamptz) DecodeBinary(ci *ConnInfo, src []byte) error {
case negativeInfinityMicrosecondOffset: case negativeInfinityMicrosecondOffset:
*dst = Timestamptz{Status: Present, InfinityModifier: -Infinity} *dst = Timestamptz{Status: Present, InfinityModifier: -Infinity}
default: default:
microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K tim := time.Unix(
tim := time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000) microsecFromUnixEpochToY2K/1000000+microsecSinceY2K/1000000,
(microsecFromUnixEpochToY2K%1000000*1000)+(microsecSinceY2K%1000000*1000),
)
*dst = Timestamptz{Time: tim, Status: Present} *dst = Timestamptz{Time: tim, Status: Present}
} }
@ -229,6 +239,9 @@ func (src Timestamptz) Value() (driver.Value, error) {
if src.InfinityModifier != None { if src.InfinityModifier != None {
return src.InfinityModifier.String(), nil return src.InfinityModifier.String(), nil
} }
if src.Time.Location().String() == time.UTC.String() {
return src.Time.UTC(), nil
}
return src.Time, nil return src.Time, nil
case Null: case Null:
return nil, nil return nil, nil
@ -287,8 +300,23 @@ func (dst *Timestamptz) UnmarshalJSON(b []byte) error {
return err return err
} }
*dst = Timestamptz{Time: tim, Status: Present} *dst = Timestamptz{Time: normalizePotentialUTC(tim), Status: Present}
} }
return nil return nil
} }
// Normalize timestamps in UTC location to behave similarly to how the Golang
// standard library does it: UTC timestamps lack a .loc value.
//
// Reason for this: when comparing two timestamps with reflect.DeepEqual (generally
// speaking not a good idea, but several testing libraries (for example testify)
// does this), their location data needs to be equal for them to be considered
// equal.
func normalizePotentialUTC(timestamp time.Time) time.Time {
if timestamp.Location().String() != time.UTC.String() {
return timestamp
}
return timestamp.UTC()
}

View File

@ -1,5 +1,17 @@
// Code generated by erb. DO NOT EDIT. // Code generated by erb. DO NOT EDIT.
<%
# defaults when not explicitly set on command line
binary_format ||= "true"
text_format ||= "true"
text_null ||= "NULL"
encode_binary ||= binary_format
decode_binary ||= binary_format
%>
package pgtype package pgtype
import ( import (
@ -279,6 +291,7 @@ func (src *<%= pgtype_array_type %>) assignToRecursive(value reflect.Value, inde
return index, nil return index, nil
} }
<% if text_format == "true" %>
func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error { func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil { if src == nil {
*dst = <%= pgtype_array_type %>{Status: Null} *dst = <%= pgtype_array_type %>{Status: Null}
@ -314,8 +327,9 @@ func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error
return nil return nil
} }
<% end %>
<% if binary_format == "true" %> <% if decode_binary == "true" %>
func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) error { func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil { if src == nil {
*dst = <%= pgtype_array_type %>{Status: Null} *dst = <%= pgtype_array_type %>{Status: Null}
@ -359,6 +373,7 @@ func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) erro
} }
<% end %> <% end %>
<% if text_format == "true" %>
func (src <%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) { func (src <%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status { switch src.Status {
case Null: case Null:
@ -415,8 +430,9 @@ func (src <%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte
return buf, nil return buf, nil
} }
<% end %>
<% if binary_format == "true" %> <% if encode_binary == "true" %>
func (src <%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) { func (src <%= pgtype_array_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status { switch src.Status {
case Null: case Null:
@ -462,6 +478,7 @@ func (src <%= pgtype_array_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte
} }
<% end %> <% end %>
<% if text_format == "true" %>
// Scan implements the database/sql Scanner interface. // Scan implements the database/sql Scanner interface.
func (dst *<%= pgtype_array_type %>) Scan(src interface{}) error { func (dst *<%= pgtype_array_type %>) Scan(src interface{}) error {
if src == nil { if src == nil {
@ -492,3 +509,4 @@ func (src <%= pgtype_array_type %>) Value() (driver.Value, error) {
return string(buf), nil return string(buf), nil
} }
<% end %>

View File

@ -1,28 +1,31 @@
erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int2 text_null=NULL binary_format=true typed_array.go.erb > int2_array.go erb pgtype_array_type=Int2Array pgtype_element_type=Int2 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int2 typed_array.go.erb > int2_array.go
erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int4 text_null=NULL binary_format=true typed_array.go.erb > int4_array.go erb pgtype_array_type=Int4Array pgtype_element_type=Int4 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int4 typed_array.go.erb > int4_array.go
erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int8 text_null=NULL binary_format=true typed_array.go.erb > int8_array.go erb pgtype_array_type=Int8Array pgtype_element_type=Int8 go_array_types=[]int16,[]*int16,[]uint16,[]*uint16,[]int32,[]*int32,[]uint32,[]*uint32,[]int64,[]*int64,[]uint64,[]*uint64,[]int,[]*int,[]uint,[]*uint element_type_name=int8 typed_array.go.erb > int8_array.go
erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool,[]*bool element_type_name=bool text_null=NULL binary_format=true typed_array.go.erb > bool_array.go erb pgtype_array_type=BoolArray pgtype_element_type=Bool go_array_types=[]bool,[]*bool element_type_name=bool typed_array.go.erb > bool_array.go
erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time,[]*time.Time element_type_name=date text_null=NULL binary_format=true typed_array.go.erb > date_array.go erb pgtype_array_type=DateArray pgtype_element_type=Date go_array_types=[]time.Time,[]*time.Time element_type_name=date typed_array.go.erb > date_array.go
erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time,[]*time.Time element_type_name=timestamptz text_null=NULL binary_format=true typed_array.go.erb > timestamptz_array.go erb pgtype_array_type=TimestamptzArray pgtype_element_type=Timestamptz go_array_types=[]time.Time,[]*time.Time element_type_name=timestamptz typed_array.go.erb > timestamptz_array.go
erb pgtype_array_type=TstzrangeArray pgtype_element_type=Tstzrange go_array_types=[]Tstzrange element_type_name=tstzrange text_null=NULL binary_format=true typed_array.go.erb > tstzrange_array.go erb pgtype_array_type=TstzrangeArray pgtype_element_type=Tstzrange go_array_types=[]Tstzrange element_type_name=tstzrange typed_array.go.erb > tstzrange_array.go
erb pgtype_array_type=TsrangeArray pgtype_element_type=Tsrange go_array_types=[]Tsrange element_type_name=tsrange text_null=NULL binary_format=true typed_array.go.erb > tsrange_array.go erb pgtype_array_type=TsrangeArray pgtype_element_type=Tsrange go_array_types=[]Tsrange element_type_name=tsrange typed_array.go.erb > tsrange_array.go
erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time,[]*time.Time element_type_name=timestamp text_null=NULL binary_format=true typed_array.go.erb > timestamp_array.go erb pgtype_array_type=TimestampArray pgtype_element_type=Timestamp go_array_types=[]time.Time,[]*time.Time element_type_name=timestamp typed_array.go.erb > timestamp_array.go
erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32,[]*float32 element_type_name=float4 text_null=NULL binary_format=true typed_array.go.erb > float4_array.go erb pgtype_array_type=Float4Array pgtype_element_type=Float4 go_array_types=[]float32,[]*float32 element_type_name=float4 typed_array.go.erb > float4_array.go
erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64,[]*float64 element_type_name=float8 text_null=NULL binary_format=true typed_array.go.erb > float8_array.go erb pgtype_array_type=Float8Array pgtype_element_type=Float8 go_array_types=[]float64,[]*float64 element_type_name=float8 typed_array.go.erb > float8_array.go
erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP,[]*net.IP element_type_name=inet text_null=NULL binary_format=true typed_array.go.erb > inet_array.go erb pgtype_array_type=InetArray pgtype_element_type=Inet go_array_types=[]*net.IPNet,[]net.IP,[]*net.IP element_type_name=inet typed_array.go.erb > inet_array.go
erb pgtype_array_type=MacaddrArray pgtype_element_type=Macaddr go_array_types=[]net.HardwareAddr,[]*net.HardwareAddr element_type_name=macaddr text_null=NULL binary_format=true typed_array.go.erb > macaddr_array.go erb pgtype_array_type=MacaddrArray pgtype_element_type=Macaddr go_array_types=[]net.HardwareAddr,[]*net.HardwareAddr element_type_name=macaddr typed_array.go.erb > macaddr_array.go
erb pgtype_array_type=CIDRArray pgtype_element_type=CIDR go_array_types=[]*net.IPNet,[]net.IP,[]*net.IP element_type_name=cidr text_null=NULL binary_format=true typed_array.go.erb > cidr_array.go erb pgtype_array_type=CIDRArray pgtype_element_type=CIDR go_array_types=[]*net.IPNet,[]net.IP,[]*net.IP element_type_name=cidr typed_array.go.erb > cidr_array.go
erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string,[]*string element_type_name=text text_null=NULL binary_format=true typed_array.go.erb > text_array.go erb pgtype_array_type=TextArray pgtype_element_type=Text go_array_types=[]string,[]*string element_type_name=text typed_array.go.erb > text_array.go
erb pgtype_array_type=VarcharArray pgtype_element_type=Varchar go_array_types=[]string,[]*string element_type_name=varchar text_null=NULL binary_format=true typed_array.go.erb > varchar_array.go erb pgtype_array_type=VarcharArray pgtype_element_type=Varchar go_array_types=[]string,[]*string element_type_name=varchar typed_array.go.erb > varchar_array.go
erb pgtype_array_type=BPCharArray pgtype_element_type=BPChar go_array_types=[]string,[]*string element_type_name=bpchar text_null=NULL binary_format=true typed_array.go.erb > bpchar_array.go erb pgtype_array_type=BPCharArray pgtype_element_type=BPChar go_array_types=[]string,[]*string element_type_name=bpchar typed_array.go.erb > bpchar_array.go
erb pgtype_array_type=ByteaArray pgtype_element_type=Bytea go_array_types=[][]byte element_type_name=bytea text_null=NULL binary_format=true typed_array.go.erb > bytea_array.go erb pgtype_array_type=ByteaArray pgtype_element_type=Bytea go_array_types=[][]byte element_type_name=bytea typed_array.go.erb > bytea_array.go
erb pgtype_array_type=ACLItemArray pgtype_element_type=ACLItem go_array_types=[]string,[]*string element_type_name=aclitem text_null=NULL binary_format=false typed_array.go.erb > aclitem_array.go erb pgtype_array_type=ACLItemArray pgtype_element_type=ACLItem go_array_types=[]string,[]*string element_type_name=aclitem binary_format=false typed_array.go.erb > aclitem_array.go
erb pgtype_array_type=HstoreArray pgtype_element_type=Hstore go_array_types=[]map[string]string element_type_name=hstore text_null=NULL binary_format=true typed_array.go.erb > hstore_array.go erb pgtype_array_type=HstoreArray pgtype_element_type=Hstore go_array_types=[]map[string]string element_type_name=hstore typed_array.go.erb > hstore_array.go
erb pgtype_array_type=NumericArray pgtype_element_type=Numeric go_array_types=[]float32,[]*float32,[]float64,[]*float64,[]int64,[]*int64,[]uint64,[]*uint64 element_type_name=numeric text_null=NULL binary_format=true typed_array.go.erb > numeric_array.go erb pgtype_array_type=NumericArray pgtype_element_type=Numeric go_array_types=[]float32,[]*float32,[]float64,[]*float64,[]int64,[]*int64,[]uint64,[]*uint64 element_type_name=numeric typed_array.go.erb > numeric_array.go
erb pgtype_array_type=UUIDArray pgtype_element_type=UUID go_array_types=[][16]byte,[][]byte,[]string,[]*string element_type_name=uuid text_null=NULL binary_format=true typed_array.go.erb > uuid_array.go erb pgtype_array_type=UUIDArray pgtype_element_type=UUID go_array_types=[][16]byte,[][]byte,[]string,[]*string element_type_name=uuid typed_array.go.erb > uuid_array.go
erb pgtype_array_type=JSONBArray pgtype_element_type=JSONB go_array_types=[]string,[][]byte element_type_name=jsonb text_null=NULL binary_format=true typed_array.go.erb > jsonb_array.go erb pgtype_array_type=JSONArray pgtype_element_type=JSON go_array_types=[]string,[][]byte,[]json.RawMessage element_type_name=json typed_array.go.erb > json_array.go
erb pgtype_array_type=JSONBArray pgtype_element_type=JSONB go_array_types=[]string,[][]byte,[]json.RawMessage element_type_name=jsonb typed_array.go.erb > jsonb_array.go
# While the binary format is theoretically possible it is only practical to use the text format. # While the binary format is theoretically possible it is only practical to use the text format.
erb pgtype_array_type=EnumArray pgtype_element_type=GenericText go_array_types=[]string,[]*string text_null=NULL binary_format=false typed_array.go.erb > enum_array.go erb pgtype_array_type=EnumArray pgtype_element_type=GenericText go_array_types=[]string,[]*string binary_format=false typed_array.go.erb > enum_array.go
erb pgtype_array_type=RecordArray pgtype_element_type=Record go_array_types=[][]Value element_type_name=record text_null=NULL encode_binary=false text_format=false typed_array.go.erb > record_array.go
goimports -w *_array.go goimports -w *_array.go

View File

@ -0,0 +1,239 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type <%= multirange_type %> struct {
Ranges []<%= range_type %>
Status Status
}
func (dst *<%= multirange_type %>) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = <%= multirange_type %>{Status: Null}
return nil
}
switch value := src.(type) {
case <%= multirange_type %>:
*dst = value
case *<%= multirange_type %>:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []<%= range_type %>:
if value == nil {
*dst = <%= multirange_type %>{Status: Null}
} else if len(value) == 0 {
*dst = <%= multirange_type %>{Status: Present}
} else {
elements := make([]<%= range_type %>, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = <%= multirange_type %>{
Ranges: elements,
Status: Present,
}
}
case []*<%= range_type %>:
if value == nil {
*dst = <%= multirange_type %>{Status: Null}
} else if len(value) == 0 {
*dst = <%= multirange_type %>{Status: Present}
} else {
elements := make([]<%= range_type %>, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = <%= multirange_type %>{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to <%= multirange_type %>", src)
}
return nil
}
func (dst <%= multirange_type %>) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *<%= multirange_type %>) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *<%= multirange_type %>) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = <%= multirange_type %>{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []<%= range_type %>
if len(utmr.Elements) > 0 {
elements = make([]<%= range_type %>, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem <%= range_type %>
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = <%= multirange_type %>{Ranges: elements, Status: Present}
return nil
}
func (dst *<%= multirange_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = <%= multirange_type %>{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = <%= multirange_type %>{Status: Present}
return nil
}
elements := make([]<%= range_type %>, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = <%= multirange_type %>{Ranges: elements, Status: Present}
return nil
}
func (src <%= multirange_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src <%= multirange_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *<%= multirange_type %>) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src <%= multirange_type %>) Value() (driver.Value, error) {
return EncodeValueText(src)
}

View File

@ -0,0 +1,8 @@
erb range_type=Numrange multirange_type=Nummultirange typed_multirange.go.erb > num_multirange.go
erb range_type=Int4range multirange_type=Int4multirange typed_multirange.go.erb > int4_multirange.go
erb range_type=Int8range multirange_type=Int8multirange typed_multirange.go.erb > int8_multirange.go
# TODO
# erb range_type=Tsrange multirange_type=Tsmultirange typed_multirange.go.erb > ts_multirange.go
# erb range_type=Tstzrange multirange_type=Tstzmultirange typed_multirange.go.erb > tstz_multirange.go
# erb range_type=Daterange multirange_type=Datemultirange typed_multirange.go.erb > date_multirange.go
goimports -w *multirange.go

Some files were not shown because too many files have changed in this diff Show More