summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc
diff options
context:
space:
mode:
authorLibravatar tobi <31960611+tsmethurst@users.noreply.github.com>2021-08-25 15:34:33 +0200
committerLibravatar GitHub <noreply@github.com>2021-08-25 15:34:33 +0200
commit2dc9fc1626507bb54417fc4a1920b847cafb27a2 (patch)
tree4ddeac479b923db38090aac8bd9209f3646851c1 /vendor/github.com/jackc
parentManually approves followers (#146) (diff)
downloadgotosocial-2dc9fc1626507bb54417fc4a1920b847cafb27a2.tar.xz
Pg to bun (#148)
* start moving to bun * changing more stuff * more * and yet more * tests passing * seems stable now * more big changes * small fix * little fixes
Diffstat (limited to 'vendor/github.com/jackc')
-rw-r--r--vendor/github.com/jackc/chunkreader/v2/.travis.yml9
-rw-r--r--vendor/github.com/jackc/chunkreader/v2/LICENSE22
-rw-r--r--vendor/github.com/jackc/chunkreader/v2/README.md8
-rw-r--r--vendor/github.com/jackc/chunkreader/v2/chunkreader.go104
-rw-r--r--vendor/github.com/jackc/chunkreader/v2/go.mod3
-rw-r--r--vendor/github.com/jackc/pgconn/.gitignore3
-rw-r--r--vendor/github.com/jackc/pgconn/CHANGELOG.md122
-rw-r--r--vendor/github.com/jackc/pgconn/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgconn/README.md56
-rw-r--r--vendor/github.com/jackc/pgconn/auth_scram.go266
-rw-r--r--vendor/github.com/jackc/pgconn/config.go729
-rw-r--r--vendor/github.com/jackc/pgconn/defaults.go64
-rw-r--r--vendor/github.com/jackc/pgconn/defaults_windows.go59
-rw-r--r--vendor/github.com/jackc/pgconn/doc.go29
-rw-r--r--vendor/github.com/jackc/pgconn/errors.go221
-rw-r--r--vendor/github.com/jackc/pgconn/go.mod15
-rw-r--r--vendor/github.com/jackc/pgconn/go.sum130
-rw-r--r--vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go64
-rw-r--r--vendor/github.com/jackc/pgconn/pgconn.go1724
-rw-r--r--vendor/github.com/jackc/pgconn/stmtcache/lru.go157
-rw-r--r--vendor/github.com/jackc/pgconn/stmtcache/stmtcache.go58
-rw-r--r--vendor/github.com/jackc/pgio/.travis.yml9
-rw-r--r--vendor/github.com/jackc/pgio/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgio/README.md11
-rw-r--r--vendor/github.com/jackc/pgio/doc.go6
-rw-r--r--vendor/github.com/jackc/pgio/go.mod3
-rw-r--r--vendor/github.com/jackc/pgio/write.go40
-rw-r--r--vendor/github.com/jackc/pgpassfile/.travis.yml9
-rw-r--r--vendor/github.com/jackc/pgpassfile/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgpassfile/README.md8
-rw-r--r--vendor/github.com/jackc/pgpassfile/go.mod5
-rw-r--r--vendor/github.com/jackc/pgpassfile/go.sum7
-rw-r--r--vendor/github.com/jackc/pgpassfile/pgpass.go110
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/.travis.yml9
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/README.md12
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_cleartext_password.go52
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_md5_password.go77
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_ok.go52
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_sasl.go75
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_sasl_continue.go81
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/authentication_sasl_final.go81
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/backend.go204
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/backend_key_data.go51
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/big_endian.go37
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/bind.go216
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/bind_complete.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/cancel_request.go58
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/chunkreader.go19
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/close.go89
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/close_complete.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/command_complete.go71
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_both_response.go95
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_data.go62
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_done.go38
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_fail.go53
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_in_response.go96
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/copy_out_response.go96
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/data_row.go142
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/describe.go88
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/doc.go4
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/empty_query_response.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/error_response.go334
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/execute.go65
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/flush.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/frontend.go201
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/function_call_response.go101
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/go.mod9
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/go.sum14
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/gss_enc_request.go49
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/no_data.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/notice_response.go17
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/notification_response.go73
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/parameter_description.go66
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/parameter_status.go66
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/parse.go88
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/parse_complete.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/password_message.go54
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/pgproto3.go65
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/portal_suspended.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/query.go50
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/ready_for_query.go61
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/row_description.go165
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go94
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/sasl_response.go61
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/ssl_request.go49
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/startup_message.go96
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/sync.go34
-rw-r--r--vendor/github.com/jackc/pgproto3/v2/terminate.go34
-rw-r--r--vendor/github.com/jackc/pgservicefile/.travis.yml9
-rw-r--r--vendor/github.com/jackc/pgservicefile/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgservicefile/README.md6
-rw-r--r--vendor/github.com/jackc/pgservicefile/go.mod5
-rw-r--r--vendor/github.com/jackc/pgservicefile/go.sum10
-rw-r--r--vendor/github.com/jackc/pgservicefile/pgservicefile.go79
-rw-r--r--vendor/github.com/jackc/pgtype/.travis.yml34
-rw-r--r--vendor/github.com/jackc/pgtype/CHANGELOG.md103
-rw-r--r--vendor/github.com/jackc/pgtype/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgtype/README.md8
-rw-r--r--vendor/github.com/jackc/pgtype/aclitem.go138
-rw-r--r--vendor/github.com/jackc/pgtype/aclitem_array.go428
-rw-r--r--vendor/github.com/jackc/pgtype/array.go381
-rw-r--r--vendor/github.com/jackc/pgtype/array_type.go353
-rw-r--r--vendor/github.com/jackc/pgtype/bit.go45
-rw-r--r--vendor/github.com/jackc/pgtype/bool.go217
-rw-r--r--vendor/github.com/jackc/pgtype/bool_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/box.go165
-rw-r--r--vendor/github.com/jackc/pgtype/bpchar.go76
-rw-r--r--vendor/github.com/jackc/pgtype/bpchar_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/bytea.go163
-rw-r--r--vendor/github.com/jackc/pgtype/bytea_array.go489
-rw-r--r--vendor/github.com/jackc/pgtype/cid.go61
-rw-r--r--vendor/github.com/jackc/pgtype/cidr.go31
-rw-r--r--vendor/github.com/jackc/pgtype/cidr_array.go546
-rw-r--r--vendor/github.com/jackc/pgtype/circle.go150
-rw-r--r--vendor/github.com/jackc/pgtype/composite_fields.go107
-rw-r--r--vendor/github.com/jackc/pgtype/composite_type.go682
-rw-r--r--vendor/github.com/jackc/pgtype/convert.go472
-rw-r--r--vendor/github.com/jackc/pgtype/database_sql.go41
-rw-r--r--vendor/github.com/jackc/pgtype/date.go287
-rw-r--r--vendor/github.com/jackc/pgtype/date_array.go518
-rw-r--r--vendor/github.com/jackc/pgtype/daterange.go267
-rw-r--r--vendor/github.com/jackc/pgtype/enum_array.go428
-rw-r--r--vendor/github.com/jackc/pgtype/enum_type.go168
-rw-r--r--vendor/github.com/jackc/pgtype/float4.go282
-rw-r--r--vendor/github.com/jackc/pgtype/float4_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/float8.go272
-rw-r--r--vendor/github.com/jackc/pgtype/float8_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/generic_binary.go39
-rw-r--r--vendor/github.com/jackc/pgtype/generic_text.go39
-rw-r--r--vendor/github.com/jackc/pgtype/go.mod13
-rw-r--r--vendor/github.com/jackc/pgtype/go.sum175
-rw-r--r--vendor/github.com/jackc/pgtype/hstore.go439
-rw-r--r--vendor/github.com/jackc/pgtype/hstore_array.go489
-rw-r--r--vendor/github.com/jackc/pgtype/inet.go250
-rw-r--r--vendor/github.com/jackc/pgtype/inet_array.go546
-rw-r--r--vendor/github.com/jackc/pgtype/int2.go304
-rw-r--r--vendor/github.com/jackc/pgtype/int2_array.go909
-rw-r--r--vendor/github.com/jackc/pgtype/int4.go312
-rw-r--r--vendor/github.com/jackc/pgtype/int4_array.go909
-rw-r--r--vendor/github.com/jackc/pgtype/int4range.go267
-rw-r--r--vendor/github.com/jackc/pgtype/int8.go298
-rw-r--r--vendor/github.com/jackc/pgtype/int8_array.go909
-rw-r--r--vendor/github.com/jackc/pgtype/int8range.go267
-rw-r--r--vendor/github.com/jackc/pgtype/interval.go257
-rw-r--r--vendor/github.com/jackc/pgtype/json.go205
-rw-r--r--vendor/github.com/jackc/pgtype/jsonb.go85
-rw-r--r--vendor/github.com/jackc/pgtype/jsonb_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/line.go148
-rw-r--r--vendor/github.com/jackc/pgtype/lseg.go165
-rw-r--r--vendor/github.com/jackc/pgtype/macaddr.go173
-rw-r--r--vendor/github.com/jackc/pgtype/macaddr_array.go518
-rw-r--r--vendor/github.com/jackc/pgtype/name.go58
-rw-r--r--vendor/github.com/jackc/pgtype/numeric.go716
-rw-r--r--vendor/github.com/jackc/pgtype/numeric_array.go685
-rw-r--r--vendor/github.com/jackc/pgtype/numrange.go267
-rw-r--r--vendor/github.com/jackc/pgtype/oid.go81
-rw-r--r--vendor/github.com/jackc/pgtype/oid_value.go55
-rw-r--r--vendor/github.com/jackc/pgtype/path.go195
-rw-r--r--vendor/github.com/jackc/pgtype/pgtype.go940
-rw-r--r--vendor/github.com/jackc/pgtype/pguint32.go162
-rw-r--r--vendor/github.com/jackc/pgtype/point.go214
-rw-r--r--vendor/github.com/jackc/pgtype/polygon.go226
-rw-r--r--vendor/github.com/jackc/pgtype/qchar.go152
-rw-r--r--vendor/github.com/jackc/pgtype/range.go277
-rw-r--r--vendor/github.com/jackc/pgtype/record.go126
-rw-r--r--vendor/github.com/jackc/pgtype/text.go182
-rw-r--r--vendor/github.com/jackc/pgtype/text_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/tid.go156
-rw-r--r--vendor/github.com/jackc/pgtype/time.go231
-rw-r--r--vendor/github.com/jackc/pgtype/timestamp.go241
-rw-r--r--vendor/github.com/jackc/pgtype/timestamp_array.go518
-rw-r--r--vendor/github.com/jackc/pgtype/timestamptz.go294
-rw-r--r--vendor/github.com/jackc/pgtype/timestamptz_array.go518
-rw-r--r--vendor/github.com/jackc/pgtype/tsrange.go267
-rw-r--r--vendor/github.com/jackc/pgtype/tsrange_array.go470
-rw-r--r--vendor/github.com/jackc/pgtype/tstzrange.go267
-rw-r--r--vendor/github.com/jackc/pgtype/tstzrange_array.go470
-rw-r--r--vendor/github.com/jackc/pgtype/typed_array.go.erb494
-rw-r--r--vendor/github.com/jackc/pgtype/typed_array_gen.sh28
-rw-r--r--vendor/github.com/jackc/pgtype/typed_range.go.erb269
-rw-r--r--vendor/github.com/jackc/pgtype/typed_range_gen.sh7
-rw-r--r--vendor/github.com/jackc/pgtype/unknown.go44
-rw-r--r--vendor/github.com/jackc/pgtype/uuid.go230
-rw-r--r--vendor/github.com/jackc/pgtype/uuid_array.go573
-rw-r--r--vendor/github.com/jackc/pgtype/varbit.go133
-rw-r--r--vendor/github.com/jackc/pgtype/varchar.go66
-rw-r--r--vendor/github.com/jackc/pgtype/varchar_array.go517
-rw-r--r--vendor/github.com/jackc/pgtype/xid.go64
-rw-r--r--vendor/github.com/jackc/pgx/v4/.gitignore24
-rw-r--r--vendor/github.com/jackc/pgx/v4/CHANGELOG.md209
-rw-r--r--vendor/github.com/jackc/pgx/v4/LICENSE22
-rw-r--r--vendor/github.com/jackc/pgx/v4/README.md203
-rw-r--r--vendor/github.com/jackc/pgx/v4/batch.go179
-rw-r--r--vendor/github.com/jackc/pgx/v4/conn.go850
-rw-r--r--vendor/github.com/jackc/pgx/v4/copy_from.go211
-rw-r--r--vendor/github.com/jackc/pgx/v4/doc.go340
-rw-r--r--vendor/github.com/jackc/pgx/v4/extended_query_builder.go168
-rw-r--r--vendor/github.com/jackc/pgx/v4/go.mod21
-rw-r--r--vendor/github.com/jackc/pgx/v4/go.sum196
-rw-r--r--vendor/github.com/jackc/pgx/v4/go_stdlib.go61
-rw-r--r--vendor/github.com/jackc/pgx/v4/internal/sanitize/sanitize.go304
-rw-r--r--vendor/github.com/jackc/pgx/v4/large_objects.go121
-rw-r--r--vendor/github.com/jackc/pgx/v4/logger.go98
-rw-r--r--vendor/github.com/jackc/pgx/v4/messages.go23
-rw-r--r--vendor/github.com/jackc/pgx/v4/rows.go347
-rw-r--r--vendor/github.com/jackc/pgx/v4/stdlib/sql.go858
-rw-r--r--vendor/github.com/jackc/pgx/v4/tx.go444
-rw-r--r--vendor/github.com/jackc/pgx/v4/values.go280
209 files changed, 41116 insertions, 0 deletions
diff --git a/vendor/github.com/jackc/chunkreader/v2/.travis.yml b/vendor/github.com/jackc/chunkreader/v2/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/chunkreader/v2/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.x
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/jackc/chunkreader/v2/LICENSE b/vendor/github.com/jackc/chunkreader/v2/LICENSE
new file mode 100644
index 000000000..c1c4f50fc
--- /dev/null
+++ b/vendor/github.com/jackc/chunkreader/v2/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/chunkreader/v2/README.md b/vendor/github.com/jackc/chunkreader/v2/README.md
new file mode 100644
index 000000000..01209bfa2
--- /dev/null
+++ b/vendor/github.com/jackc/chunkreader/v2/README.md
@@ -0,0 +1,8 @@
+[![](https://godoc.org/github.com/jackc/chunkreader?status.svg)](https://godoc.org/github.com/jackc/chunkreader)
+[![Build Status](https://travis-ci.org/jackc/chunkreader.svg)](https://travis-ci.org/jackc/chunkreader)
+
+# chunkreader
+
+Package chunkreader provides an io.Reader wrapper that minimizes IO reads and memory allocations.
+
+Extracted from original implementation in https://github.com/jackc/pgx.
diff --git a/vendor/github.com/jackc/chunkreader/v2/chunkreader.go b/vendor/github.com/jackc/chunkreader/v2/chunkreader.go
new file mode 100644
index 000000000..afea1c520
--- /dev/null
+++ b/vendor/github.com/jackc/chunkreader/v2/chunkreader.go
@@ -0,0 +1,104 @@
+// Package chunkreader provides an io.Reader wrapper that minimizes IO reads and memory allocations.
+package chunkreader
+
+import (
+ "io"
+)
+
+// ChunkReader is a io.Reader wrapper that minimizes IO reads and memory allocations. It allocates memory in chunks and
+// will read as much as will fit in the current buffer in a single call regardless of how large a read is actually
+// requested. The memory returned via Next is owned by the caller. This avoids the need for an additional copy.
+//
+// The downside of this approach is that a large buffer can be pinned in memory even if only a small slice is
+// referenced. For example, an entire 4096 byte block could be pinned in memory by even a 1 byte slice. In these rare
+// cases it would be advantageous to copy the bytes to another slice.
+type ChunkReader struct {
+ r io.Reader
+
+ buf []byte
+ rp, wp int // buf read position and write position
+
+ config Config
+}
+
+// Config contains configuration parameters for ChunkReader.
+type Config struct {
+ MinBufLen int // Minimum buffer length
+}
+
+// New creates and returns a new ChunkReader for r with default configuration.
+func New(r io.Reader) *ChunkReader {
+ cr, err := NewConfig(r, Config{})
+ if err != nil {
+ panic("default config can't be bad")
+ }
+
+ return cr
+}
+
+// NewConfig creates and a new ChunkReader for r configured by config.
+func NewConfig(r io.Reader, config Config) (*ChunkReader, error) {
+ if config.MinBufLen == 0 {
+ // By historical reasons Postgres currently has 8KB send buffer inside,
+ // so here we want to have at least the same size buffer.
+ // @see https://github.com/postgres/postgres/blob/249d64999615802752940e017ee5166e726bc7cd/src/backend/libpq/pqcomm.c#L134
+ // @see https://www.postgresql.org/message-id/0cdc5485-cb3c-5e16-4a46-e3b2f7a41322%40ya.ru
+ config.MinBufLen = 8192
+ }
+
+ return &ChunkReader{
+ r: r,
+ buf: make([]byte, config.MinBufLen),
+ config: config,
+ }, nil
+}
+
+// Next returns buf filled with the next n bytes. The caller gains ownership of buf. It is not necessary to make a copy
+// of buf. If an error occurs, buf will be nil.
+func (r *ChunkReader) Next(n int) (buf []byte, err error) {
+ // n bytes already in buf
+ if (r.wp - r.rp) >= n {
+ buf = r.buf[r.rp : r.rp+n]
+ r.rp += n
+ return buf, err
+ }
+
+ // available space in buf is less than n
+ if len(r.buf) < n {
+ r.copyBufContents(r.newBuf(n))
+ }
+
+ // buf is large enough, but need to shift filled area to start to make enough contiguous space
+ minReadCount := n - (r.wp - r.rp)
+ if (len(r.buf) - r.wp) < minReadCount {
+ newBuf := r.newBuf(n)
+ r.copyBufContents(newBuf)
+ }
+
+ if err := r.appendAtLeast(minReadCount); err != nil {
+ return nil, err
+ }
+
+ buf = r.buf[r.rp : r.rp+n]
+ r.rp += n
+ return buf, nil
+}
+
+func (r *ChunkReader) appendAtLeast(fillLen int) error {
+ n, err := io.ReadAtLeast(r.r, r.buf[r.wp:], fillLen)
+ r.wp += n
+ return err
+}
+
+func (r *ChunkReader) newBuf(size int) []byte {
+ if size < r.config.MinBufLen {
+ size = r.config.MinBufLen
+ }
+ return make([]byte, size)
+}
+
+func (r *ChunkReader) copyBufContents(dest []byte) {
+ r.wp = copy(dest, r.buf[r.rp:r.wp])
+ r.rp = 0
+ r.buf = dest
+}
diff --git a/vendor/github.com/jackc/chunkreader/v2/go.mod b/vendor/github.com/jackc/chunkreader/v2/go.mod
new file mode 100644
index 000000000..a1384b407
--- /dev/null
+++ b/vendor/github.com/jackc/chunkreader/v2/go.mod
@@ -0,0 +1,3 @@
+module github.com/jackc/chunkreader/v2
+
+go 1.12
diff --git a/vendor/github.com/jackc/pgconn/.gitignore b/vendor/github.com/jackc/pgconn/.gitignore
new file mode 100644
index 000000000..e980f5555
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/.gitignore
@@ -0,0 +1,3 @@
+.envrc
+vendor/
+.vscode
diff --git a/vendor/github.com/jackc/pgconn/CHANGELOG.md b/vendor/github.com/jackc/pgconn/CHANGELOG.md
new file mode 100644
index 000000000..45c02f1e9
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/CHANGELOG.md
@@ -0,0 +1,122 @@
+# 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)
+
+* pgconn.Timeout only is true for errors originating in pgconn (Michael Darr)
+* Add defaults for sslcert, sslkey, and sslrootcert (Joshua Brindle)
+* Solve issue with 'sslmode=verify-full' when there are multiple hosts (mgoddard)
+* Fix default host when parsing URL without host but with port
+* Allow dbname query parameter in URL conn string
+* Update underlying dependencies
+
+# 1.8.1 (March 25, 2021)
+
+* Better connection string sanitization (ip.novikov)
+* Use proper pgpass location on Windows (Moshe Katz)
+* Use errors instead of golang.org/x/xerrors
+* Resume fallback on server error in Connect (Andrey Borodin)
+
+# 1.8.0 (December 3, 2020)
+
+* Add StatementErrored method to stmtcache.Cache. This allows the cache to purge invalidated prepared statements. (Ethan Pailes)
+
+# 1.7.2 (November 3, 2020)
+
+* Fix data value slices into work buffer with capacities larger than length.
+
+# 1.7.1 (October 31, 2020)
+
+* Do not asyncClose after receiving FATAL error from PostgreSQL server
+
+# 1.7.0 (September 26, 2020)
+
+* Exec(Params|Prepared) return ResultReader with FieldDescriptions loaded
+* Add ReceiveResults (Sebastiaan Mannem)
+* Fix parsing DSN connection with bad backslash
+* Add PgConn.CleanupDone so connection pools can determine when async close is complete
+
+# 1.6.4 (July 29, 2020)
+
+* Fix deadlock on error after CommandComplete but before ReadyForQuery
+* Fix panic on parsing DSN with trailing '='
+
+# 1.6.3 (July 22, 2020)
+
+* Fix error message after AppendCertsFromPEM failure (vahid-sohrabloo)
+
+# 1.6.2 (July 14, 2020)
+
+* Update pgservicefile library
+
+# 1.6.1 (June 27, 2020)
+
+* Update golang.org/x/crypto to latest
+* Update golang.org/x/text to 0.3.3
+* Fix error handling for bad PGSERVICE definition
+* Redact passwords in ParseConfig errors (Lukas Vogel)
+
+# 1.6.0 (June 6, 2020)
+
+* Fix panic when closing conn during cancellable query
+* Fix behavior of sslmode=require with sslrootcert present (Petr Jediný)
+* Fix field descriptions available after command concluded (Tobias Salzmann)
+* Support connect_timeout (georgysavva)
+* Handle IPv6 in connection URLs (Lukas Vogel)
+* Fix ValidateConnect with cancelable context
+* Improve CopyFrom performance
+* Add Config.Copy (georgysavva)
+
+# 1.5.0 (March 30, 2020)
+
+* Update golang.org/x/crypto for security fix
+* Implement "verify-ca" SSL mode (Greg Curtis)
+
+# 1.4.0 (March 7, 2020)
+
+* Fix ExecParams and ExecPrepared handling of empty query.
+* Support reading config from PostgreSQL service files.
+
+# 1.3.2 (February 14, 2020)
+
+* Update chunkreader to v2.0.1 for optimized default buffer size.
+
+# 1.3.1 (February 5, 2020)
+
+* Fix CopyFrom deadlock when multiple NoticeResponse received during copy
+
+# 1.3.0 (January 23, 2020)
+
+* Add Hijack and Construct.
+* Update pgproto3 to v2.0.1.
+
+# 1.2.1 (January 13, 2020)
+
+* Fix data race in context cancellation introduced in v1.2.0.
+
+# 1.2.0 (January 11, 2020)
+
+## Features
+
+* Add Insert(), Update(), Delete(), and Select() statement type query methods to CommandTag.
+* Add PgError.SQLState method. This could be used for compatibility with other drivers and databases.
+
+## Performance
+
+* Improve performance when context.Background() is used. (bakape)
+* CommandTag.RowsAffected is faster and does not allocate.
+
+## Fixes
+
+* Try to cancel any in-progress query when a conn is closed by ctx cancel.
+* Handle NoticeResponse during CopyFrom.
+* Ignore errors sending Terminate message while closing connection. This mimics the behavior of libpq PGfinish.
+
+# 1.1.0 (October 12, 2019)
+
+* Add PgConn.IsBusy() method.
+
+# 1.0.1 (September 19, 2019)
+
+* Fix statement cache not properly cleaning discarded statements.
diff --git a/vendor/github.com/jackc/pgconn/LICENSE b/vendor/github.com/jackc/pgconn/LICENSE
new file mode 100644
index 000000000..aebadd6c4
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019-2021 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgconn/README.md b/vendor/github.com/jackc/pgconn/README.md
new file mode 100644
index 000000000..1c698a118
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/README.md
@@ -0,0 +1,56 @@
+[![](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)
+
+# pgconn
+
+Package pgconn is a low-level PostgreSQL database driver. It operates at nearly the same level as the C library libpq.
+It is primarily intended to serve as the foundation for higher level libraries such as https://github.com/jackc/pgx.
+Applications should handle normal queries with a higher level library and only use pgconn directly when required for
+low-level access to PostgreSQL functionality.
+
+## Example Usage
+
+```go
+pgConn, err := pgconn.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+if err != nil {
+ log.Fatalln("pgconn failed to connect:", err)
+}
+defer pgConn.Close(context.Background())
+
+result := pgConn.ExecParams(context.Background(), "SELECT email FROM users WHERE id=$1", [][]byte{[]byte("123")}, nil, nil, nil)
+for result.NextRow() {
+ fmt.Println("User 123 has email:", string(result.Values()[0]))
+}
+_, err = result.Close()
+if err != nil {
+ log.Fatalln("failed reading result:", err)
+}
+```
+
+## Testing
+
+The pgconn tests require a PostgreSQL database. It will connect to the database specified in the `PGX_TEST_CONN_STRING`
+environment variable. The `PGX_TEST_CONN_STRING` environment variable can be a URL or DSN. In addition, the standard `PG*`
+environment variables will be respected. Consider using [direnv](https://github.com/direnv/direnv) to simplify
+environment variable handling.
+
+### Example Test Environment
+
+Connect to your PostgreSQL server and run:
+
+```
+create database pgx_test;
+```
+
+Now you can run the tests:
+
+```bash
+PGX_TEST_CONN_STRING="host=/var/run/postgresql dbname=pgx_test" go test ./...
+```
+
+### Connection and Authentication Tests
+
+Pgconn supports multiple connection types and means of authentication. These tests are optional. They
+will only run if the appropriate environment variable is set. Run `go test -v | grep SKIP` to see if any tests are being
+skipped. Most developers will not need to enable these tests. See `ci/setup_test.bash` for an example set up if you need change
+authentication code.
diff --git a/vendor/github.com/jackc/pgconn/auth_scram.go b/vendor/github.com/jackc/pgconn/auth_scram.go
new file mode 100644
index 000000000..6a143fcdc
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/auth_scram.go
@@ -0,0 +1,266 @@
+// SCRAM-SHA-256 authentication
+//
+// Resources:
+// https://tools.ietf.org/html/rfc5802
+// https://tools.ietf.org/html/rfc8265
+// https://www.postgresql.org/docs/current/sasl-authentication.html
+//
+// Inspiration drawn from other implementations:
+// https://github.com/lib/pq/pull/608
+// https://github.com/lib/pq/pull/788
+// https://github.com/lib/pq/pull/833
+
+package pgconn
+
+import (
+ "bytes"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "strconv"
+
+ "github.com/jackc/pgproto3/v2"
+ "golang.org/x/crypto/pbkdf2"
+ "golang.org/x/text/secure/precis"
+)
+
+const clientNonceLen = 18
+
+// Perform SCRAM authentication.
+func (c *PgConn) scramAuth(serverAuthMechanisms []string) error {
+ sc, err := newScramClient(serverAuthMechanisms, c.config.Password)
+ if err != nil {
+ return err
+ }
+
+ // Send client-first-message in a SASLInitialResponse
+ saslInitialResponse := &pgproto3.SASLInitialResponse{
+ AuthMechanism: "SCRAM-SHA-256",
+ Data: sc.clientFirstMessage(),
+ }
+ _, err = c.conn.Write(saslInitialResponse.Encode(nil))
+ if err != nil {
+ return err
+ }
+
+ // Receive server-first-message payload in a AuthenticationSASLContinue.
+ saslContinue, err := c.rxSASLContinue()
+ if err != nil {
+ return err
+ }
+ err = sc.recvServerFirstMessage(saslContinue.Data)
+ if err != nil {
+ return err
+ }
+
+ // Send client-final-message in a SASLResponse
+ saslResponse := &pgproto3.SASLResponse{
+ Data: []byte(sc.clientFinalMessage()),
+ }
+ _, err = c.conn.Write(saslResponse.Encode(nil))
+ if err != nil {
+ return err
+ }
+
+ // Receive server-final-message payload in a AuthenticationSASLFinal.
+ saslFinal, err := c.rxSASLFinal()
+ if err != nil {
+ return err
+ }
+ return sc.recvServerFinalMessage(saslFinal.Data)
+}
+
+func (c *PgConn) rxSASLContinue() (*pgproto3.AuthenticationSASLContinue, error) {
+ msg, err := c.receiveMessage()
+ if err != nil {
+ return nil, err
+ }
+ saslContinue, ok := msg.(*pgproto3.AuthenticationSASLContinue)
+ if ok {
+ return saslContinue, nil
+ }
+
+ return nil, errors.New("expected AuthenticationSASLContinue message but received unexpected message")
+}
+
+func (c *PgConn) rxSASLFinal() (*pgproto3.AuthenticationSASLFinal, error) {
+ msg, err := c.receiveMessage()
+ if err != nil {
+ return nil, err
+ }
+ saslFinal, ok := msg.(*pgproto3.AuthenticationSASLFinal)
+ if ok {
+ return saslFinal, nil
+ }
+
+ return nil, errors.New("expected AuthenticationSASLFinal message but received unexpected message")
+}
+
+type scramClient struct {
+ serverAuthMechanisms []string
+ password []byte
+ clientNonce []byte
+
+ clientFirstMessageBare []byte
+
+ serverFirstMessage []byte
+ clientAndServerNonce []byte
+ salt []byte
+ iterations int
+
+ saltedPassword []byte
+ authMessage []byte
+}
+
+func newScramClient(serverAuthMechanisms []string, password string) (*scramClient, error) {
+ sc := &scramClient{
+ serverAuthMechanisms: serverAuthMechanisms,
+ }
+
+ // Ensure server supports SCRAM-SHA-256
+ hasScramSHA256 := false
+ for _, mech := range sc.serverAuthMechanisms {
+ if mech == "SCRAM-SHA-256" {
+ hasScramSHA256 = true
+ break
+ }
+ }
+ if !hasScramSHA256 {
+ return nil, errors.New("server does not support SCRAM-SHA-256")
+ }
+
+ // precis.OpaqueString is equivalent to SASLprep for password.
+ var err error
+ sc.password, err = precis.OpaqueString.Bytes([]byte(password))
+ if err != nil {
+ // PostgreSQL allows passwords invalid according to SCRAM / SASLprep.
+ sc.password = []byte(password)
+ }
+
+ buf := make([]byte, clientNonceLen)
+ _, err = rand.Read(buf)
+ if err != nil {
+ return nil, err
+ }
+ sc.clientNonce = make([]byte, base64.RawStdEncoding.EncodedLen(len(buf)))
+ base64.RawStdEncoding.Encode(sc.clientNonce, buf)
+
+ return sc, nil
+}
+
+func (sc *scramClient) clientFirstMessage() []byte {
+ sc.clientFirstMessageBare = []byte(fmt.Sprintf("n=,r=%s", sc.clientNonce))
+ return []byte(fmt.Sprintf("n,,%s", sc.clientFirstMessageBare))
+}
+
+func (sc *scramClient) recvServerFirstMessage(serverFirstMessage []byte) error {
+ sc.serverFirstMessage = serverFirstMessage
+ buf := serverFirstMessage
+ if !bytes.HasPrefix(buf, []byte("r=")) {
+ return errors.New("invalid SCRAM server-first-message received from server: did not include r=")
+ }
+ buf = buf[2:]
+
+ idx := bytes.IndexByte(buf, ',')
+ if idx == -1 {
+ return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
+ }
+ sc.clientAndServerNonce = buf[:idx]
+ buf = buf[idx+1:]
+
+ if !bytes.HasPrefix(buf, []byte("s=")) {
+ return errors.New("invalid SCRAM server-first-message received from server: did not include s=")
+ }
+ buf = buf[2:]
+
+ idx = bytes.IndexByte(buf, ',')
+ if idx == -1 {
+ return errors.New("invalid SCRAM server-first-message received from server: did not include i=")
+ }
+ saltStr := buf[:idx]
+ buf = buf[idx+1:]
+
+ if !bytes.HasPrefix(buf, []byte("i=")) {
+ return errors.New("invalid SCRAM server-first-message received from server: did not include i=")
+ }
+ buf = buf[2:]
+ iterationsStr := buf
+
+ var err error
+ sc.salt, err = base64.StdEncoding.DecodeString(string(saltStr))
+ if err != nil {
+ return fmt.Errorf("invalid SCRAM salt received from server: %w", err)
+ }
+
+ sc.iterations, err = strconv.Atoi(string(iterationsStr))
+ if err != nil || sc.iterations <= 0 {
+ return fmt.Errorf("invalid SCRAM iteration count received from server: %w", err)
+ }
+
+ if !bytes.HasPrefix(sc.clientAndServerNonce, sc.clientNonce) {
+ return errors.New("invalid SCRAM nonce: did not start with client nonce")
+ }
+
+ if len(sc.clientAndServerNonce) <= len(sc.clientNonce) {
+ return errors.New("invalid SCRAM nonce: did not include server nonce")
+ }
+
+ return nil
+}
+
+func (sc *scramClient) clientFinalMessage() string {
+ clientFinalMessageWithoutProof := []byte(fmt.Sprintf("c=biws,r=%s", sc.clientAndServerNonce))
+
+ sc.saltedPassword = pbkdf2.Key([]byte(sc.password), sc.salt, sc.iterations, 32, sha256.New)
+ sc.authMessage = bytes.Join([][]byte{sc.clientFirstMessageBare, sc.serverFirstMessage, clientFinalMessageWithoutProof}, []byte(","))
+
+ clientProof := computeClientProof(sc.saltedPassword, sc.authMessage)
+
+ return fmt.Sprintf("%s,p=%s", clientFinalMessageWithoutProof, clientProof)
+}
+
+func (sc *scramClient) recvServerFinalMessage(serverFinalMessage []byte) error {
+ if !bytes.HasPrefix(serverFinalMessage, []byte("v=")) {
+ return errors.New("invalid SCRAM server-final-message received from server")
+ }
+
+ serverSignature := serverFinalMessage[2:]
+
+ if !hmac.Equal(serverSignature, computeServerSignature(sc.saltedPassword, sc.authMessage)) {
+ return errors.New("invalid SCRAM ServerSignature received from server")
+ }
+
+ return nil
+}
+
+func computeHMAC(key, msg []byte) []byte {
+ mac := hmac.New(sha256.New, key)
+ mac.Write(msg)
+ return mac.Sum(nil)
+}
+
+func computeClientProof(saltedPassword, authMessage []byte) []byte {
+ clientKey := computeHMAC(saltedPassword, []byte("Client Key"))
+ storedKey := sha256.Sum256(clientKey)
+ clientSignature := computeHMAC(storedKey[:], authMessage)
+
+ clientProof := make([]byte, len(clientSignature))
+ for i := 0; i < len(clientSignature); i++ {
+ clientProof[i] = clientKey[i] ^ clientSignature[i]
+ }
+
+ buf := make([]byte, base64.StdEncoding.EncodedLen(len(clientProof)))
+ base64.StdEncoding.Encode(buf, clientProof)
+ return buf
+}
+
+func computeServerSignature(saltedPassword []byte, authMessage []byte) []byte {
+ serverKey := computeHMAC(saltedPassword, []byte("Server Key"))
+ serverSignature := computeHMAC(serverKey, authMessage)
+ buf := make([]byte, base64.StdEncoding.EncodedLen(len(serverSignature)))
+ base64.StdEncoding.Encode(buf, serverSignature)
+ return buf
+}
diff --git a/vendor/github.com/jackc/pgconn/config.go b/vendor/github.com/jackc/pgconn/config.go
new file mode 100644
index 000000000..172e7478b
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/config.go
@@ -0,0 +1,729 @@
+package pgconn
+
+import (
+ "context"
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "net"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/jackc/chunkreader/v2"
+ "github.com/jackc/pgpassfile"
+ "github.com/jackc/pgproto3/v2"
+ "github.com/jackc/pgservicefile"
+)
+
+type AfterConnectFunc func(ctx context.Context, pgconn *PgConn) error
+type ValidateConnectFunc func(ctx context.Context, pgconn *PgConn) error
+
+// 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.
+type Config struct {
+ Host string // host (e.g. localhost) or absolute path to unix domain socket directory (e.g. /private/tmp)
+ Port uint16
+ Database string
+ User string
+ Password string
+ TLSConfig *tls.Config // nil disables TLS
+ ConnectTimeout time.Duration
+ DialFunc DialFunc // e.g. net.Dialer.DialContext
+ LookupFunc LookupFunc // e.g. net.Resolver.LookupHost
+ BuildFrontend BuildFrontendFunc
+ RuntimeParams map[string]string // Run-time parameters to set on connection as session default values (e.g. search_path or application_name)
+
+ Fallbacks []*FallbackConfig
+
+ // 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
+ // fallback config is tried. This allows implementing high availability behavior such as libpq does with target_session_attrs.
+ ValidateConnect ValidateConnectFunc
+
+ // AfterConnect is called after ValidateConnect. It can be used to set up the connection (e.g. Set session variables
+ // or prepare statements). If this returns an error the connection attempt fails.
+ AfterConnect AfterConnectFunc
+
+ // OnNotice is a callback function called when a notice response is received.
+ OnNotice NoticeHandler
+
+ // OnNotification is a callback function called when a notification from the LISTEN/NOTIFY system is received.
+ OnNotification NotificationHandler
+
+ createdByParseConfig bool // Used to enforce created by ParseConfig rule.
+}
+
+// Copy returns a deep copy of the config that is safe to use and modify.
+// The only exception is the TLSConfig field:
+// according to the tls.Config docs it must not be modified after creation.
+func (c *Config) Copy() *Config {
+ newConf := new(Config)
+ *newConf = *c
+ if newConf.TLSConfig != nil {
+ newConf.TLSConfig = c.TLSConfig.Clone()
+ }
+ if newConf.RuntimeParams != nil {
+ newConf.RuntimeParams = make(map[string]string, len(c.RuntimeParams))
+ for k, v := range c.RuntimeParams {
+ newConf.RuntimeParams[k] = v
+ }
+ }
+ if newConf.Fallbacks != nil {
+ newConf.Fallbacks = make([]*FallbackConfig, len(c.Fallbacks))
+ for i, fallback := range c.Fallbacks {
+ newFallback := new(FallbackConfig)
+ *newFallback = *fallback
+ if newFallback.TLSConfig != nil {
+ newFallback.TLSConfig = fallback.TLSConfig.Clone()
+ }
+ newConf.Fallbacks[i] = newFallback
+ }
+ }
+ return newConf
+}
+
+// FallbackConfig is additional settings to attempt a connection with when the primary Config fails to establish a
+// network connection. It is used for TLS fallback such as sslmode=prefer and high availability (HA) connections.
+type FallbackConfig struct {
+ Host string // host (e.g. localhost) or path to unix domain socket directory (e.g. /private/tmp)
+ Port uint16
+ TLSConfig *tls.Config // nil disables TLS
+}
+
+// NetworkAddress converts a PostgreSQL host and port into network and address suitable for use with
+// net.Dial.
+func NetworkAddress(host string, port uint16) (network, address string) {
+ if strings.HasPrefix(host, "/") {
+ network = "unix"
+ address = filepath.Join(host, ".s.PGSQL.") + strconv.FormatInt(int64(port), 10)
+ } else {
+ network = "tcp"
+ address = net.JoinHostPort(host, strconv.Itoa(int(port)))
+ }
+ return network, address
+}
+
+// ParseConfig builds a *Config with similar behavior to the PostgreSQL standard C library libpq. It uses the same
+// defaults as libpq (e.g. port=5432) and understands most PG* environment variables. ParseConfig closely matches
+// the parsing behavior of libpq. connString may either be in URL format or keyword = value format (DSN style). 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.
+//
+// # Example DSN
+// user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca
+//
+// # Example URL
+// postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca
+//
+// The returned *Config may be modified. However, it is strongly recommended that any configuration that can be done
+// through the connection string be done there. In particular the fields Host, Port, TLSConfig, and Fallbacks can be
+// interdependent (e.g. TLSConfig needs knowledge of the host to validate the server certificate). These fields should
+// not be modified individually. They should all be modified or all left unchanged.
+//
+// ParseConfig supports specifying multiple hosts in similar manner to libpq. Host and port may include comma separated
+// values that will be tried in order. This can be used as part of a high availability system. See
+// https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-MULTIPLE-HOSTS for more information.
+//
+// # Example URL
+// postgres://jack:secret@foo.example.com:5432,bar.example.com:5432/mydb
+//
+// ParseConfig currently recognizes the following environment variable and their parameter key word equivalents passed
+// via database URL or DSN:
+//
+// PGHOST
+// PGPORT
+// PGDATABASE
+// PGUSER
+// PGPASSWORD
+// PGPASSFILE
+// PGSERVICE
+// PGSERVICEFILE
+// PGSSLMODE
+// PGSSLCERT
+// PGSSLKEY
+// PGSSLROOTCERT
+// PGAPPNAME
+// PGCONNECT_TIMEOUT
+// PGTARGETSESSIONATTRS
+//
+// See http://www.postgresql.org/docs/11/static/libpq-envars.html for details on the meaning of environment variables.
+//
+// See https://www.postgresql.org/docs/11/libpq-connect.html#LIBPQ-PARAMKEYWORDS for parameter key word names. They are
+// usually but not always the environment variable name downcased and without the "PG" prefix.
+//
+// Important Security Notes:
+//
+// ParseConfig tries to match libpq behavior with regard to PGSSLMODE. This includes defaulting to "prefer" behavior if
+// not set.
+//
+// See http://www.postgresql.org/docs/11/static/libpq-ssl.html#LIBPQ-SSL-PROTECTION for details on what level of
+// security each sslmode provides.
+//
+// The sslmode "prefer" (the default), sslmode "allow", and multiple hosts are implemented via the Fallbacks field of
+// the Config struct. If TLSConfig is manually changed it will not affect the fallbacks. For example, in the case of
+// 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
+// changed later but the unencrypted fallback is present. Ensure there are no stale fallbacks when manually setting
+// TLCConfig.
+//
+// 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
+// does not.
+//
+// In addition, ParseConfig accepts the following options:
+//
+// min_read_buffer_size
+// The minimum size of the internal read buffer. Default 8192.
+// servicefile
+// libpq only reads servicefile from the PGSERVICEFILE environment variable. ParseConfig accepts servicefile as a
+// part of the connection string.
+func ParseConfig(connString string) (*Config, error) {
+ defaultSettings := defaultSettings()
+ envSettings := parseEnvSettings()
+
+ connStringSettings := make(map[string]string)
+ if connString != "" {
+ var err error
+ // connString may be a database URL or a DSN
+ if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
+ connStringSettings, err = parseURLSettings(connString)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "failed to parse as URL", err: err}
+ }
+ } else {
+ connStringSettings, err = parseDSNSettings(connString)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "failed to parse as DSN", err: err}
+ }
+ }
+ }
+
+ settings := mergeSettings(defaultSettings, envSettings, connStringSettings)
+ if service, present := settings["service"]; present {
+ serviceSettings, err := parseServiceSettings(settings["servicefile"], service)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "failed to read service", err: err}
+ }
+
+ settings = mergeSettings(defaultSettings, envSettings, serviceSettings, connStringSettings)
+ }
+
+ minReadBufferSize, err := strconv.ParseInt(settings["min_read_buffer_size"], 10, 32)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "cannot parse min_read_buffer_size", err: err}
+ }
+
+ config := &Config{
+ createdByParseConfig: true,
+ Database: settings["database"],
+ User: settings["user"],
+ Password: settings["password"],
+ RuntimeParams: make(map[string]string),
+ BuildFrontend: makeDefaultBuildFrontendFunc(int(minReadBufferSize)),
+ }
+
+ if connectTimeoutSetting, present := settings["connect_timeout"]; present {
+ connectTimeout, err := parseConnectTimeoutSetting(connectTimeoutSetting)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "invalid connect_timeout", err: err}
+ }
+ config.ConnectTimeout = connectTimeout
+ config.DialFunc = makeConnectTimeoutDialFunc(connectTimeout)
+ } else {
+ defaultDialer := makeDefaultDialer()
+ config.DialFunc = defaultDialer.DialContext
+ }
+
+ config.LookupFunc = makeDefaultResolver().LookupHost
+
+ notRuntimeParams := map[string]struct{}{
+ "host": struct{}{},
+ "port": struct{}{},
+ "database": struct{}{},
+ "user": struct{}{},
+ "password": struct{}{},
+ "passfile": struct{}{},
+ "connect_timeout": struct{}{},
+ "sslmode": struct{}{},
+ "sslkey": struct{}{},
+ "sslcert": struct{}{},
+ "sslrootcert": struct{}{},
+ "target_session_attrs": struct{}{},
+ "min_read_buffer_size": struct{}{},
+ "service": struct{}{},
+ "servicefile": struct{}{},
+ }
+
+ for k, v := range settings {
+ if _, present := notRuntimeParams[k]; present {
+ continue
+ }
+ config.RuntimeParams[k] = v
+ }
+
+ fallbacks := []*FallbackConfig{}
+
+ hosts := strings.Split(settings["host"], ",")
+ ports := strings.Split(settings["port"], ",")
+
+ for i, host := range hosts {
+ var portStr string
+ if i < len(ports) {
+ portStr = ports[i]
+ } else {
+ portStr = ports[0]
+ }
+
+ port, err := parsePort(portStr)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "invalid port", err: err}
+ }
+
+ var tlsConfigs []*tls.Config
+
+ // Ignore TLS settings if Unix domain socket like libpq
+ if network, _ := NetworkAddress(host, port); network == "unix" {
+ tlsConfigs = append(tlsConfigs, nil)
+ } else {
+ var err error
+ tlsConfigs, err = configTLS(settings, host)
+ if err != nil {
+ return nil, &parseConfigError{connString: connString, msg: "failed to configure TLS", err: err}
+ }
+ }
+
+ for _, tlsConfig := range tlsConfigs {
+ fallbacks = append(fallbacks, &FallbackConfig{
+ Host: host,
+ Port: port,
+ TLSConfig: tlsConfig,
+ })
+ }
+ }
+
+ config.Host = fallbacks[0].Host
+ config.Port = fallbacks[0].Port
+ config.TLSConfig = fallbacks[0].TLSConfig
+ config.Fallbacks = fallbacks[1:]
+
+ passfile, err := pgpassfile.ReadPassfile(settings["passfile"])
+ if err == nil {
+ if config.Password == "" {
+ host := config.Host
+ if network, _ := NetworkAddress(config.Host, config.Port); network == "unix" {
+ host = "localhost"
+ }
+
+ config.Password = passfile.FindPassword(host, strconv.Itoa(int(config.Port)), config.Database, config.User)
+ }
+ }
+
+ if settings["target_session_attrs"] == "read-write" {
+ config.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite
+ } else if settings["target_session_attrs"] != "any" {
+ return nil, &parseConfigError{connString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", settings["target_session_attrs"])}
+ }
+
+ return config, nil
+}
+
+func mergeSettings(settingSets ...map[string]string) map[string]string {
+ settings := make(map[string]string)
+
+ for _, s2 := range settingSets {
+ for k, v := range s2 {
+ settings[k] = v
+ }
+ }
+
+ return settings
+}
+
+func parseEnvSettings() map[string]string {
+ settings := make(map[string]string)
+
+ nameMap := map[string]string{
+ "PGHOST": "host",
+ "PGPORT": "port",
+ "PGDATABASE": "database",
+ "PGUSER": "user",
+ "PGPASSWORD": "password",
+ "PGPASSFILE": "passfile",
+ "PGAPPNAME": "application_name",
+ "PGCONNECT_TIMEOUT": "connect_timeout",
+ "PGSSLMODE": "sslmode",
+ "PGSSLKEY": "sslkey",
+ "PGSSLCERT": "sslcert",
+ "PGSSLROOTCERT": "sslrootcert",
+ "PGTARGETSESSIONATTRS": "target_session_attrs",
+ "PGSERVICE": "service",
+ "PGSERVICEFILE": "servicefile",
+ }
+
+ for envname, realname := range nameMap {
+ value := os.Getenv(envname)
+ if value != "" {
+ settings[realname] = value
+ }
+ }
+
+ return settings
+}
+
+func parseURLSettings(connString string) (map[string]string, error) {
+ settings := make(map[string]string)
+
+ url, err := url.Parse(connString)
+ if err != nil {
+ return nil, err
+ }
+
+ if url.User != nil {
+ settings["user"] = url.User.Username()
+ if password, present := url.User.Password(); present {
+ settings["password"] = password
+ }
+ }
+
+ // Handle multiple host:port's in url.Host by splitting them into host,host,host and port,port,port.
+ var hosts []string
+ var ports []string
+ for _, host := range strings.Split(url.Host, ",") {
+ if host == "" {
+ continue
+ }
+ if isIPOnly(host) {
+ hosts = append(hosts, strings.Trim(host, "[]"))
+ continue
+ }
+ h, p, err := net.SplitHostPort(host)
+ if err != nil {
+ return nil, fmt.Errorf("failed to split host:port in '%s', err: %w", host, err)
+ }
+ if h != "" {
+ hosts = append(hosts, h)
+ }
+ if p != "" {
+ ports = append(ports, p)
+ }
+ }
+ if len(hosts) > 0 {
+ settings["host"] = strings.Join(hosts, ",")
+ }
+ if len(ports) > 0 {
+ settings["port"] = strings.Join(ports, ",")
+ }
+
+ database := strings.TrimLeft(url.Path, "/")
+ if database != "" {
+ settings["database"] = database
+ }
+
+ nameMap := map[string]string{
+ "dbname": "database",
+ }
+
+ for k, v := range url.Query() {
+ if k2, present := nameMap[k]; present {
+ k = k2
+ }
+
+ settings[k] = v[0]
+ }
+
+ return settings, nil
+}
+
+func isIPOnly(host string) bool {
+ return net.ParseIP(strings.Trim(host, "[]")) != nil || !strings.Contains(host, ":")
+}
+
+var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1}
+
+func parseDSNSettings(s string) (map[string]string, error) {
+ settings := make(map[string]string)
+
+ nameMap := map[string]string{
+ "dbname": "database",
+ }
+
+ for len(s) > 0 {
+ var key, val string
+ eqIdx := strings.IndexRune(s, '=')
+ if eqIdx < 0 {
+ return nil, errors.New("invalid dsn")
+ }
+
+ key = strings.Trim(s[:eqIdx], " \t\n\r\v\f")
+ s = strings.TrimLeft(s[eqIdx+1:], " \t\n\r\v\f")
+ if len(s) == 0 {
+ } else if s[0] != '\'' {
+ end := 0
+ for ; end < len(s); end++ {
+ if asciiSpace[s[end]] == 1 {
+ break
+ }
+ if s[end] == '\\' {
+ end++
+ if end == len(s) {
+ return nil, errors.New("invalid backslash")
+ }
+ }
+ }
+ val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
+ if end == len(s) {
+ s = ""
+ } else {
+ s = s[end+1:]
+ }
+ } else { // quoted string
+ s = s[1:]
+ end := 0
+ for ; end < len(s); end++ {
+ if s[end] == '\'' {
+ break
+ }
+ if s[end] == '\\' {
+ end++
+ }
+ }
+ if end == len(s) {
+ return nil, errors.New("unterminated quoted string in connection info string")
+ }
+ val = strings.Replace(strings.Replace(s[:end], "\\\\", "\\", -1), "\\'", "'", -1)
+ if end == len(s) {
+ s = ""
+ } else {
+ s = s[end+1:]
+ }
+ }
+
+ if k, ok := nameMap[key]; ok {
+ key = k
+ }
+
+ if key == "" {
+ return nil, errors.New("invalid dsn")
+ }
+
+ settings[key] = val
+ }
+
+ return settings, nil
+}
+
+func parseServiceSettings(servicefilePath, serviceName string) (map[string]string, error) {
+ servicefile, err := pgservicefile.ReadServicefile(servicefilePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read service file: %v", servicefilePath)
+ }
+
+ service, err := servicefile.GetService(serviceName)
+ if err != nil {
+ return nil, fmt.Errorf("unable to find service: %v", serviceName)
+ }
+
+ nameMap := map[string]string{
+ "dbname": "database",
+ }
+
+ settings := make(map[string]string, len(service.Settings))
+ for k, v := range service.Settings {
+ if k2, present := nameMap[k]; present {
+ k = k2
+ }
+ settings[k] = v
+ }
+
+ return settings, nil
+}
+
+// configTLS uses libpq's TLS parameters to construct []*tls.Config. It is
+// necessary to allow returning multiple TLS configs as sslmode "allow" and
+// "prefer" allow fallback.
+func configTLS(settings map[string]string, thisHost string) ([]*tls.Config, error) {
+ host := thisHost
+ sslmode := settings["sslmode"]
+ sslrootcert := settings["sslrootcert"]
+ sslcert := settings["sslcert"]
+ sslkey := settings["sslkey"]
+
+ // Match libpq default behavior
+ if sslmode == "" {
+ sslmode = "prefer"
+ }
+
+ tlsConfig := &tls.Config{}
+
+ switch sslmode {
+ case "disable":
+ return []*tls.Config{nil}, nil
+ case "allow", "prefer":
+ tlsConfig.InsecureSkipVerify = true
+ case "require":
+ // According to PostgreSQL documentation, if a root CA file exists,
+ // the behavior of sslmode=require should be the same as that of verify-ca
+ //
+ // See https://www.postgresql.org/docs/12/libpq-ssl.html
+ if sslrootcert != "" {
+ goto nextCase
+ }
+ tlsConfig.InsecureSkipVerify = true
+ break
+ nextCase:
+ fallthrough
+ case "verify-ca":
+ // Don't perform the default certificate verification because it
+ // will verify the hostname. Instead, verify the server's
+ // certificate chain ourselves in VerifyPeerCertificate and
+ // ignore the server name. This emulates libpq's verify-ca
+ // behavior.
+ //
+ // See https://github.com/golang/go/issues/21971#issuecomment-332693931
+ // and https://pkg.go.dev/crypto/tls?tab=doc#example-Config-VerifyPeerCertificate
+ // for more info.
+ tlsConfig.InsecureSkipVerify = true
+ tlsConfig.VerifyPeerCertificate = func(certificates [][]byte, _ [][]*x509.Certificate) error {
+ certs := make([]*x509.Certificate, len(certificates))
+ for i, asn1Data := range certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ return errors.New("failed to parse certificate from server: " + err.Error())
+ }
+ certs[i] = cert
+ }
+
+ // Leave DNSName empty to skip hostname verification.
+ opts := x509.VerifyOptions{
+ Roots: tlsConfig.RootCAs,
+ Intermediates: x509.NewCertPool(),
+ }
+ // Skip the first cert because it's the leaf. All others
+ // are intermediates.
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err := certs[0].Verify(opts)
+ return err
+ }
+ case "verify-full":
+ tlsConfig.ServerName = host
+ default:
+ return nil, errors.New("sslmode is invalid")
+ }
+
+ if sslrootcert != "" {
+ caCertPool := x509.NewCertPool()
+
+ caPath := sslrootcert
+ caCert, err := ioutil.ReadFile(caPath)
+ if err != nil {
+ return nil, fmt.Errorf("unable to read CA file: %w", err)
+ }
+
+ if !caCertPool.AppendCertsFromPEM(caCert) {
+ return nil, errors.New("unable to add CA to cert pool")
+ }
+
+ tlsConfig.RootCAs = caCertPool
+ tlsConfig.ClientCAs = caCertPool
+ }
+
+ if (sslcert != "" && sslkey == "") || (sslcert == "" && sslkey != "") {
+ return nil, errors.New(`both "sslcert" and "sslkey" are required`)
+ }
+
+ if sslcert != "" && sslkey != "" {
+ cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
+ if err != nil {
+ return nil, fmt.Errorf("unable to read cert: %w", err)
+ }
+
+ tlsConfig.Certificates = []tls.Certificate{cert}
+ }
+
+ switch sslmode {
+ case "allow":
+ return []*tls.Config{nil, tlsConfig}, nil
+ case "prefer":
+ return []*tls.Config{tlsConfig, nil}, nil
+ case "require", "verify-ca", "verify-full":
+ return []*tls.Config{tlsConfig}, nil
+ default:
+ panic("BUG: bad sslmode should already have been caught")
+ }
+}
+
+func parsePort(s string) (uint16, error) {
+ port, err := strconv.ParseUint(s, 10, 16)
+ if err != nil {
+ return 0, err
+ }
+ if port < 1 || port > math.MaxUint16 {
+ return 0, errors.New("outside range")
+ }
+ return uint16(port), nil
+}
+
+func makeDefaultDialer() *net.Dialer {
+ return &net.Dialer{KeepAlive: 5 * time.Minute}
+}
+
+func makeDefaultResolver() *net.Resolver {
+ return net.DefaultResolver
+}
+
+func makeDefaultBuildFrontendFunc(minBufferLen int) BuildFrontendFunc {
+ return func(r io.Reader, w io.Writer) Frontend {
+ cr, err := chunkreader.NewConfig(r, chunkreader.Config{MinBufLen: minBufferLen})
+ if err != nil {
+ panic(fmt.Sprintf("BUG: chunkreader.NewConfig failed: %v", err))
+ }
+ frontend := pgproto3.NewFrontend(cr, w)
+
+ return frontend
+ }
+}
+
+func parseConnectTimeoutSetting(s string) (time.Duration, error) {
+ timeout, err := strconv.ParseInt(s, 10, 64)
+ if err != nil {
+ return 0, err
+ }
+ if timeout < 0 {
+ return 0, errors.New("negative timeout")
+ }
+ return time.Duration(timeout) * time.Second, nil
+}
+
+func makeConnectTimeoutDialFunc(timeout time.Duration) DialFunc {
+ d := makeDefaultDialer()
+ d.Timeout = timeout
+ return d.DialContext
+}
+
+// ValidateConnectTargetSessionAttrsReadWrite is an ValidateConnectFunc that implements libpq compatible
+// target_session_attrs=read-write.
+func ValidateConnectTargetSessionAttrsReadWrite(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("read only connection")
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgconn/defaults.go b/vendor/github.com/jackc/pgconn/defaults.go
new file mode 100644
index 000000000..f69cad317
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/defaults.go
@@ -0,0 +1,64 @@
+// +build !windows
+
+package pgconn
+
+import (
+ "os"
+ "os/user"
+ "path/filepath"
+)
+
+func defaultSettings() map[string]string {
+ settings := make(map[string]string)
+
+ settings["host"] = defaultHost()
+ settings["port"] = "5432"
+
+ // Default to the OS user name. Purposely ignoring err getting user name from
+ // OS. The client application will simply have to specify the user in that
+ // case (which they typically will be doing anyway).
+ user, err := user.Current()
+ if err == nil {
+ settings["user"] = user.Username
+ settings["passfile"] = filepath.Join(user.HomeDir, ".pgpass")
+ settings["servicefile"] = filepath.Join(user.HomeDir, ".pg_service.conf")
+ sslcert := filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+ sslkey := filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+ if _, err := os.Stat(sslcert); err == nil {
+ if _, err := os.Stat(sslkey); err == nil {
+ // Both the cert and key must be present to use them, or do not use either
+ settings["sslcert"] = sslcert
+ settings["sslkey"] = sslkey
+ }
+ }
+ sslrootcert := filepath.Join(user.HomeDir, ".postgresql", "root.crt")
+ if _, err := os.Stat(sslrootcert); err == nil {
+ settings["sslrootcert"] = sslrootcert
+ }
+ }
+
+ settings["target_session_attrs"] = "any"
+
+ settings["min_read_buffer_size"] = "8192"
+
+ return settings
+}
+
+// defaultHost attempts to mimic libpq's default host. libpq uses the default unix socket location on *nix and localhost
+// on Windows. The default socket location is compiled into libpq. Since pgx does not have access to that default it
+// checks the existence of common locations.
+func defaultHost() string {
+ candidatePaths := []string{
+ "/var/run/postgresql", // Debian
+ "/private/tmp", // OSX - homebrew
+ "/tmp", // standard PostgreSQL
+ }
+
+ for _, path := range candidatePaths {
+ if _, err := os.Stat(path); err == nil {
+ return path
+ }
+ }
+
+ return "localhost"
+}
diff --git a/vendor/github.com/jackc/pgconn/defaults_windows.go b/vendor/github.com/jackc/pgconn/defaults_windows.go
new file mode 100644
index 000000000..71eb77dba
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/defaults_windows.go
@@ -0,0 +1,59 @@
+package pgconn
+
+import (
+ "os"
+ "os/user"
+ "path/filepath"
+ "strings"
+)
+
+func defaultSettings() map[string]string {
+ settings := make(map[string]string)
+
+ settings["host"] = defaultHost()
+ settings["port"] = "5432"
+
+ // Default to the OS user name. Purposely ignoring err getting user name from
+ // OS. The client application will simply have to specify the user in that
+ // case (which they typically will be doing anyway).
+ user, err := user.Current()
+ appData := os.Getenv("APPDATA")
+ if err == nil {
+ // Windows gives us the username here as `DOMAIN\user` or `LOCALPCNAME\user`,
+ // but the libpq default is just the `user` portion, so we strip off the first part.
+ username := user.Username
+ if strings.Contains(username, "\\") {
+ username = username[strings.LastIndex(username, "\\")+1:]
+ }
+
+ settings["user"] = username
+ settings["passfile"] = filepath.Join(appData, "postgresql", "pgpass.conf")
+ settings["servicefile"] = filepath.Join(user.HomeDir, ".pg_service.conf")
+ sslcert := filepath.Join(appData, "postgresql", "postgresql.crt")
+ sslkey := filepath.Join(appData, "postgresql", "postgresql.key")
+ if _, err := os.Stat(sslcert); err == nil {
+ if _, err := os.Stat(sslkey); err == nil {
+ // Both the cert and key must be present to use them, or do not use either
+ settings["sslcert"] = sslcert
+ settings["sslkey"] = sslkey
+ }
+ }
+ sslrootcert := filepath.Join(appData, "postgresql", "root.crt")
+ if _, err := os.Stat(sslrootcert); err == nil {
+ settings["sslrootcert"] = sslrootcert
+ }
+ }
+
+ settings["target_session_attrs"] = "any"
+
+ settings["min_read_buffer_size"] = "8192"
+
+ return settings
+}
+
+// defaultHost attempts to mimic libpq's default host. libpq uses the default unix socket location on *nix and localhost
+// on Windows. The default socket location is compiled into libpq. Since pgx does not have access to that default it
+// checks the existence of common locations.
+func defaultHost() string {
+ return "localhost"
+}
diff --git a/vendor/github.com/jackc/pgconn/doc.go b/vendor/github.com/jackc/pgconn/doc.go
new file mode 100644
index 000000000..cde58cd89
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/doc.go
@@ -0,0 +1,29 @@
+// Package pgconn is a low-level PostgreSQL database driver.
+/*
+pgconn provides lower level access to a PostgreSQL connection than a database/sql or pgx connection. It operates at
+nearly the same level is the C library libpq.
+
+Establishing a Connection
+
+Use Connect to establish a connection. It accepts a connection string in URL or DSN and will read the environment for
+libpq style environment variables.
+
+Executing a Query
+
+ExecParams and ExecPrepared execute a single query. They return readers that iterate over each row. The Read method
+reads all rows into memory.
+
+Executing Multiple Queries in a Single Round Trip
+
+Exec and ExecBatch can execute multiple queries in a single round trip. They return readers that iterate over each query
+result. The ReadAll method reads all query results into memory.
+
+Context Support
+
+All potentially blocking operations take a context.Context. If a context is canceled while the method is in progress the
+method immediately returns. In most circumstances, this will close the underlying connection.
+
+The CancelRequest method may be used to request the PostgreSQL server cancel an in-progress query without forcing the
+client to abort.
+*/
+package pgconn
diff --git a/vendor/github.com/jackc/pgconn/errors.go b/vendor/github.com/jackc/pgconn/errors.go
new file mode 100644
index 000000000..a32b29c92
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/errors.go
@@ -0,0 +1,221 @@
+package pgconn
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "net/url"
+ "regexp"
+ "strings"
+)
+
+// SafeToRetry checks if the err is guaranteed to have occurred before sending any data to the server.
+func SafeToRetry(err error) bool {
+ if e, ok := err.(interface{ SafeToRetry() bool }); ok {
+ return e.SafeToRetry()
+ }
+ return false
+}
+
+// Timeout checks if err was was caused by a timeout. To be specific, it is true if err was caused within pgconn by a
+// context.Canceled, context.DeadlineExceeded or an implementer of net.Error where Timeout() is true.
+func Timeout(err error) bool {
+ var timeoutErr *errTimeout
+ return errors.As(err, &timeoutErr)
+}
+
+// PgError represents an error reported by the PostgreSQL server. See
+// http://www.postgresql.org/docs/11/static/protocol-error-fields.html for
+// detailed field description.
+type PgError struct {
+ Severity string
+ Code string
+ Message string
+ Detail string
+ Hint string
+ Position int32
+ InternalPosition int32
+ InternalQuery string
+ Where string
+ SchemaName string
+ TableName string
+ ColumnName string
+ DataTypeName string
+ ConstraintName string
+ File string
+ Line int32
+ Routine string
+}
+
+func (pe *PgError) Error() string {
+ return pe.Severity + ": " + pe.Message + " (SQLSTATE " + pe.Code + ")"
+}
+
+// SQLState returns the SQLState of the error.
+func (pe *PgError) SQLState() string {
+ return pe.Code
+}
+
+type connectError struct {
+ config *Config
+ msg string
+ err error
+}
+
+func (e *connectError) Error() string {
+ sb := &strings.Builder{}
+ fmt.Fprintf(sb, "failed to connect to `host=%s user=%s database=%s`: %s", e.config.Host, e.config.User, e.config.Database, e.msg)
+ if e.err != nil {
+ fmt.Fprintf(sb, " (%s)", e.err.Error())
+ }
+ return sb.String()
+}
+
+func (e *connectError) Unwrap() error {
+ return e.err
+}
+
+type connLockError struct {
+ status string
+}
+
+func (e *connLockError) SafeToRetry() bool {
+ return true // a lock failure by definition happens before the connection is used.
+}
+
+func (e *connLockError) Error() string {
+ return e.status
+}
+
+type parseConfigError struct {
+ connString string
+ msg string
+ err error
+}
+
+func (e *parseConfigError) Error() string {
+ connString := redactPW(e.connString)
+ if e.err == nil {
+ return fmt.Sprintf("cannot parse `%s`: %s", connString, e.msg)
+ }
+ return fmt.Sprintf("cannot parse `%s`: %s (%s)", connString, e.msg, e.err.Error())
+}
+
+func (e *parseConfigError) Unwrap() error {
+ 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 {
+ msg string
+ err error
+ safeToRetry bool
+}
+
+func (e *pgconnError) Error() string {
+ if e.msg == "" {
+ return e.err.Error()
+ }
+ if e.err == nil {
+ return e.msg
+ }
+ return fmt.Sprintf("%s: %s", e.msg, e.err.Error())
+}
+
+func (e *pgconnError) SafeToRetry() bool {
+ return e.safeToRetry
+}
+
+func (e *pgconnError) Unwrap() error {
+ return e.err
+}
+
+// errTimeout occurs when an error was caused by a timeout. Specifically, it wraps an error which is
+// context.Canceled, context.DeadlineExceeded, or an implementer of net.Error where Timeout() is true.
+type errTimeout struct {
+ err error
+}
+
+func (e *errTimeout) Error() string {
+ return fmt.Sprintf("timeout: %s", e.err.Error())
+}
+
+func (e *errTimeout) SafeToRetry() bool {
+ return SafeToRetry(e.err)
+}
+
+func (e *errTimeout) Unwrap() error {
+ return e.err
+}
+
+type contextAlreadyDoneError struct {
+ err error
+}
+
+func (e *contextAlreadyDoneError) Error() string {
+ return fmt.Sprintf("context already done: %s", e.err.Error())
+}
+
+func (e *contextAlreadyDoneError) SafeToRetry() bool {
+ return true
+}
+
+func (e *contextAlreadyDoneError) Unwrap() error {
+ return e.err
+}
+
+// newContextAlreadyDoneError double-wraps a context error in `contextAlreadyDoneError` and `errTimeout`.
+func newContextAlreadyDoneError(ctx context.Context) (err error) {
+ return &errTimeout{&contextAlreadyDoneError{err: ctx.Err()}}
+}
+
+type writeError struct {
+ err error
+ safeToRetry bool
+}
+
+func (e *writeError) Error() string {
+ return fmt.Sprintf("write failed: %s", e.err.Error())
+}
+
+func (e *writeError) SafeToRetry() bool {
+ return e.safeToRetry
+}
+
+func (e *writeError) Unwrap() error {
+ return e.err
+}
+
+func redactPW(connString string) string {
+ if strings.HasPrefix(connString, "postgres://") || strings.HasPrefix(connString, "postgresql://") {
+ if u, err := url.Parse(connString); err == nil {
+ return redactURL(u)
+ }
+ }
+ quotedDSN := regexp.MustCompile(`password='[^']*'`)
+ connString = quotedDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
+ plainDSN := regexp.MustCompile(`password=[^ ]*`)
+ connString = plainDSN.ReplaceAllLiteralString(connString, "password=xxxxx")
+ brokenURL := regexp.MustCompile(`:[^:@]+?@`)
+ connString = brokenURL.ReplaceAllLiteralString(connString, ":xxxxxx@")
+ return connString
+}
+
+func redactURL(u *url.URL) string {
+ if u == nil {
+ return ""
+ }
+ if _, pwSet := u.User.Password(); pwSet {
+ u.User = url.UserPassword(u.User.Username(), "xxxxx")
+ }
+ return u.String()
+}
diff --git a/vendor/github.com/jackc/pgconn/go.mod b/vendor/github.com/jackc/pgconn/go.mod
new file mode 100644
index 000000000..6fdd0e979
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/go.mod
@@ -0,0 +1,15 @@
+module github.com/jackc/pgconn
+
+go 1.12
+
+require (
+ github.com/jackc/chunkreader/v2 v2.0.1
+ github.com/jackc/pgio v1.0.0
+ github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65
+ github.com/jackc/pgpassfile v1.0.0
+ github.com/jackc/pgproto3/v2 v2.1.1
+ github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b
+ github.com/stretchr/testify v1.7.0
+ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
+ golang.org/x/text v0.3.6
+)
diff --git a/vendor/github.com/jackc/pgconn/go.sum b/vendor/github.com/jackc/pgconn/go.sum
new file mode 100644
index 000000000..3c77ee21b
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/go.sum
@@ -0,0 +1,130 @@
+github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
+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.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+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/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+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/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/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/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/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-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+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-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+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/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go b/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go
new file mode 100644
index 000000000..391f0b791
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go
@@ -0,0 +1,64 @@
+package ctxwatch
+
+import (
+ "context"
+)
+
+// ContextWatcher watches a context and performs an action when the context is canceled. It can watch one context at a
+// time.
+type ContextWatcher struct {
+ onCancel func()
+ onUnwatchAfterCancel func()
+ unwatchChan chan struct{}
+ watchInProgress bool
+ onCancelWasCalled bool
+}
+
+// NewContextWatcher returns a ContextWatcher. onCancel will be called when a watched context is canceled.
+// OnUnwatchAfterCancel will be called when Unwatch is called and the watched context had already been canceled and
+// onCancel called.
+func NewContextWatcher(onCancel func(), onUnwatchAfterCancel func()) *ContextWatcher {
+ cw := &ContextWatcher{
+ onCancel: onCancel,
+ onUnwatchAfterCancel: onUnwatchAfterCancel,
+ unwatchChan: make(chan struct{}),
+ }
+
+ return cw
+}
+
+// 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) {
+ if cw.watchInProgress {
+ panic("Watch already in progress")
+ }
+
+ cw.onCancelWasCalled = false
+
+ if ctx.Done() != nil {
+ cw.watchInProgress = true
+ go func() {
+ select {
+ case <-ctx.Done():
+ cw.onCancel()
+ cw.onCancelWasCalled = true
+ <-cw.unwatchChan
+ case <-cw.unwatchChan:
+ }
+ }()
+ } else {
+ cw.watchInProgress = false
+ }
+}
+
+// Unwatch stops watching the previously watched context. If the onCancel function passed to NewContextWatcher was
+// called then onUnwatchAfterCancel will also be called.
+func (cw *ContextWatcher) Unwatch() {
+ if cw.watchInProgress {
+ cw.unwatchChan <- struct{}{}
+ if cw.onCancelWasCalled {
+ cw.onUnwatchAfterCancel()
+ }
+ cw.watchInProgress = false
+ }
+}
diff --git a/vendor/github.com/jackc/pgconn/pgconn.go b/vendor/github.com/jackc/pgconn/pgconn.go
new file mode 100644
index 000000000..43b13e43a
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/pgconn.go
@@ -0,0 +1,1724 @@
+package pgconn
+
+import (
+ "context"
+ "crypto/md5"
+ "crypto/tls"
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "net"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/jackc/pgconn/internal/ctxwatch"
+ "github.com/jackc/pgio"
+ "github.com/jackc/pgproto3/v2"
+)
+
+const (
+ connStatusUninitialized = iota
+ connStatusConnecting
+ connStatusClosed
+ connStatusIdle
+ connStatusBusy
+)
+
+const wbufLen = 1024
+
+// Notice represents a notice response message reported by the PostgreSQL server. Be aware that this is distinct from
+// LISTEN/NOTIFY notification.
+type Notice PgError
+
+// Notification is a message received from the PostgreSQL LISTEN/NOTIFY system
+type Notification struct {
+ PID uint32 // backend pid that sent the notification
+ Channel string // channel from which notification was received
+ Payload string
+}
+
+// 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)
+
+// LookupFunc is a function that can be used to lookup IPs addrs from host.
+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.
+type BuildFrontendFunc func(r io.Reader, w io.Writer) Frontend
+
+// NoticeHandler is a function that can handle notices received from the PostgreSQL server. Notices can be received at
+// any time, usually during handling of a query response. The *PgConn is provided so the handler is aware of the origin
+// of the notice, but it must not invoke any query method. Be aware that this is distinct from LISTEN/NOTIFY
+// notification.
+type NoticeHandler func(*PgConn, *Notice)
+
+// NotificationHandler is a function that can handle notifications received from the PostgreSQL server. Notifications
+// can be received at any time, usually during handling of a query response. The *PgConn is provided so the handler is
+// aware of the origin of the notice, but it must not invoke any query method. Be aware that this is distinct from a
+// notice event.
+type NotificationHandler func(*PgConn, *Notification)
+
+// Frontend used to receive messages from backend.
+type Frontend interface {
+ Receive() (pgproto3.BackendMessage, error)
+}
+
+// PgConn is a low-level PostgreSQL connection handle. It is not safe for concurrent usage.
+type PgConn struct {
+ conn net.Conn // the underlying TCP or unix domain socket connection
+ pid uint32 // backend pid
+ secretKey uint32 // key to use to send a cancel query message to the server
+ parameterStatuses map[string]string // parameters that have been reported by the server
+ txStatus byte
+ frontend Frontend
+
+ config *Config
+
+ status byte // One of connStatus* constants
+
+ bufferingReceive bool
+ bufferingReceiveMux sync.Mutex
+ bufferingReceiveMsg pgproto3.BackendMessage
+ bufferingReceiveErr error
+
+ peekedMsg pgproto3.BackendMessage
+
+ // Reusable / preallocated resources
+ wbuf []byte // write buffer
+ resultReader ResultReader
+ multiResultReader MultiResultReader
+ contextWatcher *ctxwatch.ContextWatcher
+
+ cleanupDone chan struct{}
+}
+
+// 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.
+func Connect(ctx context.Context, connString string) (*PgConn, error) {
+ config, err := ParseConfig(connString)
+ 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
+// ParseConfig. ctx can be used to cancel a connect attempt.
+//
+// If config.Fallbacks are present they will sequentially be tried in case of error establishing network connection. An
+// 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,
+// if all attempts fail the last error is returned.
+func ConnectConfig(ctx context.Context, config *Config) (pgConn *PgConn, err error) {
+ // Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
+ // zero values.
+ if !config.createdByParseConfig {
+ 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.
+ fallbackConfigs := []*FallbackConfig{
+ {
+ Host: config.Host,
+ Port: config.Port,
+ TLSConfig: config.TLSConfig,
+ },
+ }
+ fallbackConfigs = append(fallbackConfigs, config.Fallbacks...)
+
+ fallbackConfigs, err = expandWithIPs(ctx, config.LookupFunc, fallbackConfigs)
+ if err != nil {
+ return nil, &connectError{config: config, msg: "hostname resolving error", err: err}
+ }
+
+ if len(fallbackConfigs) == 0 {
+ return nil, &connectError{config: config, msg: "hostname resolving error", err: errors.New("ip addr wasn't found")}
+ }
+
+ for _, fc := range fallbackConfigs {
+ pgConn, err = connect(ctx, config, fc)
+ if err == nil {
+ break
+ } else if pgerr, ok := err.(*PgError); ok {
+ err = &connectError{config: config, msg: "server error", err: pgerr}
+ ERRCODE_INVALID_PASSWORD := "28P01" // worng password
+ ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION := "28000" // db does not exist
+ if pgerr.Code == ERRCODE_INVALID_PASSWORD || pgerr.Code == ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION {
+ break
+ }
+ }
+ }
+
+ if err != nil {
+ return nil, err // no need to wrap in connectError because it will already be wrapped in all cases except PgError
+ }
+
+ if config.AfterConnect != nil {
+ err := config.AfterConnect(ctx, pgConn)
+ if err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "AfterConnect error", err: err}
+ }
+ }
+
+ return pgConn, nil
+}
+
+func expandWithIPs(ctx context.Context, lookupFn LookupFunc, fallbacks []*FallbackConfig) ([]*FallbackConfig, error) {
+ var configs []*FallbackConfig
+
+ for _, fb := range fallbacks {
+ // skip resolve for unix sockets
+ if strings.HasPrefix(fb.Host, "/") {
+ configs = append(configs, &FallbackConfig{
+ Host: fb.Host,
+ Port: fb.Port,
+ TLSConfig: fb.TLSConfig,
+ })
+
+ continue
+ }
+
+ ips, err := lookupFn(ctx, fb.Host)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, ip := range ips {
+ configs = append(configs, &FallbackConfig{
+ Host: ip,
+ Port: fb.Port,
+ TLSConfig: fb.TLSConfig,
+ })
+ }
+ }
+
+ return configs, nil
+}
+
+func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig) (*PgConn, error) {
+ pgConn := new(PgConn)
+ pgConn.config = config
+ pgConn.wbuf = make([]byte, 0, wbufLen)
+ pgConn.cleanupDone = make(chan struct{})
+
+ var err error
+ network, address := NetworkAddress(fallbackConfig.Host, fallbackConfig.Port)
+ pgConn.conn, err = config.DialFunc(ctx, network, address)
+ if err != nil {
+ var netErr net.Error
+ if errors.As(err, &netErr) && netErr.Timeout() {
+ err = &errTimeout{err: err}
+ }
+ return nil, &connectError{config: config, msg: "dial error", err: err}
+ }
+
+ pgConn.parameterStatuses = make(map[string]string)
+
+ if fallbackConfig.TLSConfig != nil {
+ if err := pgConn.startTLS(fallbackConfig.TLSConfig); err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "tls error", err: err}
+ }
+ }
+
+ 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()
+
+ pgConn.frontend = config.BuildFrontend(pgConn.conn, pgConn.conn)
+
+ startupMsg := pgproto3.StartupMessage{
+ ProtocolVersion: pgproto3.ProtocolVersionNumber,
+ Parameters: make(map[string]string),
+ }
+
+ // Copy default run-time params
+ for k, v := range config.RuntimeParams {
+ startupMsg.Parameters[k] = v
+ }
+
+ startupMsg.Parameters["user"] = config.User
+ if config.Database != "" {
+ startupMsg.Parameters["database"] = config.Database
+ }
+
+ if _, err := pgConn.conn.Write(startupMsg.Encode(pgConn.wbuf)); err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "failed to write startup message", err: err}
+ }
+
+ for {
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ pgConn.conn.Close()
+ if err, ok := err.(*PgError); ok {
+ return nil, err
+ }
+ return nil, &connectError{config: config, msg: "failed to receive message", err: preferContextOverNetTimeoutError(ctx, err)}
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.BackendKeyData:
+ pgConn.pid = msg.ProcessID
+ pgConn.secretKey = msg.SecretKey
+
+ case *pgproto3.AuthenticationOk:
+ case *pgproto3.AuthenticationCleartextPassword:
+ err = pgConn.txPasswordMessage(pgConn.config.Password)
+ if err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "failed to write password message", err: err}
+ }
+ case *pgproto3.AuthenticationMD5Password:
+ digestedPassword := "md5" + hexMD5(hexMD5(pgConn.config.Password+pgConn.config.User)+string(msg.Salt[:]))
+ err = pgConn.txPasswordMessage(digestedPassword)
+ if err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "failed to write password message", err: err}
+ }
+ case *pgproto3.AuthenticationSASL:
+ err = pgConn.scramAuth(msg.AuthMechanisms)
+ if err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "failed SASL auth", err: err}
+ }
+
+ case *pgproto3.ReadyForQuery:
+ pgConn.status = connStatusIdle
+ if config.ValidateConnect != nil {
+ // ValidateConnect may execute commands that cause the context to be watched again. Unwatch first to avoid
+ // the watch already in progress panic. This is that last thing done by this method so there is no need to
+ // restart the watch after ValidateConnect returns.
+ //
+ // See https://github.com/jackc/pgconn/issues/40.
+ pgConn.contextWatcher.Unwatch()
+
+ err := config.ValidateConnect(ctx, pgConn)
+ if err != nil {
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "ValidateConnect failed", err: err}
+ }
+ }
+ return pgConn, nil
+ case *pgproto3.ParameterStatus:
+ // handled by ReceiveMessage
+ case *pgproto3.ErrorResponse:
+ pgConn.conn.Close()
+ return nil, ErrorResponseToPgError(msg)
+ default:
+ pgConn.conn.Close()
+ return nil, &connectError{config: config, msg: "received unexpected message", err: err}
+ }
+ }
+}
+
+func (pgConn *PgConn) startTLS(tlsConfig *tls.Config) (err error) {
+ err = binary.Write(pgConn.conn, binary.BigEndian, []int32{8, 80877103})
+ if err != nil {
+ return
+ }
+
+ response := make([]byte, 1)
+ if _, err = io.ReadFull(pgConn.conn, response); err != nil {
+ return
+ }
+
+ if response[0] != 'S' {
+ return errors.New("server refused TLS connection")
+ }
+
+ pgConn.conn = tls.Client(pgConn.conn, tlsConfig)
+
+ return nil
+}
+
+func (pgConn *PgConn) txPasswordMessage(password string) (err error) {
+ msg := &pgproto3.PasswordMessage{Password: password}
+ _, err = pgConn.conn.Write(msg.Encode(pgConn.wbuf))
+ return err
+}
+
+func hexMD5(s string) string {
+ hash := md5.New()
+ io.WriteString(hash, s)
+ return hex.EncodeToString(hash.Sum(nil))
+}
+
+func (pgConn *PgConn) signalMessage() chan struct{} {
+ if pgConn.bufferingReceive {
+ panic("BUG: signalMessage when already in progress")
+ }
+
+ pgConn.bufferingReceive = true
+ pgConn.bufferingReceiveMux.Lock()
+
+ ch := make(chan struct{})
+ go func() {
+ pgConn.bufferingReceiveMsg, pgConn.bufferingReceiveErr = pgConn.frontend.Receive()
+ pgConn.bufferingReceiveMux.Unlock()
+ close(ch)
+ }()
+
+ return ch
+}
+
+// SendBytes sends buf to the PostgreSQL server. It must only be used when the connection is not busy. e.g. It is as
+// error to call SendBytes while reading the result of a query.
+//
+// This is a very low level method that requires deep understanding of the PostgreSQL wire protocol to use correctly.
+// See https://www.postgresql.org/docs/current/protocol.html.
+func (pgConn *PgConn) SendBytes(ctx context.Context, buf []byte) error {
+ if err := pgConn.lock(); err != nil {
+ return err
+ }
+ defer pgConn.unlock()
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ return newContextAlreadyDoneError(ctx)
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ return &writeError{err: err, safeToRetry: n == 0}
+ }
+
+ return nil
+}
+
+// ReceiveMessage receives one wire protocol message from the PostgreSQL server. It must only be used when the
+// connection is not busy. e.g. It is an error to call ReceiveMessage while reading the result of a query. The messages
+// are still handled by the core pgconn message handling system so receiving a NotificationResponse will still trigger
+// the OnNotification callback.
+//
+// This is a very low level method that requires deep understanding of the PostgreSQL wire protocol to use correctly.
+// See https://www.postgresql.org/docs/current/protocol.html.
+func (pgConn *PgConn) ReceiveMessage(ctx context.Context) (pgproto3.BackendMessage, error) {
+ if err := pgConn.lock(); err != nil {
+ return nil, err
+ }
+ defer pgConn.unlock()
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ return nil, newContextAlreadyDoneError(ctx)
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ err = &pgconnError{
+ msg: "receive message failed",
+ err: preferContextOverNetTimeoutError(ctx, err),
+ safeToRetry: true}
+ }
+ return msg, err
+}
+
+// peekMessage peeks at the next message without setting up context cancellation.
+func (pgConn *PgConn) peekMessage() (pgproto3.BackendMessage, error) {
+ if pgConn.peekedMsg != nil {
+ return pgConn.peekedMsg, nil
+ }
+
+ var msg pgproto3.BackendMessage
+ var err error
+ if pgConn.bufferingReceive {
+ pgConn.bufferingReceiveMux.Lock()
+ msg = pgConn.bufferingReceiveMsg
+ err = pgConn.bufferingReceiveErr
+ pgConn.bufferingReceiveMux.Unlock()
+ pgConn.bufferingReceive = false
+
+ // If a timeout error happened in the background try the read again.
+ var netErr net.Error
+ if errors.As(err, &netErr) && netErr.Timeout() {
+ msg, err = pgConn.frontend.Receive()
+ }
+ } else {
+ msg, err = pgConn.frontend.Receive()
+ }
+
+ if err != nil {
+ // Close on anything other than timeout error - everything else is fatal
+ var netErr net.Error
+ isNetErr := errors.As(err, &netErr)
+ if !(isNetErr && netErr.Timeout()) {
+ pgConn.asyncClose()
+ }
+
+ return nil, err
+ }
+
+ pgConn.peekedMsg = msg
+ return msg, nil
+}
+
+// receiveMessage receives a message without setting up context cancellation
+func (pgConn *PgConn) receiveMessage() (pgproto3.BackendMessage, error) {
+ msg, err := pgConn.peekMessage()
+ if err != nil {
+ // Close on anything other than timeout error - everything else is fatal
+ var netErr net.Error
+ isNetErr := errors.As(err, &netErr)
+ if !(isNetErr && netErr.Timeout()) {
+ pgConn.asyncClose()
+ }
+
+ return nil, err
+ }
+ pgConn.peekedMsg = nil
+
+ switch msg := msg.(type) {
+ case *pgproto3.ReadyForQuery:
+ pgConn.txStatus = msg.TxStatus
+ case *pgproto3.ParameterStatus:
+ pgConn.parameterStatuses[msg.Name] = msg.Value
+ case *pgproto3.ErrorResponse:
+ if msg.Severity == "FATAL" {
+ pgConn.status = connStatusClosed
+ pgConn.conn.Close() // Ignore error as the connection is already broken and there is already an error to return.
+ close(pgConn.cleanupDone)
+ return nil, ErrorResponseToPgError(msg)
+ }
+ case *pgproto3.NoticeResponse:
+ if pgConn.config.OnNotice != nil {
+ pgConn.config.OnNotice(pgConn, noticeResponseToNotice(msg))
+ }
+ case *pgproto3.NotificationResponse:
+ if pgConn.config.OnNotification != nil {
+ pgConn.config.OnNotification(pgConn, &Notification{PID: msg.PID, Channel: msg.Channel, Payload: msg.Payload})
+ }
+ }
+
+ return msg, nil
+}
+
+// Conn returns the underlying net.Conn.
+func (pgConn *PgConn) Conn() net.Conn {
+ return pgConn.conn
+}
+
+// PID returns the backend PID.
+func (pgConn *PgConn) PID() uint32 {
+ return pgConn.pid
+}
+
+// TxStatus returns the current TxStatus as reported by the server in the ReadyForQuery message.
+//
+// Possible return values:
+// 'I' - idle / not in transaction
+// 'T' - in a transaction
+// 'E' - in a failed transaction
+//
+// See https://www.postgresql.org/docs/current/protocol-message-formats.html.
+func (pgConn *PgConn) TxStatus() byte {
+ return pgConn.txStatus
+}
+
+// SecretKey returns the backend secret key used to send a cancel query message to the server.
+func (pgConn *PgConn) SecretKey() uint32 {
+ return pgConn.secretKey
+}
+
+// Close closes a connection. It is safe to call Close on a already closed connection. Close attempts a clean close by
+// sending the exit message to PostgreSQL. However, this could block so ctx is available to limit the time to wait. The
+// underlying net.Conn.Close() will always be called regardless of any other errors.
+func (pgConn *PgConn) Close(ctx context.Context) error {
+ if pgConn.status == connStatusClosed {
+ return nil
+ }
+ pgConn.status = connStatusClosed
+
+ defer close(pgConn.cleanupDone)
+ defer pgConn.conn.Close()
+
+ if ctx != context.Background() {
+ // Close may be called while a cancellable query is in progress. This will most often be triggered by panic when
+ // a defer closes the connection (possibly indirectly via a transaction or a connection pool). Unwatch to end any
+ // previous watch. It is safe to Unwatch regardless of whether a watch is already is progress.
+ //
+ // See https://github.com/jackc/pgconn/issues/29
+ pgConn.contextWatcher.Unwatch()
+
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ // Ignore any errors sending Terminate message and waiting for server to close connection.
+ // This mimics the behavior of libpq PQfinish. It calls closePGconn which calls sendTerminateConn which purposefully
+ // ignores errors.
+ //
+ // See https://github.com/jackc/pgx/issues/637
+ pgConn.conn.Write([]byte{'X', 0, 0, 0, 4})
+ pgConn.conn.Read(make([]byte, 1))
+
+ return pgConn.conn.Close()
+}
+
+// asyncClose marks the connection as closed and asynchronously sends a cancel query message and closes the underlying
+// connection.
+func (pgConn *PgConn) asyncClose() {
+ if pgConn.status == connStatusClosed {
+ return
+ }
+ pgConn.status = connStatusClosed
+
+ go func() {
+ defer close(pgConn.cleanupDone)
+ defer pgConn.conn.Close()
+
+ deadline := time.Now().Add(time.Second * 15)
+
+ ctx, cancel := context.WithDeadline(context.Background(), deadline)
+ defer cancel()
+
+ pgConn.CancelRequest(ctx)
+
+ pgConn.conn.SetDeadline(deadline)
+
+ pgConn.conn.Write([]byte{'X', 0, 0, 0, 4})
+ pgConn.conn.Read(make([]byte, 1))
+ }()
+}
+
+// CleanupDone returns a channel that will be closed after all underlying resources have been cleaned up. A closed
+// connection is no longer usable, but underlying resources, in particular the net.Conn, may not have finished closing
+// yet. This is because certain errors such as a context cancellation require that the interrupted function call return
+// immediately, but the error may also cause the connection to be closed. In these cases the underlying resources are
+// closed asynchronously.
+//
+// This is only likely to be useful to connection pools. It gives them a way avoid establishing a new connection while
+// an old connection is still being cleaned up and thereby exceeding the maximum pool size.
+func (pgConn *PgConn) CleanupDone() chan (struct{}) {
+ return pgConn.cleanupDone
+}
+
+// IsClosed reports if the connection has been closed.
+//
+// CleanupDone() can be used to determine if all cleanup has been completed.
+func (pgConn *PgConn) IsClosed() bool {
+ return pgConn.status < connStatusIdle
+}
+
+// IsBusy reports if the connection is busy.
+func (pgConn *PgConn) IsBusy() bool {
+ return pgConn.status == connStatusBusy
+}
+
+// lock locks the connection.
+func (pgConn *PgConn) lock() error {
+ switch pgConn.status {
+ case connStatusBusy:
+ return &connLockError{status: "conn busy"} // This only should be possible in case of an application bug.
+ case connStatusClosed:
+ return &connLockError{status: "conn closed"}
+ case connStatusUninitialized:
+ return &connLockError{status: "conn uninitialized"}
+ }
+ pgConn.status = connStatusBusy
+ return nil
+}
+
+func (pgConn *PgConn) unlock() {
+ switch pgConn.status {
+ case connStatusBusy:
+ pgConn.status = connStatusIdle
+ case connStatusClosed:
+ default:
+ panic("BUG: cannot unlock unlocked connection") // This should only be possible if there is a bug in this package.
+ }
+}
+
+// ParameterStatus returns the value of a parameter reported by the server (e.g.
+// server_version). Returns an empty string for unknown parameters.
+func (pgConn *PgConn) ParameterStatus(key string) string {
+ return pgConn.parameterStatuses[key]
+}
+
+// CommandTag is the result of an Exec function
+type CommandTag []byte
+
+// RowsAffected returns the number of rows affected. If the CommandTag was not
+// for a row affecting command (e.g. "CREATE TABLE") then it returns 0.
+func (ct CommandTag) RowsAffected() int64 {
+ // Find last non-digit
+ idx := -1
+ for i := len(ct) - 1; i >= 0; i-- {
+ if ct[i] >= '0' && ct[i] <= '9' {
+ idx = i
+ } else {
+ break
+ }
+ }
+
+ if idx == -1 {
+ return 0
+ }
+
+ var n int64
+ for _, b := range ct[idx:] {
+ n = n*10 + int64(b-'0')
+ }
+
+ return n
+}
+
+func (ct CommandTag) String() string {
+ return string(ct)
+}
+
+// Insert is true if the command tag starts with "INSERT".
+func (ct CommandTag) Insert() bool {
+ return len(ct) >= 6 &&
+ ct[0] == 'I' &&
+ ct[1] == 'N' &&
+ ct[2] == 'S' &&
+ ct[3] == 'E' &&
+ ct[4] == 'R' &&
+ ct[5] == 'T'
+}
+
+// Update is true if the command tag starts with "UPDATE".
+func (ct CommandTag) Update() bool {
+ return len(ct) >= 6 &&
+ ct[0] == 'U' &&
+ ct[1] == 'P' &&
+ ct[2] == 'D' &&
+ ct[3] == 'A' &&
+ ct[4] == 'T' &&
+ ct[5] == 'E'
+}
+
+// Delete is true if the command tag starts with "DELETE".
+func (ct CommandTag) Delete() bool {
+ return len(ct) >= 6 &&
+ ct[0] == 'D' &&
+ ct[1] == 'E' &&
+ ct[2] == 'L' &&
+ ct[3] == 'E' &&
+ ct[4] == 'T' &&
+ ct[5] == 'E'
+}
+
+// Select is true if the command tag starts with "SELECT".
+func (ct CommandTag) Select() bool {
+ return len(ct) >= 6 &&
+ ct[0] == 'S' &&
+ ct[1] == 'E' &&
+ ct[2] == 'L' &&
+ ct[3] == 'E' &&
+ ct[4] == 'C' &&
+ ct[5] == 'T'
+}
+
+type StatementDescription struct {
+ Name string
+ SQL string
+ ParamOIDs []uint32
+ Fields []pgproto3.FieldDescription
+}
+
+// Prepare creates a prepared statement. If the name is empty, the anonymous prepared statement will be used. This
+// allows Prepare to also to describe statements without creating a server-side prepared statement.
+func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs []uint32) (*StatementDescription, error) {
+ if err := pgConn.lock(); err != nil {
+ return nil, err
+ }
+ defer pgConn.unlock()
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ return nil, newContextAlreadyDoneError(ctx)
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Parse{Name: name, Query: sql, ParameterOIDs: paramOIDs}).Encode(buf)
+ buf = (&pgproto3.Describe{ObjectType: 'S', Name: name}).Encode(buf)
+ buf = (&pgproto3.Sync{}).Encode(buf)
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, &writeError{err: err, safeToRetry: n == 0}
+ }
+
+ psd := &StatementDescription{Name: name, SQL: sql}
+
+ var parseErr error
+
+readloop:
+ for {
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, preferContextOverNetTimeoutError(ctx, err)
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.ParameterDescription:
+ psd.ParamOIDs = make([]uint32, len(msg.ParameterOIDs))
+ copy(psd.ParamOIDs, msg.ParameterOIDs)
+ case *pgproto3.RowDescription:
+ psd.Fields = make([]pgproto3.FieldDescription, len(msg.Fields))
+ copy(psd.Fields, msg.Fields)
+ case *pgproto3.ErrorResponse:
+ parseErr = ErrorResponseToPgError(msg)
+ case *pgproto3.ReadyForQuery:
+ break readloop
+ }
+ }
+
+ if parseErr != nil {
+ return nil, parseErr
+ }
+ return psd, nil
+}
+
+// ErrorResponseToPgError converts a wire protocol error message to a *PgError.
+func ErrorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError {
+ return &PgError{
+ Severity: msg.Severity,
+ Code: string(msg.Code),
+ Message: string(msg.Message),
+ Detail: string(msg.Detail),
+ Hint: msg.Hint,
+ Position: msg.Position,
+ InternalPosition: msg.InternalPosition,
+ InternalQuery: string(msg.InternalQuery),
+ Where: string(msg.Where),
+ SchemaName: string(msg.SchemaName),
+ TableName: string(msg.TableName),
+ ColumnName: string(msg.ColumnName),
+ DataTypeName: string(msg.DataTypeName),
+ ConstraintName: msg.ConstraintName,
+ File: string(msg.File),
+ Line: msg.Line,
+ Routine: string(msg.Routine),
+ }
+}
+
+func noticeResponseToNotice(msg *pgproto3.NoticeResponse) *Notice {
+ pgerr := ErrorResponseToPgError((*pgproto3.ErrorResponse)(msg))
+ return (*Notice)(pgerr)
+}
+
+// CancelRequest sends a cancel request to the PostgreSQL server. It returns an error if unable to deliver the cancel
+// request, but lack of an error does not ensure that the query was canceled. As specified in the documentation, there
+// is no way to be sure a query was canceled. See https://www.postgresql.org/docs/11/protocol-flow.html#id-1.10.5.7.9
+func (pgConn *PgConn) CancelRequest(ctx context.Context) error {
+ // Open a cancellation request to the same server. The address is taken from the net.Conn directly instead of reusing
+ // the connection config. This is important in high availability configurations where fallback connections may be
+ // specified or DNS may be used to load balance.
+ serverAddr := pgConn.conn.RemoteAddr()
+ cancelConn, err := pgConn.config.DialFunc(ctx, serverAddr.Network(), serverAddr.String())
+ if err != nil {
+ return err
+ }
+ defer cancelConn.Close()
+
+ if ctx != context.Background() {
+ contextWatcher := ctxwatch.NewContextWatcher(
+ func() { cancelConn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) },
+ func() { cancelConn.SetDeadline(time.Time{}) },
+ )
+ contextWatcher.Watch(ctx)
+ defer contextWatcher.Unwatch()
+ }
+
+ buf := make([]byte, 16)
+ binary.BigEndian.PutUint32(buf[0:4], 16)
+ binary.BigEndian.PutUint32(buf[4:8], 80877102)
+ binary.BigEndian.PutUint32(buf[8:12], uint32(pgConn.pid))
+ binary.BigEndian.PutUint32(buf[12:16], uint32(pgConn.secretKey))
+ _, err = cancelConn.Write(buf)
+ if err != nil {
+ return err
+ }
+
+ _, err = cancelConn.Read(buf)
+ if err != io.EOF {
+ return err
+ }
+
+ return nil
+}
+
+// WaitForNotification waits for a LISTON/NOTIFY message to be received. It returns an error if a notification was not
+// received.
+func (pgConn *PgConn) WaitForNotification(ctx context.Context) error {
+ if err := pgConn.lock(); err != nil {
+ return err
+ }
+ defer pgConn.unlock()
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ return newContextAlreadyDoneError(ctx)
+ default:
+ }
+
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ for {
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ return preferContextOverNetTimeoutError(ctx, err)
+ }
+
+ switch msg.(type) {
+ case *pgproto3.NotificationResponse:
+ return nil
+ }
+ }
+}
+
+// Exec executes SQL via the PostgreSQL simple query protocol. SQL may contain multiple queries. Execution is
+// implicitly wrapped in a transaction unless a transaction is already in progress or SQL contains transaction control
+// statements.
+//
+// Prefer ExecParams unless executing arbitrary SQL that may contain multiple queries.
+func (pgConn *PgConn) Exec(ctx context.Context, sql string) *MultiResultReader {
+ if err := pgConn.lock(); err != nil {
+ return &MultiResultReader{
+ closed: true,
+ err: err,
+ }
+ }
+
+ pgConn.multiResultReader = MultiResultReader{
+ pgConn: pgConn,
+ ctx: ctx,
+ }
+ multiResult := &pgConn.multiResultReader
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ multiResult.closed = true
+ multiResult.err = newContextAlreadyDoneError(ctx)
+ pgConn.unlock()
+ return multiResult
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ }
+
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Query{String: sql}).Encode(buf)
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ pgConn.contextWatcher.Unwatch()
+ multiResult.closed = true
+ multiResult.err = &writeError{err: err, safeToRetry: n == 0}
+ pgConn.unlock()
+ return multiResult
+ }
+
+ return multiResult
+}
+
+// ReceiveResults reads the result that might be returned by Postgres after a SendBytes
+// (e.a. after sending a CopyDone in a copy-both situation).
+//
+// This is a very low level method that requires deep understanding of the PostgreSQL wire protocol to use correctly.
+// See https://www.postgresql.org/docs/current/protocol.html.
+func (pgConn *PgConn) ReceiveResults(ctx context.Context) *MultiResultReader {
+ if err := pgConn.lock(); err != nil {
+ return &MultiResultReader{
+ closed: true,
+ err: err,
+ }
+ }
+
+ pgConn.multiResultReader = MultiResultReader{
+ pgConn: pgConn,
+ ctx: ctx,
+ }
+ multiResult := &pgConn.multiResultReader
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ multiResult.closed = true
+ multiResult.err = newContextAlreadyDoneError(ctx)
+ pgConn.unlock()
+ return multiResult
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ }
+
+ return multiResult
+}
+
+// ExecParams executes a command via the PostgreSQL extended query protocol.
+//
+// sql is a SQL command string. It may only contain one query. Parameter substitution is positional using $1, $2, $3,
+// etc.
+//
+// paramValues are the parameter values. It must be encoded in the format given by paramFormats.
+//
+// paramOIDs is a slice of data type OIDs for paramValues. If paramOIDs is nil, the server will infer the data type for
+// all parameters. Any paramOID element that is 0 that will cause the server to infer the data type for that parameter.
+// ExecParams will panic if len(paramOIDs) is not 0, 1, or len(paramValues).
+//
+// paramFormats is a slice of format codes determining for each paramValue column whether it is encoded in text or
+// binary format. If paramFormats is nil all params are text format. ExecParams will panic if
+// len(paramFormats) is not 0, 1, or len(paramValues).
+//
+// resultFormats is a slice of format codes determining for each result column whether it is encoded in text or
+// binary format. If resultFormats is nil all results will be in text format.
+//
+// ResultReader must be closed before PgConn can be used again.
+func (pgConn *PgConn) ExecParams(ctx context.Context, sql string, paramValues [][]byte, paramOIDs []uint32, paramFormats []int16, resultFormats []int16) *ResultReader {
+ result := pgConn.execExtendedPrefix(ctx, paramValues)
+ if result.closed {
+ return result
+ }
+
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(buf)
+ buf = (&pgproto3.Bind{ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf)
+
+ pgConn.execExtendedSuffix(buf, result)
+
+ return result
+}
+
+// ExecPrepared enqueues the execution of a prepared statement via the PostgreSQL extended query protocol.
+//
+// paramValues are the parameter values. It must be encoded in the format given by paramFormats.
+//
+// paramFormats is a slice of format codes determining for each paramValue column whether it is encoded in text or
+// binary format. If paramFormats is nil all params are text format. ExecPrepared will panic if
+// len(paramFormats) is not 0, 1, or len(paramValues).
+//
+// resultFormats is a slice of format codes determining for each result column whether it is encoded in text or
+// binary format. If resultFormats is nil all results will be in text format.
+//
+// ResultReader must be closed before PgConn can be used again.
+func (pgConn *PgConn) ExecPrepared(ctx context.Context, stmtName string, paramValues [][]byte, paramFormats []int16, resultFormats []int16) *ResultReader {
+ result := pgConn.execExtendedPrefix(ctx, paramValues)
+ if result.closed {
+ return result
+ }
+
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(buf)
+
+ pgConn.execExtendedSuffix(buf, result)
+
+ return result
+}
+
+func (pgConn *PgConn) execExtendedPrefix(ctx context.Context, paramValues [][]byte) *ResultReader {
+ pgConn.resultReader = ResultReader{
+ pgConn: pgConn,
+ ctx: ctx,
+ }
+ result := &pgConn.resultReader
+
+ if err := pgConn.lock(); err != nil {
+ result.concludeCommand(nil, err)
+ result.closed = true
+ return result
+ }
+
+ if len(paramValues) > math.MaxUint16 {
+ result.concludeCommand(nil, fmt.Errorf("extended protocol limited to %v parameters", math.MaxUint16))
+ result.closed = true
+ pgConn.unlock()
+ return result
+ }
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ result.concludeCommand(nil, newContextAlreadyDoneError(ctx))
+ result.closed = true
+ pgConn.unlock()
+ return result
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ }
+
+ return result
+}
+
+func (pgConn *PgConn) execExtendedSuffix(buf []byte, result *ResultReader) {
+ buf = (&pgproto3.Describe{ObjectType: 'P'}).Encode(buf)
+ buf = (&pgproto3.Execute{}).Encode(buf)
+ buf = (&pgproto3.Sync{}).Encode(buf)
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ result.concludeCommand(nil, &writeError{err: err, safeToRetry: n == 0})
+ pgConn.contextWatcher.Unwatch()
+ result.closed = true
+ pgConn.unlock()
+ return
+ }
+
+ result.readUntilRowDescription()
+}
+
+// CopyTo executes the copy command sql and copies the results to w.
+func (pgConn *PgConn) CopyTo(ctx context.Context, w io.Writer, sql string) (CommandTag, error) {
+ if err := pgConn.lock(); err != nil {
+ return nil, err
+ }
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ pgConn.unlock()
+ return nil, newContextAlreadyDoneError(ctx)
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ // Send copy to command
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Query{String: sql}).Encode(buf)
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ pgConn.unlock()
+ return nil, &writeError{err: err, safeToRetry: n == 0}
+ }
+
+ // Read results
+ var commandTag CommandTag
+ var pgErr error
+ for {
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, preferContextOverNetTimeoutError(ctx, err)
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.CopyDone:
+ case *pgproto3.CopyData:
+ _, err := w.Write(msg.Data)
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, err
+ }
+ case *pgproto3.ReadyForQuery:
+ pgConn.unlock()
+ return commandTag, pgErr
+ case *pgproto3.CommandComplete:
+ commandTag = CommandTag(msg.CommandTag)
+ case *pgproto3.ErrorResponse:
+ pgErr = ErrorResponseToPgError(msg)
+ }
+ }
+}
+
+// CopyFrom executes the copy command sql and copies all of r to the PostgreSQL server.
+//
+// Note: context cancellation will only interrupt operations on the underlying PostgreSQL network connection. Reads on r
+// could still block.
+func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (CommandTag, error) {
+ if err := pgConn.lock(); err != nil {
+ return nil, err
+ }
+ defer pgConn.unlock()
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ return nil, newContextAlreadyDoneError(ctx)
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ defer pgConn.contextWatcher.Unwatch()
+ }
+
+ // Send copy to command
+ buf := pgConn.wbuf
+ buf = (&pgproto3.Query{String: sql}).Encode(buf)
+
+ n, err := pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ 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, preferContextOverNetTimeoutError(ctx, 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
+ abortCopyChan := make(chan struct{})
+ copyErrChan := make(chan error, 1)
+ signalMessageChan := pgConn.signalMessage()
+
+ go func() {
+ buf := make([]byte, 0, 65536)
+ buf = append(buf, 'd')
+ sp := len(buf)
+
+ for {
+ n, readErr := r.Read(buf[5:cap(buf)])
+ if n > 0 {
+ buf = buf[0 : n+5]
+ pgio.SetInt32(buf[sp:], int32(n+4))
+
+ _, writeErr := pgConn.conn.Write(buf)
+ if writeErr != nil {
+ // Write errors are always fatal, but we can't use asyncClose because we are in a different goroutine.
+ pgConn.conn.Close()
+
+ copyErrChan <- writeErr
+ return
+ }
+ }
+ if readErr != nil {
+ copyErrChan <- readErr
+ return
+ }
+
+ select {
+ case <-abortCopyChan:
+ return
+ default:
+ }
+ }
+ }()
+
+ var copyErr error
+ for copyErr == nil && pgErr == nil {
+ select {
+ case copyErr = <-copyErrChan:
+ case <-signalMessageChan:
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, preferContextOverNetTimeoutError(ctx, err)
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.ErrorResponse:
+ pgErr = ErrorResponseToPgError(msg)
+ default:
+ signalMessageChan = pgConn.signalMessage()
+ }
+ }
+ }
+ close(abortCopyChan)
+
+ buf = buf[:0]
+ if copyErr == io.EOF || pgErr != nil {
+ copyDone := &pgproto3.CopyDone{}
+ buf = copyDone.Encode(buf)
+ } else {
+ copyFail := &pgproto3.CopyFail{Message: copyErr.Error()}
+ buf = copyFail.Encode(buf)
+ }
+ _, err = pgConn.conn.Write(buf)
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, err
+ }
+
+ // Read results
+ for {
+ msg, err := pgConn.receiveMessage()
+ if err != nil {
+ pgConn.asyncClose()
+ return nil, preferContextOverNetTimeoutError(ctx, err)
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.ReadyForQuery:
+ return commandTag, pgErr
+ case *pgproto3.CommandComplete:
+ commandTag = CommandTag(msg.CommandTag)
+ case *pgproto3.ErrorResponse:
+ pgErr = ErrorResponseToPgError(msg)
+ }
+ }
+}
+
+// MultiResultReader is a reader for a command that could return multiple results such as Exec or ExecBatch.
+type MultiResultReader struct {
+ pgConn *PgConn
+ ctx context.Context
+
+ rr *ResultReader
+
+ closed bool
+ err error
+}
+
+// ReadAll reads all available results. Calling ReadAll is mutually exclusive with all other MultiResultReader methods.
+func (mrr *MultiResultReader) ReadAll() ([]*Result, error) {
+ var results []*Result
+
+ for mrr.NextResult() {
+ results = append(results, mrr.ResultReader().Read())
+ }
+ err := mrr.Close()
+
+ return results, err
+}
+
+func (mrr *MultiResultReader) receiveMessage() (pgproto3.BackendMessage, error) {
+ msg, err := mrr.pgConn.receiveMessage()
+
+ if err != nil {
+ mrr.pgConn.contextWatcher.Unwatch()
+ mrr.err = preferContextOverNetTimeoutError(mrr.ctx, err)
+ mrr.closed = true
+ mrr.pgConn.asyncClose()
+ return nil, mrr.err
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.ReadyForQuery:
+ mrr.pgConn.contextWatcher.Unwatch()
+ mrr.closed = true
+ mrr.pgConn.unlock()
+ case *pgproto3.ErrorResponse:
+ mrr.err = ErrorResponseToPgError(msg)
+ }
+
+ return msg, nil
+}
+
+// NextResult returns advances the MultiResultReader to the next result and returns true if a result is available.
+func (mrr *MultiResultReader) NextResult() bool {
+ for !mrr.closed && mrr.err == nil {
+ msg, err := mrr.receiveMessage()
+ if err != nil {
+ return false
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.RowDescription:
+ mrr.pgConn.resultReader = ResultReader{
+ pgConn: mrr.pgConn,
+ multiResultReader: mrr,
+ ctx: mrr.ctx,
+ fieldDescriptions: msg.Fields,
+ }
+ mrr.rr = &mrr.pgConn.resultReader
+ return true
+ case *pgproto3.CommandComplete:
+ mrr.pgConn.resultReader = ResultReader{
+ commandTag: CommandTag(msg.CommandTag),
+ commandConcluded: true,
+ closed: true,
+ }
+ mrr.rr = &mrr.pgConn.resultReader
+ return true
+ case *pgproto3.EmptyQueryResponse:
+ return false
+ }
+ }
+
+ return false
+}
+
+// ResultReader returns the current ResultReader.
+func (mrr *MultiResultReader) ResultReader() *ResultReader {
+ return mrr.rr
+}
+
+// Close closes the MultiResultReader and returns the first error that occurred during the MultiResultReader's use.
+func (mrr *MultiResultReader) Close() error {
+ for !mrr.closed {
+ _, err := mrr.receiveMessage()
+ if err != nil {
+ return mrr.err
+ }
+ }
+
+ return mrr.err
+}
+
+// ResultReader is a reader for the result of a single query.
+type ResultReader struct {
+ pgConn *PgConn
+ multiResultReader *MultiResultReader
+ ctx context.Context
+
+ fieldDescriptions []pgproto3.FieldDescription
+ rowValues [][]byte
+ commandTag CommandTag
+ commandConcluded bool
+ closed bool
+ err error
+}
+
+// Result is the saved query response that is returned by calling Read on a ResultReader.
+type Result struct {
+ FieldDescriptions []pgproto3.FieldDescription
+ Rows [][][]byte
+ CommandTag CommandTag
+ Err error
+}
+
+// Read saves the query response to a Result.
+func (rr *ResultReader) Read() *Result {
+ br := &Result{}
+
+ for rr.NextRow() {
+ if br.FieldDescriptions == nil {
+ br.FieldDescriptions = make([]pgproto3.FieldDescription, len(rr.FieldDescriptions()))
+ copy(br.FieldDescriptions, rr.FieldDescriptions())
+ }
+
+ row := make([][]byte, len(rr.Values()))
+ copy(row, rr.Values())
+ br.Rows = append(br.Rows, row)
+ }
+
+ br.CommandTag, br.Err = rr.Close()
+
+ return br
+}
+
+// NextRow advances the ResultReader to the next row and returns true if a row is available.
+func (rr *ResultReader) NextRow() bool {
+ for !rr.commandConcluded {
+ msg, err := rr.receiveMessage()
+ if err != nil {
+ return false
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.DataRow:
+ rr.rowValues = msg.Values
+ return true
+ }
+ }
+
+ return false
+}
+
+// FieldDescriptions returns the field descriptions for the current result set. The returned slice is only valid until
+// the ResultReader is closed.
+func (rr *ResultReader) FieldDescriptions() []pgproto3.FieldDescription {
+ return rr.fieldDescriptions
+}
+
+// Values returns the current row data. NextRow must have been previously been called. The returned [][]byte is only
+// valid until the next NextRow call or the ResultReader is closed. However, the underlying byte data is safe to
+// retain a reference to and mutate.
+func (rr *ResultReader) Values() [][]byte {
+ return rr.rowValues
+}
+
+// Close consumes any remaining result data and returns the command tag or
+// error.
+func (rr *ResultReader) Close() (CommandTag, error) {
+ if rr.closed {
+ return rr.commandTag, rr.err
+ }
+ rr.closed = true
+
+ for !rr.commandConcluded {
+ _, err := rr.receiveMessage()
+ if err != nil {
+ return nil, rr.err
+ }
+ }
+
+ if rr.multiResultReader == nil {
+ for {
+ msg, err := rr.receiveMessage()
+ if err != nil {
+ return nil, rr.err
+ }
+
+ switch msg := msg.(type) {
+ // Detect a deferred constraint violation where the ErrorResponse is sent after CommandComplete.
+ case *pgproto3.ErrorResponse:
+ rr.err = ErrorResponseToPgError(msg)
+ case *pgproto3.ReadyForQuery:
+ rr.pgConn.contextWatcher.Unwatch()
+ rr.pgConn.unlock()
+ return rr.commandTag, rr.err
+ }
+ }
+ }
+
+ return rr.commandTag, rr.err
+}
+
+// readUntilRowDescription ensures the ResultReader's fieldDescriptions are loaded. It does not return an error as any
+// error will be stored in the ResultReader.
+func (rr *ResultReader) readUntilRowDescription() {
+ for !rr.commandConcluded {
+ // Peek before receive to avoid consuming a DataRow if the result set does not include a RowDescription method.
+ // This should never happen under normal pgconn usage, but it is possible if SendBytes and ReceiveResults are
+ // manually used to construct a query that does not issue a describe statement.
+ msg, _ := rr.pgConn.peekMessage()
+ if _, ok := msg.(*pgproto3.DataRow); ok {
+ return
+ }
+
+ // Consume the message
+ msg, _ = rr.receiveMessage()
+ if _, ok := msg.(*pgproto3.RowDescription); ok {
+ return
+ }
+ }
+}
+
+func (rr *ResultReader) receiveMessage() (msg pgproto3.BackendMessage, err error) {
+ if rr.multiResultReader == nil {
+ msg, err = rr.pgConn.receiveMessage()
+ } else {
+ msg, err = rr.multiResultReader.receiveMessage()
+ }
+
+ if err != nil {
+ err = preferContextOverNetTimeoutError(rr.ctx, err)
+ rr.concludeCommand(nil, err)
+ rr.pgConn.contextWatcher.Unwatch()
+ rr.closed = true
+ if rr.multiResultReader == nil {
+ rr.pgConn.asyncClose()
+ }
+
+ return nil, rr.err
+ }
+
+ switch msg := msg.(type) {
+ case *pgproto3.RowDescription:
+ rr.fieldDescriptions = msg.Fields
+ case *pgproto3.CommandComplete:
+ rr.concludeCommand(CommandTag(msg.CommandTag), nil)
+ case *pgproto3.EmptyQueryResponse:
+ rr.concludeCommand(nil, nil)
+ case *pgproto3.ErrorResponse:
+ rr.concludeCommand(nil, ErrorResponseToPgError(msg))
+ }
+
+ return msg, nil
+}
+
+func (rr *ResultReader) concludeCommand(commandTag CommandTag, err error) {
+ // Keep the first error that is recorded. Store the error before checking if the command is already concluded to
+ // allow for receiving an error after CommandComplete but before ReadyForQuery.
+ if err != nil && rr.err == nil {
+ rr.err = err
+ }
+
+ if rr.commandConcluded {
+ return
+ }
+
+ rr.commandTag = commandTag
+ rr.rowValues = nil
+ rr.commandConcluded = true
+}
+
+// Batch is a collection of queries that can be sent to the PostgreSQL server in a single round-trip.
+type Batch struct {
+ buf []byte
+}
+
+// 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) {
+ batch.buf = (&pgproto3.Parse{Query: sql, ParameterOIDs: paramOIDs}).Encode(batch.buf)
+ batch.ExecPrepared("", paramValues, paramFormats, resultFormats)
+}
+
+// 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) {
+ batch.buf = (&pgproto3.Bind{PreparedStatement: stmtName, ParameterFormatCodes: paramFormats, Parameters: paramValues, ResultFormatCodes: resultFormats}).Encode(batch.buf)
+ batch.buf = (&pgproto3.Describe{ObjectType: 'P'}).Encode(batch.buf)
+ batch.buf = (&pgproto3.Execute{}).Encode(batch.buf)
+}
+
+// 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.
+func (pgConn *PgConn) ExecBatch(ctx context.Context, batch *Batch) *MultiResultReader {
+ if err := pgConn.lock(); err != nil {
+ return &MultiResultReader{
+ closed: true,
+ err: err,
+ }
+ }
+
+ pgConn.multiResultReader = MultiResultReader{
+ pgConn: pgConn,
+ ctx: ctx,
+ }
+ multiResult := &pgConn.multiResultReader
+
+ if ctx != context.Background() {
+ select {
+ case <-ctx.Done():
+ multiResult.closed = true
+ multiResult.err = newContextAlreadyDoneError(ctx)
+ pgConn.unlock()
+ return multiResult
+ default:
+ }
+ pgConn.contextWatcher.Watch(ctx)
+ }
+
+ batch.buf = (&pgproto3.Sync{}).Encode(batch.buf)
+
+ // 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
+ // channel to relay the error back. The practical effect of this is that the underlying Write error is not reported.
+ // The error the code reading the batch results receives will be a closed connection error.
+ //
+ // See https://github.com/jackc/pgx/issues/374.
+ go func() {
+ _, err := pgConn.conn.Write(batch.buf)
+ if err != nil {
+ pgConn.conn.Close()
+ }
+ }()
+
+ return multiResult
+}
+
+// EscapeString escapes a string such that it can safely be interpolated into a SQL command string. It does not include
+// the surrounding single quotes.
+//
+// The current implementation requires that standard_conforming_strings=on and client_encoding="UTF8". If these
+// conditions are not met an error will be returned. It is possible these restrictions will be lifted in the future.
+func (pgConn *PgConn) EscapeString(s string) (string, error) {
+ if pgConn.ParameterStatus("standard_conforming_strings") != "on" {
+ return "", errors.New("EscapeString must be run with standard_conforming_strings=on")
+ }
+
+ if pgConn.ParameterStatus("client_encoding") != "UTF8" {
+ return "", errors.New("EscapeString must be run with client_encoding=UTF8")
+ }
+
+ return strings.Replace(s, "'", "''", -1), nil
+}
+
+// HijackedConn is the result of hijacking a connection.
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+type HijackedConn struct {
+ Conn net.Conn // the underlying TCP or unix domain socket connection
+ PID uint32 // backend pid
+ SecretKey uint32 // key to use to send a cancel query message to the server
+ ParameterStatuses map[string]string // parameters that have been reported by the server
+ TxStatus byte
+ Frontend Frontend
+ Config *Config
+}
+
+// Hijack extracts the internal connection data. pgConn must be in an idle state. pgConn is unusable after hijacking.
+// Hijacking is typically only useful when using pgconn to establish a connection, but taking complete control of the
+// raw connection after that (e.g. a load balancer or proxy).
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+func (pgConn *PgConn) Hijack() (*HijackedConn, error) {
+ if err := pgConn.lock(); err != nil {
+ return nil, err
+ }
+ pgConn.status = connStatusClosed
+
+ return &HijackedConn{
+ Conn: pgConn.conn,
+ PID: pgConn.pid,
+ SecretKey: pgConn.secretKey,
+ ParameterStatuses: pgConn.parameterStatuses,
+ TxStatus: pgConn.txStatus,
+ Frontend: pgConn.frontend,
+ Config: pgConn.config,
+ }, nil
+}
+
+// Construct created a PgConn from an already established connection to a PostgreSQL server. This is the inverse of
+// PgConn.Hijack. The connection must be in an idle state.
+//
+// Due to the necessary exposure of internal implementation details, it is not covered by the semantic versioning
+// compatibility.
+func Construct(hc *HijackedConn) (*PgConn, error) {
+ pgConn := &PgConn{
+ conn: hc.Conn,
+ pid: hc.PID,
+ secretKey: hc.SecretKey,
+ parameterStatuses: hc.ParameterStatuses,
+ txStatus: hc.TxStatus,
+ frontend: hc.Frontend,
+ config: hc.Config,
+
+ status: connStatusIdle,
+
+ wbuf: make([]byte, 0, wbufLen),
+ cleanupDone: make(chan struct{}),
+ }
+
+ 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{}) },
+ )
+
+ return pgConn, nil
+}
diff --git a/vendor/github.com/jackc/pgconn/stmtcache/lru.go b/vendor/github.com/jackc/pgconn/stmtcache/lru.go
new file mode 100644
index 000000000..f58f2ac34
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/stmtcache/lru.go
@@ -0,0 +1,157 @@
+package stmtcache
+
+import (
+ "container/list"
+ "context"
+ "fmt"
+ "sync/atomic"
+
+ "github.com/jackc/pgconn"
+)
+
+var lruCount uint64
+
+// LRU implements Cache with a Least Recently Used (LRU) cache.
+type LRU struct {
+ conn *pgconn.PgConn
+ mode int
+ cap int
+ prepareCount int
+ m map[string]*list.Element
+ l *list.List
+ psNamePrefix string
+ stmtsToClear []string
+}
+
+// NewLRU creates a new LRU. mode is either ModePrepare or ModeDescribe. cap is the maximum size of the cache.
+func NewLRU(conn *pgconn.PgConn, mode int, cap int) *LRU {
+ mustBeValidMode(mode)
+ mustBeValidCap(cap)
+
+ n := atomic.AddUint64(&lruCount, 1)
+
+ return &LRU{
+ conn: conn,
+ mode: mode,
+ cap: cap,
+ m: make(map[string]*list.Element),
+ l: list.New(),
+ psNamePrefix: fmt.Sprintf("lrupsc_%d", n),
+ }
+}
+
+// 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) {
+ // flush an outstanding bad statements
+ txStatus := c.conn.TxStatus()
+ if (txStatus == 'I' || txStatus == 'T') && len(c.stmtsToClear) > 0 {
+ for _, stmt := range c.stmtsToClear {
+ err := c.clearStmt(ctx, stmt)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if el, ok := c.m[sql]; ok {
+ c.l.MoveToFront(el)
+ return el.Value.(*pgconn.StatementDescription), nil
+ }
+
+ if c.l.Len() == c.cap {
+ err := c.removeOldest(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ psd, err := c.prepare(ctx, sql)
+ if err != nil {
+ return nil, err
+ }
+
+ el := c.l.PushFront(psd)
+ c.m[sql] = el
+
+ return psd, nil
+}
+
+// Clear removes all entries in the cache. Any prepared statements will be deallocated from the PostgreSQL session.
+func (c *LRU) Clear(ctx context.Context) error {
+ for c.l.Len() > 0 {
+ err := c.removeOldest(ctx)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (c *LRU) StatementErrored(sql string, err error) {
+ pgErr, ok := err.(*pgconn.PgError)
+ if !ok {
+ return
+ }
+
+ isInvalidCachedPlanError := pgErr.Severity == "ERROR" &&
+ pgErr.Code == "0A000" &&
+ pgErr.Message == "cached plan must not change result type"
+ if isInvalidCachedPlanError {
+ c.stmtsToClear = append(c.stmtsToClear, sql)
+ }
+}
+
+func (c *LRU) clearStmt(ctx context.Context, sql string) error {
+ elem, inMap := c.m[sql]
+ if !inMap {
+ // The statement probably fell off the back of the list. In that case, we've
+ // ensured that it isn't in the cache, so we can declare victory.
+ return nil
+ }
+
+ c.l.Remove(elem)
+
+ psd := elem.Value.(*pgconn.StatementDescription)
+ delete(c.m, psd.SQL)
+ if c.mode == ModePrepare {
+ return c.conn.Exec(ctx, fmt.Sprintf("deallocate %s", psd.Name)).Close()
+ }
+ return nil
+}
+
+// Len returns the number of cached prepared statement descriptions.
+func (c *LRU) Len() int {
+ return c.l.Len()
+}
+
+// Cap returns the maximum number of cached prepared statement descriptions.
+func (c *LRU) Cap() int {
+ return c.cap
+}
+
+// Mode returns the mode of the cache (ModePrepare or ModeDescribe)
+func (c *LRU) Mode() int {
+ return c.mode
+}
+
+func (c *LRU) prepare(ctx context.Context, sql string) (*pgconn.StatementDescription, error) {
+ var name string
+ if c.mode == ModePrepare {
+ name = fmt.Sprintf("%s_%d", c.psNamePrefix, c.prepareCount)
+ c.prepareCount += 1
+ }
+
+ return c.conn.Prepare(ctx, name, sql, nil)
+}
+
+func (c *LRU) removeOldest(ctx context.Context) error {
+ oldest := c.l.Back()
+ c.l.Remove(oldest)
+ psd := oldest.Value.(*pgconn.StatementDescription)
+ delete(c.m, psd.SQL)
+ if c.mode == ModePrepare {
+ return c.conn.Exec(ctx, fmt.Sprintf("deallocate %s", psd.Name)).Close()
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgconn/stmtcache/stmtcache.go b/vendor/github.com/jackc/pgconn/stmtcache/stmtcache.go
new file mode 100644
index 000000000..d083e1b4f
--- /dev/null
+++ b/vendor/github.com/jackc/pgconn/stmtcache/stmtcache.go
@@ -0,0 +1,58 @@
+// Package stmtcache is a cache that can be used to implement lazy prepared statements.
+package stmtcache
+
+import (
+ "context"
+
+ "github.com/jackc/pgconn"
+)
+
+const (
+ ModePrepare = iota // Cache should prepare named statements.
+ ModeDescribe // Cache should prepare the anonymous prepared statement to only fetch the description of the statement.
+)
+
+// Cache prepares and caches prepared statement descriptions.
+type Cache interface {
+ // Get returns the prepared statement description for sql preparing or describing the sql on the server as needed.
+ Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error)
+
+ // Clear removes all entries in the cache. Any prepared statements will be deallocated from the PostgreSQL session.
+ Clear(ctx context.Context) error
+
+ // StatementErrored informs the cache that the given statement resulted in an error when it
+ // was last used against the database. In some cases, this will cause the cache to maer that
+ // statement as bad. The bad statement will instead be flushed during the next call to Get
+ // that occurs outside of a failed transaction.
+ StatementErrored(sql string, err error)
+
+ // Len returns the number of cached prepared statement descriptions.
+ Len() int
+
+ // Cap returns the maximum number of cached prepared statement descriptions.
+ Cap() int
+
+ // Mode returns the mode of the cache (ModePrepare or ModeDescribe)
+ Mode() int
+}
+
+// New returns the preferred cache implementation for mode and cap. mode is either ModePrepare or ModeDescribe. cap is
+// the maximum size of the cache.
+func New(conn *pgconn.PgConn, mode int, cap int) Cache {
+ mustBeValidMode(mode)
+ mustBeValidCap(cap)
+
+ return NewLRU(conn, mode, cap)
+}
+
+func mustBeValidMode(mode int) {
+ if mode != ModePrepare && mode != ModeDescribe {
+ panic("mode must be ModePrepare or ModeDescribe")
+ }
+}
+
+func mustBeValidCap(cap int) {
+ if cap < 1 {
+ panic("cache must have cap of >= 1")
+ }
+}
diff --git a/vendor/github.com/jackc/pgio/.travis.yml b/vendor/github.com/jackc/pgio/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.x
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/jackc/pgio/LICENSE b/vendor/github.com/jackc/pgio/LICENSE
new file mode 100644
index 000000000..c1c4f50fc
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgio/README.md b/vendor/github.com/jackc/pgio/README.md
new file mode 100644
index 000000000..1952ed862
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/README.md
@@ -0,0 +1,11 @@
+[![](https://godoc.org/github.com/jackc/pgio?status.svg)](https://godoc.org/github.com/jackc/pgio)
+[![Build Status](https://travis-ci.org/jackc/pgio.svg)](https://travis-ci.org/jackc/pgio)
+
+# pgio
+
+Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol.
+
+pgio provides functions for appending integers to a []byte while doing byte
+order conversion.
+
+Extracted from original implementation in https://github.com/jackc/pgx.
diff --git a/vendor/github.com/jackc/pgio/doc.go b/vendor/github.com/jackc/pgio/doc.go
new file mode 100644
index 000000000..ef2dcc7f7
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/doc.go
@@ -0,0 +1,6 @@
+// Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol.
+/*
+pgio provides functions for appending integers to a []byte while doing byte
+order conversion.
+*/
+package pgio
diff --git a/vendor/github.com/jackc/pgio/go.mod b/vendor/github.com/jackc/pgio/go.mod
new file mode 100644
index 000000000..c1efdddb6
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/go.mod
@@ -0,0 +1,3 @@
+module github.com/jackc/pgio
+
+go 1.12
diff --git a/vendor/github.com/jackc/pgio/write.go b/vendor/github.com/jackc/pgio/write.go
new file mode 100644
index 000000000..96aedf9dd
--- /dev/null
+++ b/vendor/github.com/jackc/pgio/write.go
@@ -0,0 +1,40 @@
+package pgio
+
+import "encoding/binary"
+
+func AppendUint16(buf []byte, n uint16) []byte {
+ wp := len(buf)
+ buf = append(buf, 0, 0)
+ binary.BigEndian.PutUint16(buf[wp:], n)
+ return buf
+}
+
+func AppendUint32(buf []byte, n uint32) []byte {
+ wp := len(buf)
+ buf = append(buf, 0, 0, 0, 0)
+ binary.BigEndian.PutUint32(buf[wp:], n)
+ return buf
+}
+
+func AppendUint64(buf []byte, n uint64) []byte {
+ wp := len(buf)
+ buf = append(buf, 0, 0, 0, 0, 0, 0, 0, 0)
+ binary.BigEndian.PutUint64(buf[wp:], n)
+ return buf
+}
+
+func AppendInt16(buf []byte, n int16) []byte {
+ return AppendUint16(buf, uint16(n))
+}
+
+func AppendInt32(buf []byte, n int32) []byte {
+ return AppendUint32(buf, uint32(n))
+}
+
+func AppendInt64(buf []byte, n int64) []byte {
+ return AppendUint64(buf, uint64(n))
+}
+
+func SetInt32(buf []byte, n int32) {
+ binary.BigEndian.PutUint32(buf, uint32(n))
+}
diff --git a/vendor/github.com/jackc/pgpassfile/.travis.yml b/vendor/github.com/jackc/pgpassfile/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.x
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/jackc/pgpassfile/LICENSE b/vendor/github.com/jackc/pgpassfile/LICENSE
new file mode 100644
index 000000000..c1c4f50fc
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgpassfile/README.md b/vendor/github.com/jackc/pgpassfile/README.md
new file mode 100644
index 000000000..661289ed8
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/README.md
@@ -0,0 +1,8 @@
+[![](https://godoc.org/github.com/jackc/pgpassfile?status.svg)](https://godoc.org/github.com/jackc/pgpassfile)
+[![Build Status](https://travis-ci.org/jackc/pgpassfile.svg)](https://travis-ci.org/jackc/pgpassfile)
+
+# pgpassfile
+
+Package pgpassfile is a parser PostgreSQL .pgpass files.
+
+Extracted and rewritten from original implementation in https://github.com/jackc/pgx.
diff --git a/vendor/github.com/jackc/pgpassfile/go.mod b/vendor/github.com/jackc/pgpassfile/go.mod
new file mode 100644
index 000000000..48d90e313
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/go.mod
@@ -0,0 +1,5 @@
+module github.com/jackc/pgpassfile
+
+go 1.12
+
+require github.com/stretchr/testify v1.3.0
diff --git a/vendor/github.com/jackc/pgpassfile/go.sum b/vendor/github.com/jackc/pgpassfile/go.sum
new file mode 100644
index 000000000..4347755af
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/go.sum
@@ -0,0 +1,7 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
diff --git a/vendor/github.com/jackc/pgpassfile/pgpass.go b/vendor/github.com/jackc/pgpassfile/pgpass.go
new file mode 100644
index 000000000..f7eed3c84
--- /dev/null
+++ b/vendor/github.com/jackc/pgpassfile/pgpass.go
@@ -0,0 +1,110 @@
+// Package pgpassfile is a parser PostgreSQL .pgpass files.
+package pgpassfile
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+)
+
+// Entry represents a line in a PG passfile.
+type Entry struct {
+ Hostname string
+ Port string
+ Database string
+ Username string
+ Password string
+}
+
+// Passfile is the in memory data structure representing a PG passfile.
+type Passfile struct {
+ Entries []*Entry
+}
+
+// ReadPassfile reads the file at path and parses it into a Passfile.
+func ReadPassfile(path string) (*Passfile, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return ParsePassfile(f)
+}
+
+// ParsePassfile reads r and parses it into a Passfile.
+func ParsePassfile(r io.Reader) (*Passfile, error) {
+ passfile := &Passfile{}
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ entry := parseLine(scanner.Text())
+ if entry != nil {
+ passfile.Entries = append(passfile.Entries, entry)
+ }
+ }
+
+ return passfile, scanner.Err()
+}
+
+// Match (not colons or escaped colon or escaped backslash)+. Essentially gives a split on unescaped
+// colon.
+var colonSplitterRegexp = regexp.MustCompile("(([^:]|(\\:)))+")
+
+// var colonSplitterRegexp = regexp.MustCompile("((?:[^:]|(?:\\:)|(?:\\\\))+)")
+
+// parseLine parses a line into an *Entry. It returns nil on comment lines or any other unparsable
+// line.
+func parseLine(line string) *Entry {
+ const (
+ tmpBackslash = "\r"
+ tmpColon = "\n"
+ )
+
+ line = strings.TrimSpace(line)
+
+ if strings.HasPrefix(line, "#") {
+ return nil
+ }
+
+ line = strings.Replace(line, `\\`, tmpBackslash, -1)
+ line = strings.Replace(line, `\:`, tmpColon, -1)
+
+ parts := strings.Split(line, ":")
+ if len(parts) != 5 {
+ return nil
+ }
+
+ // Unescape escaped colons and backslashes
+ for i := range parts {
+ parts[i] = strings.Replace(parts[i], tmpBackslash, `\`, -1)
+ parts[i] = strings.Replace(parts[i], tmpColon, `:`, -1)
+ }
+
+ return &Entry{
+ Hostname: parts[0],
+ Port: parts[1],
+ Database: parts[2],
+ Username: parts[3],
+ Password: parts[4],
+ }
+}
+
+// FindPassword finds the password for the provided hostname, port, database, and username. For a
+// Unix domain socket hostname must be set to "localhost". An empty string will be returned if no
+// match is found.
+//
+// See https://www.postgresql.org/docs/current/libpq-pgpass.html for more password file information.
+func (pf *Passfile) FindPassword(hostname, port, database, username string) (password string) {
+ for _, e := range pf.Entries {
+ if (e.Hostname == "*" || e.Hostname == hostname) &&
+ (e.Port == "*" || e.Port == port) &&
+ (e.Database == "*" || e.Database == database) &&
+ (e.Username == "*" || e.Username == username) {
+ return e.Password
+ }
+ }
+ return ""
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/.travis.yml b/vendor/github.com/jackc/pgproto3/v2/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.x
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/jackc/pgproto3/v2/LICENSE b/vendor/github.com/jackc/pgproto3/v2/LICENSE
new file mode 100644
index 000000000..c1c4f50fc
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2019 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgproto3/v2/README.md b/vendor/github.com/jackc/pgproto3/v2/README.md
new file mode 100644
index 000000000..565b3efd5
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/README.md
@@ -0,0 +1,12 @@
+[![](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)
+
+# pgproto3
+
+Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3.
+
+pgproto3 can be used as a foundation for PostgreSQL drivers, proxies, mock servers, load balancers and more.
+
+See example/pgfortune for a playful example of a fake PostgreSQL server.
+
+Extracted from original implementation in https://github.com/jackc/pgx.
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_cleartext_password.go b/vendor/github.com/jackc/pgproto3/v2/authentication_cleartext_password.go
new file mode 100644
index 000000000..241fa6005
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_cleartext_password.go
@@ -0,0 +1,52 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationCleartextPassword is a message sent from the backend indicating that a clear-text password is required.
+type AuthenticationCleartextPassword struct {
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationCleartextPassword) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationCleartextPassword) AuthenticationResponse() {}
+
+// 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 *AuthenticationCleartextPassword) Decode(src []byte) error {
+ if len(src) != 4 {
+ return errors.New("bad authentication message size")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeCleartextPassword {
+ return errors.New("bad auth type")
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ dst = pgio.AppendInt32(dst, 8)
+ dst = pgio.AppendUint32(dst, AuthTypeCleartextPassword)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationCleartextPassword) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "AuthenticationCleartextPassword",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_md5_password.go b/vendor/github.com/jackc/pgproto3/v2/authentication_md5_password.go
new file mode 100644
index 000000000..32ec0390e
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_md5_password.go
@@ -0,0 +1,77 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationMD5Password is a message sent from the backend indicating that an MD5 hashed password is required.
+type AuthenticationMD5Password struct {
+ Salt [4]byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationMD5Password) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationMD5Password) AuthenticationResponse() {}
+
+// 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 *AuthenticationMD5Password) Decode(src []byte) error {
+ if len(src) != 8 {
+ return errors.New("bad authentication message size")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeMD5Password {
+ return errors.New("bad auth type")
+ }
+
+ copy(dst.Salt[:], src[4:8])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ dst = pgio.AppendInt32(dst, 12)
+ dst = pgio.AppendUint32(dst, AuthTypeMD5Password)
+ dst = append(dst, src.Salt[:]...)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationMD5Password) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Salt [4]byte
+ }{
+ Type: "AuthenticationMD5Password",
+ Salt: src.Salt,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationMD5Password) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Type string
+ Salt [4]byte
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Salt = msg.Salt
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_ok.go b/vendor/github.com/jackc/pgproto3/v2/authentication_ok.go
new file mode 100644
index 000000000..2b476fe51
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_ok.go
@@ -0,0 +1,52 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationOk is a message sent from the backend indicating that authentication was successful.
+type AuthenticationOk struct {
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationOk) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationOk) AuthenticationResponse() {}
+
+// 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 *AuthenticationOk) Decode(src []byte) error {
+ if len(src) != 4 {
+ return errors.New("bad authentication message size")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeOk {
+ return errors.New("bad auth type")
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ dst = pgio.AppendInt32(dst, 8)
+ dst = pgio.AppendUint32(dst, AuthTypeOk)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationOk) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "AuthenticationOK",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_sasl.go b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl.go
new file mode 100644
index 000000000..bdcb2c367
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl.go
@@ -0,0 +1,75 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationSASL is a message sent from the backend indicating that SASL authentication is required.
+type AuthenticationSASL struct {
+ AuthMechanisms []string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASL) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASL) AuthenticationResponse() {}
+
+// 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 *AuthenticationSASL) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("authentication message too short")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeSASL {
+ return errors.New("bad auth type")
+ }
+
+ authMechanisms := src[4:]
+ for len(authMechanisms) > 1 {
+ idx := bytes.IndexByte(authMechanisms, 0)
+ if idx > 0 {
+ dst.AuthMechanisms = append(dst.AuthMechanisms, string(authMechanisms[:idx]))
+ authMechanisms = authMechanisms[idx+1:]
+ }
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+ dst = pgio.AppendUint32(dst, AuthTypeSASL)
+
+ for _, s := range src.AuthMechanisms {
+ dst = append(dst, []byte(s)...)
+ dst = append(dst, 0)
+ }
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationSASL) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ AuthMechanisms []string
+ }{
+ Type: "AuthenticationSASL",
+ AuthMechanisms: src.AuthMechanisms,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_continue.go b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_continue.go
new file mode 100644
index 000000000..7f4a9c235
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_continue.go
@@ -0,0 +1,81 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationSASLContinue is a message sent from the backend containing a SASL challenge.
+type AuthenticationSASLContinue struct {
+ Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASLContinue) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASLContinue) AuthenticationResponse() {}
+
+// 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 *AuthenticationSASLContinue) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("authentication message too short")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeSASLContinue {
+ return errors.New("bad auth type")
+ }
+
+ dst.Data = src[4:]
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+ dst = pgio.AppendUint32(dst, AuthTypeSASLContinue)
+
+ dst = append(dst, src.Data...)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src AuthenticationSASLContinue) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Data string
+ }{
+ Type: "AuthenticationSASLContinue",
+ Data: string(src.Data),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationSASLContinue) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Data string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Data = []byte(msg.Data)
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_final.go b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_final.go
new file mode 100644
index 000000000..d82b9ee4d
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/authentication_sasl_final.go
@@ -0,0 +1,81 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+// AuthenticationSASLFinal is a message sent from the backend indicating a SASL authentication has completed.
+type AuthenticationSASLFinal struct {
+ Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*AuthenticationSASLFinal) Backend() {}
+
+// Backend identifies this message as an authentication response.
+func (*AuthenticationSASLFinal) AuthenticationResponse() {}
+
+// 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 *AuthenticationSASLFinal) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("authentication message too short")
+ }
+
+ authType := binary.BigEndian.Uint32(src)
+
+ if authType != AuthTypeSASLFinal {
+ return errors.New("bad auth type")
+ }
+
+ dst.Data = src[4:]
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'R')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+ dst = pgio.AppendUint32(dst, AuthTypeSASLFinal)
+
+ dst = append(dst, src.Data...)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Unmarshaler.
+func (src AuthenticationSASLFinal) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Data string
+ }{
+ Type: "AuthenticationSASLFinal",
+ Data: string(src.Data),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *AuthenticationSASLFinal) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Data string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Data = []byte(msg.Data)
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/backend.go b/vendor/github.com/jackc/pgproto3/v2/backend.go
new file mode 100644
index 000000000..e9ba38fc3
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/backend.go
@@ -0,0 +1,204 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+)
+
+// Backend acts as a server for the PostgreSQL wire protocol version 3.
+type Backend struct {
+ cr ChunkReader
+ w io.Writer
+
+ // Frontend message flyweights
+ bind Bind
+ cancelRequest CancelRequest
+ _close Close
+ copyFail CopyFail
+ copyData CopyData
+ copyDone CopyDone
+ describe Describe
+ execute Execute
+ flush Flush
+ gssEncRequest GSSEncRequest
+ parse Parse
+ query Query
+ sslRequest SSLRequest
+ startupMessage StartupMessage
+ sync Sync
+ terminate Terminate
+
+ bodyLen int
+ msgType byte
+ partialMsg bool
+ authType uint32
+}
+
+const (
+ minStartupPacketLen = 4 // minStartupPacketLen is a single 32-bit int version or code.
+ maxStartupPacketLen = 10000 // maxStartupPacketLen is MAX_STARTUP_PACKET_LENGTH from PG source.
+)
+
+// NewBackend creates a new Backend.
+func NewBackend(cr ChunkReader, w io.Writer) *Backend {
+ return &Backend{cr: cr, w: w}
+}
+
+// Send sends a message to the frontend.
+func (b *Backend) Send(msg BackendMessage) error {
+ _, err := b.w.Write(msg.Encode(nil))
+ return err
+}
+
+// ReceiveStartupMessage receives the initial connection message. This method is used of the normal Receive method
+// because the initial connection message is "special" and does not include the message type as the first byte. This
+// will return either a StartupMessage, SSLRequest, GSSEncRequest, or CancelRequest.
+func (b *Backend) ReceiveStartupMessage() (FrontendMessage, error) {
+ buf, err := b.cr.Next(4)
+ if err != nil {
+ return nil, err
+ }
+ msgSize := int(binary.BigEndian.Uint32(buf) - 4)
+
+ if msgSize < minStartupPacketLen || msgSize > maxStartupPacketLen {
+ return nil, fmt.Errorf("invalid length of startup packet: %d", msgSize)
+ }
+
+ buf, err = b.cr.Next(msgSize)
+ if err != nil {
+ return nil, translateEOFtoErrUnexpectedEOF(err)
+ }
+
+ code := binary.BigEndian.Uint32(buf)
+
+ switch code {
+ case ProtocolVersionNumber:
+ err = b.startupMessage.Decode(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &b.startupMessage, nil
+ case sslRequestNumber:
+ err = b.sslRequest.Decode(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &b.sslRequest, nil
+ case cancelRequestCode:
+ err = b.cancelRequest.Decode(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &b.cancelRequest, nil
+ case gssEncReqNumber:
+ err = b.gssEncRequest.Decode(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &b.gssEncRequest, nil
+ default:
+ return nil, fmt.Errorf("unknown startup message code: %d", code)
+ }
+}
+
+// Receive receives a message from the frontend. The returned message is only valid until the next call to Receive.
+func (b *Backend) Receive() (FrontendMessage, error) {
+ if !b.partialMsg {
+ header, err := b.cr.Next(5)
+ if err != nil {
+ return nil, translateEOFtoErrUnexpectedEOF(err)
+ }
+
+ b.msgType = header[0]
+ b.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
+ b.partialMsg = true
+ }
+
+ var msg FrontendMessage
+ switch b.msgType {
+ case 'B':
+ msg = &b.bind
+ case 'C':
+ msg = &b._close
+ case 'D':
+ msg = &b.describe
+ case 'E':
+ msg = &b.execute
+ case 'f':
+ msg = &b.copyFail
+ case 'd':
+ msg = &b.copyData
+ case 'c':
+ msg = &b.copyDone
+ case 'H':
+ msg = &b.flush
+ case 'P':
+ msg = &b.parse
+ case 'p':
+ switch b.authType {
+ case AuthTypeSASL:
+ msg = &SASLInitialResponse{}
+ case AuthTypeSASLContinue:
+ msg = &SASLResponse{}
+ case AuthTypeSASLFinal:
+ msg = &SASLResponse{}
+ case AuthTypeCleartextPassword, AuthTypeMD5Password:
+ fallthrough
+ default:
+ // to maintain backwards compatability
+ msg = &PasswordMessage{}
+ }
+ case 'Q':
+ msg = &b.query
+ case 'S':
+ msg = &b.sync
+ case 'X':
+ msg = &b.terminate
+ default:
+ return nil, fmt.Errorf("unknown message type: %c", b.msgType)
+ }
+
+ msgBody, err := b.cr.Next(b.bodyLen)
+ if err != nil {
+ return nil, translateEOFtoErrUnexpectedEOF(err)
+ }
+
+ b.partialMsg = false
+
+ err = msg.Decode(msgBody)
+ return msg, err
+}
+
+// SetAuthType sets the authentication type in the backend.
+// Since multiple message types can start with 'p', SetAuthType allows
+// contextual identification of FrontendMessages. For example, in the
+// PG message flow documentation for PasswordMessage:
+//
+// Byte1('p')
+//
+// 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
+// the context.
+//
+// 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.
+func (b *Backend) SetAuthType(authType uint32) error {
+ switch authType {
+ case AuthTypeOk,
+ AuthTypeCleartextPassword,
+ AuthTypeMD5Password,
+ AuthTypeSCMCreds,
+ AuthTypeGSS,
+ AuthTypeGSSCont,
+ AuthTypeSSPI,
+ AuthTypeSASL,
+ AuthTypeSASLContinue,
+ AuthTypeSASLFinal:
+ b.authType = authType
+ default:
+ return fmt.Errorf("authType not recognized: %d", authType)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/backend_key_data.go b/vendor/github.com/jackc/pgproto3/v2/backend_key_data.go
new file mode 100644
index 000000000..ca20dd259
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/backend_key_data.go
@@ -0,0 +1,51 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type BackendKeyData struct {
+ ProcessID uint32
+ SecretKey uint32
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*BackendKeyData) Backend() {}
+
+// 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 *BackendKeyData) Decode(src []byte) error {
+ if len(src) != 8 {
+ return &invalidMessageLenErr{messageType: "BackendKeyData", expectedLen: 8, actualLen: len(src)}
+ }
+
+ dst.ProcessID = binary.BigEndian.Uint32(src[:4])
+ dst.SecretKey = binary.BigEndian.Uint32(src[4:])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'K')
+ dst = pgio.AppendUint32(dst, 12)
+ dst = pgio.AppendUint32(dst, src.ProcessID)
+ dst = pgio.AppendUint32(dst, src.SecretKey)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src BackendKeyData) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ProcessID uint32
+ SecretKey uint32
+ }{
+ Type: "BackendKeyData",
+ ProcessID: src.ProcessID,
+ SecretKey: src.SecretKey,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/big_endian.go b/vendor/github.com/jackc/pgproto3/v2/big_endian.go
new file mode 100644
index 000000000..f7bdb97eb
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/big_endian.go
@@ -0,0 +1,37 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+)
+
+type BigEndianBuf [8]byte
+
+func (b BigEndianBuf) Int16(n int16) []byte {
+ buf := b[0:2]
+ binary.BigEndian.PutUint16(buf, uint16(n))
+ return buf
+}
+
+func (b BigEndianBuf) Uint16(n uint16) []byte {
+ buf := b[0:2]
+ binary.BigEndian.PutUint16(buf, n)
+ return buf
+}
+
+func (b BigEndianBuf) Int32(n int32) []byte {
+ buf := b[0:4]
+ binary.BigEndian.PutUint32(buf, uint32(n))
+ return buf
+}
+
+func (b BigEndianBuf) Uint32(n uint32) []byte {
+ buf := b[0:4]
+ binary.BigEndian.PutUint32(buf, n)
+ return buf
+}
+
+func (b BigEndianBuf) Int64(n int64) []byte {
+ buf := b[0:8]
+ binary.BigEndian.PutUint64(buf, uint64(n))
+ return buf
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/bind.go b/vendor/github.com/jackc/pgproto3/v2/bind.go
new file mode 100644
index 000000000..e9664f59f
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/bind.go
@@ -0,0 +1,216 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Bind struct {
+ DestinationPortal string
+ PreparedStatement string
+ ParameterFormatCodes []int16
+ Parameters [][]byte
+ ResultFormatCodes []int16
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Bind) 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 *Bind) Decode(src []byte) error {
+ *dst = Bind{}
+
+ idx := bytes.IndexByte(src, 0)
+ if idx < 0 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ dst.DestinationPortal = string(src[:idx])
+ rp := idx + 1
+
+ idx = bytes.IndexByte(src[rp:], 0)
+ if idx < 0 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ dst.PreparedStatement = string(src[rp : rp+idx])
+ rp += idx + 1
+
+ if len(src[rp:]) < 2 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ parameterFormatCodeCount := int(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ if parameterFormatCodeCount > 0 {
+ dst.ParameterFormatCodes = make([]int16, parameterFormatCodeCount)
+
+ if len(src[rp:]) < len(dst.ParameterFormatCodes)*2 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ for i := 0; i < parameterFormatCodeCount; i++ {
+ dst.ParameterFormatCodes[i] = int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ }
+ }
+
+ if len(src[rp:]) < 2 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ parameterCount := int(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ if parameterCount > 0 {
+ dst.Parameters = make([][]byte, parameterCount)
+
+ for i := 0; i < parameterCount; i++ {
+ if len(src[rp:]) < 4 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+
+ msgSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+
+ // null
+ if msgSize == -1 {
+ continue
+ }
+
+ if len(src[rp:]) < msgSize {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+
+ dst.Parameters[i] = src[rp : rp+msgSize]
+ rp += msgSize
+ }
+ }
+
+ if len(src[rp:]) < 2 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ resultFormatCodeCount := int(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ dst.ResultFormatCodes = make([]int16, resultFormatCodeCount)
+ if len(src[rp:]) < len(dst.ResultFormatCodes)*2 {
+ return &invalidMessageFormatErr{messageType: "Bind"}
+ }
+ for i := 0; i < resultFormatCodeCount; i++ {
+ dst.ResultFormatCodes[i] = int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'B')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.DestinationPortal...)
+ dst = append(dst, 0)
+ dst = append(dst, src.PreparedStatement...)
+ dst = append(dst, 0)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ParameterFormatCodes)))
+ for _, fc := range src.ParameterFormatCodes {
+ dst = pgio.AppendInt16(dst, fc)
+ }
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.Parameters)))
+ for _, p := range src.Parameters {
+ if p == nil {
+ dst = pgio.AppendInt32(dst, -1)
+ continue
+ }
+
+ dst = pgio.AppendInt32(dst, int32(len(p)))
+ dst = append(dst, p...)
+ }
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ResultFormatCodes)))
+ for _, fc := range src.ResultFormatCodes {
+ dst = pgio.AppendInt16(dst, fc)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Bind) MarshalJSON() ([]byte, error) {
+ formattedParameters := make([]map[string]string, len(src.Parameters))
+ for i, p := range src.Parameters {
+ if p == nil {
+ continue
+ }
+
+ textFormat := true
+ if len(src.ParameterFormatCodes) == 1 {
+ textFormat = src.ParameterFormatCodes[0] == 0
+ } else if len(src.ParameterFormatCodes) > 1 {
+ textFormat = src.ParameterFormatCodes[i] == 0
+ }
+
+ if textFormat {
+ formattedParameters[i] = map[string]string{"text": string(p)}
+ } else {
+ formattedParameters[i] = map[string]string{"binary": hex.EncodeToString(p)}
+ }
+ }
+
+ return json.Marshal(struct {
+ Type string
+ DestinationPortal string
+ PreparedStatement string
+ ParameterFormatCodes []int16
+ Parameters []map[string]string
+ ResultFormatCodes []int16
+ }{
+ Type: "Bind",
+ DestinationPortal: src.DestinationPortal,
+ PreparedStatement: src.PreparedStatement,
+ ParameterFormatCodes: src.ParameterFormatCodes,
+ Parameters: formattedParameters,
+ ResultFormatCodes: src.ResultFormatCodes,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Bind) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ DestinationPortal string
+ PreparedStatement string
+ ParameterFormatCodes []int16
+ Parameters []map[string]string
+ ResultFormatCodes []int16
+ }
+ err := json.Unmarshal(data, &msg)
+ if err != nil {
+ return err
+ }
+ dst.DestinationPortal = msg.DestinationPortal
+ dst.PreparedStatement = msg.PreparedStatement
+ dst.ParameterFormatCodes = msg.ParameterFormatCodes
+ dst.Parameters = make([][]byte, len(msg.Parameters))
+ dst.ResultFormatCodes = msg.ResultFormatCodes
+ for n, parameter := range msg.Parameters {
+ dst.Parameters[n], err = getValueFromJSON(parameter)
+ if err != nil {
+ return fmt.Errorf("cannot get param %d: %w", n, err)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/bind_complete.go b/vendor/github.com/jackc/pgproto3/v2/bind_complete.go
new file mode 100644
index 000000000..3be256c89
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/bind_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type BindComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*BindComplete) Backend() {}
+
+// 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 *BindComplete) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "BindComplete", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, '2', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src BindComplete) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "BindComplete",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/cancel_request.go b/vendor/github.com/jackc/pgproto3/v2/cancel_request.go
new file mode 100644
index 000000000..942e404be
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/cancel_request.go
@@ -0,0 +1,58 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+const cancelRequestCode = 80877102
+
+type CancelRequest struct {
+ ProcessID uint32
+ SecretKey uint32
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CancelRequest) Frontend() {}
+
+func (dst *CancelRequest) Decode(src []byte) error {
+ if len(src) != 12 {
+ return errors.New("bad cancel request size")
+ }
+
+ requestCode := binary.BigEndian.Uint32(src)
+
+ if requestCode != cancelRequestCode {
+ return errors.New("bad cancel request code")
+ }
+
+ dst.ProcessID = binary.BigEndian.Uint32(src[4:])
+ dst.SecretKey = binary.BigEndian.Uint32(src[8:])
+
+ return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *CancelRequest) Encode(dst []byte) []byte {
+ dst = pgio.AppendInt32(dst, 16)
+ dst = pgio.AppendInt32(dst, cancelRequestCode)
+ dst = pgio.AppendUint32(dst, src.ProcessID)
+ dst = pgio.AppendUint32(dst, src.SecretKey)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CancelRequest) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ProcessID uint32
+ SecretKey uint32
+ }{
+ Type: "CancelRequest",
+ ProcessID: src.ProcessID,
+ SecretKey: src.SecretKey,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/chunkreader.go b/vendor/github.com/jackc/pgproto3/v2/chunkreader.go
new file mode 100644
index 000000000..92206f358
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/chunkreader.go
@@ -0,0 +1,19 @@
+package pgproto3
+
+import (
+ "io"
+
+ "github.com/jackc/chunkreader/v2"
+)
+
+// ChunkReader is an interface to decouple github.com/jackc/chunkreader from this package.
+type ChunkReader interface {
+ // Next returns buf filled with the next n bytes. If an error (including a partial read) occurs,
+ // buf must be nil. Next must preserve any partially read data. Next must not reuse buf.
+ Next(n int) (buf []byte, err error)
+}
+
+// NewChunkReader creates and returns a new default ChunkReader.
+func NewChunkReader(r io.Reader) ChunkReader {
+ return chunkreader.New(r)
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/close.go b/vendor/github.com/jackc/pgproto3/v2/close.go
new file mode 100644
index 000000000..a45f2b930
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/close.go
@@ -0,0 +1,89 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type Close struct {
+ ObjectType byte // 'S' = prepared statement, 'P' = portal
+ Name string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Close) 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 *Close) Decode(src []byte) error {
+ if len(src) < 2 {
+ return &invalidMessageFormatErr{messageType: "Close"}
+ }
+
+ dst.ObjectType = src[0]
+ rp := 1
+
+ idx := bytes.IndexByte(src[rp:], 0)
+ if idx != len(src[rp:])-1 {
+ return &invalidMessageFormatErr{messageType: "Close"}
+ }
+
+ dst.Name = string(src[rp : len(src)-1])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'C')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.ObjectType)
+ dst = append(dst, src.Name...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Close) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ObjectType string
+ Name string
+ }{
+ Type: "Close",
+ ObjectType: string(src.ObjectType),
+ Name: src.Name,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Close) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ ObjectType string
+ Name string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ if len(msg.ObjectType) != 1 {
+ return errors.New("invalid length for Close.ObjectType")
+ }
+
+ dst.ObjectType = byte(msg.ObjectType[0])
+ dst.Name = msg.Name
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/close_complete.go b/vendor/github.com/jackc/pgproto3/v2/close_complete.go
new file mode 100644
index 000000000..1d7b8f085
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/close_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type CloseComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CloseComplete) Backend() {}
+
+// 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 *CloseComplete) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "CloseComplete", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, '3', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CloseComplete) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "CloseComplete",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/command_complete.go b/vendor/github.com/jackc/pgproto3/v2/command_complete.go
new file mode 100644
index 000000000..cdc49f39f
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/command_complete.go
@@ -0,0 +1,71 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type CommandComplete struct {
+ CommandTag []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CommandComplete) Backend() {}
+
+// 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 *CommandComplete) Decode(src []byte) error {
+ idx := bytes.IndexByte(src, 0)
+ if idx != len(src)-1 {
+ return &invalidMessageFormatErr{messageType: "CommandComplete"}
+ }
+
+ dst.CommandTag = src[:idx]
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'C')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.CommandTag...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CommandComplete) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ CommandTag string
+ }{
+ Type: "CommandComplete",
+ CommandTag: string(src.CommandTag),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CommandComplete) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ CommandTag string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.CommandTag = []byte(msg.CommandTag)
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_both_response.go b/vendor/github.com/jackc/pgproto3/v2/copy_both_response.go
new file mode 100644
index 000000000..fbd985d86
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_both_response.go
@@ -0,0 +1,95 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type CopyBothResponse struct {
+ OverallFormat byte
+ ColumnFormatCodes []uint16
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyBothResponse) Backend() {}
+
+// 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 *CopyBothResponse) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ if buf.Len() < 3 {
+ return &invalidMessageFormatErr{messageType: "CopyBothResponse"}
+ }
+
+ overallFormat := buf.Next(1)[0]
+
+ columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+ if buf.Len() != columnCount*2 {
+ return &invalidMessageFormatErr{messageType: "CopyBothResponse"}
+ }
+
+ columnFormatCodes := make([]uint16, columnCount)
+ for i := 0; i < columnCount; i++ {
+ columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+ }
+
+ *dst = CopyBothResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'W')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+ for _, fc := range src.ColumnFormatCodes {
+ dst = pgio.AppendUint16(dst, fc)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyBothResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ColumnFormatCodes []uint16
+ }{
+ Type: "CopyBothResponse",
+ ColumnFormatCodes: src.ColumnFormatCodes,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyBothResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ OverallFormat string
+ ColumnFormatCodes []uint16
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ if len(msg.OverallFormat) != 1 {
+ return errors.New("invalid length for CopyBothResponse.OverallFormat")
+ }
+
+ dst.OverallFormat = msg.OverallFormat[0]
+ dst.ColumnFormatCodes = msg.ColumnFormatCodes
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_data.go b/vendor/github.com/jackc/pgproto3/v2/copy_data.go
new file mode 100644
index 000000000..128aa198c
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_data.go
@@ -0,0 +1,62 @@
+package pgproto3
+
+import (
+ "encoding/hex"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type CopyData struct {
+ Data []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyData) Backend() {}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyData) 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 *CopyData) Decode(src []byte) error {
+ dst.Data = src
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'd')
+ dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))
+ dst = append(dst, src.Data...)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyData) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Data string
+ }{
+ Type: "CopyData",
+ Data: hex.EncodeToString(src.Data),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyData) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Data string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Data = []byte(msg.Data)
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_done.go b/vendor/github.com/jackc/pgproto3/v2/copy_done.go
new file mode 100644
index 000000000..0e13282bf
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_done.go
@@ -0,0 +1,38 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type CopyDone struct {
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyDone) Backend() {}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyDone) 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 *CopyDone) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "CopyDone", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'c', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyDone) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "CopyDone",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_fail.go b/vendor/github.com/jackc/pgproto3/v2/copy_fail.go
new file mode 100644
index 000000000..78ff0b30b
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_fail.go
@@ -0,0 +1,53 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type CopyFail struct {
+ Message string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*CopyFail) 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 *CopyFail) Decode(src []byte) error {
+ idx := bytes.IndexByte(src, 0)
+ if idx != len(src)-1 {
+ return &invalidMessageFormatErr{messageType: "CopyFail"}
+ }
+
+ dst.Message = string(src[:idx])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'f')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.Message...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyFail) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Message string
+ }{
+ Type: "CopyFail",
+ Message: src.Message,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_in_response.go b/vendor/github.com/jackc/pgproto3/v2/copy_in_response.go
new file mode 100644
index 000000000..80733adcf
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_in_response.go
@@ -0,0 +1,96 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type CopyInResponse struct {
+ OverallFormat byte
+ ColumnFormatCodes []uint16
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*CopyInResponse) Backend() {}
+
+// 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 *CopyInResponse) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ if buf.Len() < 3 {
+ return &invalidMessageFormatErr{messageType: "CopyInResponse"}
+ }
+
+ overallFormat := buf.Next(1)[0]
+
+ columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+ if buf.Len() != columnCount*2 {
+ return &invalidMessageFormatErr{messageType: "CopyInResponse"}
+ }
+
+ columnFormatCodes := make([]uint16, columnCount)
+ for i := 0; i < columnCount; i++ {
+ columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+ }
+
+ *dst = CopyInResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'G')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.OverallFormat)
+ dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+ for _, fc := range src.ColumnFormatCodes {
+ dst = pgio.AppendUint16(dst, fc)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyInResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ColumnFormatCodes []uint16
+ }{
+ Type: "CopyInResponse",
+ ColumnFormatCodes: src.ColumnFormatCodes,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyInResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ OverallFormat string
+ ColumnFormatCodes []uint16
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ if len(msg.OverallFormat) != 1 {
+ return errors.New("invalid length for CopyInResponse.OverallFormat")
+ }
+
+ dst.OverallFormat = msg.OverallFormat[0]
+ dst.ColumnFormatCodes = msg.ColumnFormatCodes
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/copy_out_response.go b/vendor/github.com/jackc/pgproto3/v2/copy_out_response.go
new file mode 100644
index 000000000..5e607e3ac
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/copy_out_response.go
@@ -0,0 +1,96 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type CopyOutResponse struct {
+ OverallFormat byte
+ ColumnFormatCodes []uint16
+}
+
+func (*CopyOutResponse) Backend() {}
+
+// 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 *CopyOutResponse) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ if buf.Len() < 3 {
+ return &invalidMessageFormatErr{messageType: "CopyOutResponse"}
+ }
+
+ overallFormat := buf.Next(1)[0]
+
+ columnCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+ if buf.Len() != columnCount*2 {
+ return &invalidMessageFormatErr{messageType: "CopyOutResponse"}
+ }
+
+ columnFormatCodes := make([]uint16, columnCount)
+ for i := 0; i < columnCount; i++ {
+ columnFormatCodes[i] = binary.BigEndian.Uint16(buf.Next(2))
+ }
+
+ *dst = CopyOutResponse{OverallFormat: overallFormat, ColumnFormatCodes: columnFormatCodes}
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'H')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.OverallFormat)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
+ for _, fc := range src.ColumnFormatCodes {
+ dst = pgio.AppendUint16(dst, fc)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src CopyOutResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ColumnFormatCodes []uint16
+ }{
+ Type: "CopyOutResponse",
+ ColumnFormatCodes: src.ColumnFormatCodes,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *CopyOutResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ OverallFormat string
+ ColumnFormatCodes []uint16
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ if len(msg.OverallFormat) != 1 {
+ return errors.New("invalid length for CopyOutResponse.OverallFormat")
+ }
+
+ dst.OverallFormat = msg.OverallFormat[0]
+ dst.ColumnFormatCodes = msg.ColumnFormatCodes
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/data_row.go b/vendor/github.com/jackc/pgproto3/v2/data_row.go
new file mode 100644
index 000000000..637687616
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/data_row.go
@@ -0,0 +1,142 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type DataRow struct {
+ Values [][]byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*DataRow) Backend() {}
+
+// 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 *DataRow) Decode(src []byte) error {
+ if len(src) < 2 {
+ return &invalidMessageFormatErr{messageType: "DataRow"}
+ }
+ rp := 0
+ fieldCount := int(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ // If the capacity of the values slice is too small OR substantially too
+ // large reallocate. This is too avoid one row with many columns from
+ // permanently allocating memory.
+ if cap(dst.Values) < fieldCount || cap(dst.Values)-fieldCount > 32 {
+ newCap := 32
+ if newCap < fieldCount {
+ newCap = fieldCount
+ }
+ dst.Values = make([][]byte, fieldCount, newCap)
+ } else {
+ dst.Values = dst.Values[:fieldCount]
+ }
+
+ for i := 0; i < fieldCount; i++ {
+ if len(src[rp:]) < 4 {
+ return &invalidMessageFormatErr{messageType: "DataRow"}
+ }
+
+ msgSize := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+
+ // null
+ if msgSize == -1 {
+ dst.Values[i] = nil
+ } else {
+ if len(src[rp:]) < msgSize {
+ return &invalidMessageFormatErr{messageType: "DataRow"}
+ }
+
+ dst.Values[i] = src[rp : rp+msgSize : rp+msgSize]
+ rp += msgSize
+ }
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'D')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.Values)))
+ for _, v := range src.Values {
+ if v == nil {
+ dst = pgio.AppendInt32(dst, -1)
+ continue
+ }
+
+ dst = pgio.AppendInt32(dst, int32(len(v)))
+ dst = append(dst, v...)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src DataRow) MarshalJSON() ([]byte, error) {
+ formattedValues := make([]map[string]string, len(src.Values))
+ for i, v := range src.Values {
+ if v == nil {
+ continue
+ }
+
+ var hasNonPrintable bool
+ for _, b := range v {
+ if b < 32 {
+ hasNonPrintable = true
+ break
+ }
+ }
+
+ if hasNonPrintable {
+ formattedValues[i] = map[string]string{"binary": hex.EncodeToString(v)}
+ } else {
+ formattedValues[i] = map[string]string{"text": string(v)}
+ }
+ }
+
+ return json.Marshal(struct {
+ Type string
+ Values []map[string]string
+ }{
+ Type: "DataRow",
+ Values: formattedValues,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *DataRow) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Values []map[string]string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Values = make([][]byte, len(msg.Values))
+ for n, parameter := range msg.Values {
+ var err error
+ dst.Values[n], err = getValueFromJSON(parameter)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/describe.go b/vendor/github.com/jackc/pgproto3/v2/describe.go
new file mode 100644
index 000000000..0d825db19
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/describe.go
@@ -0,0 +1,88 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type Describe struct {
+ ObjectType byte // 'S' = prepared statement, 'P' = portal
+ Name string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Describe) 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 *Describe) Decode(src []byte) error {
+ if len(src) < 2 {
+ return &invalidMessageFormatErr{messageType: "Describe"}
+ }
+
+ dst.ObjectType = src[0]
+ rp := 1
+
+ idx := bytes.IndexByte(src[rp:], 0)
+ if idx != len(src[rp:])-1 {
+ return &invalidMessageFormatErr{messageType: "Describe"}
+ }
+
+ dst.Name = string(src[rp : len(src)-1])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'D')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.ObjectType)
+ dst = append(dst, src.Name...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Describe) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ObjectType string
+ Name string
+ }{
+ Type: "Describe",
+ ObjectType: string(src.ObjectType),
+ Name: src.Name,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *Describe) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ ObjectType string
+ Name string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+ if len(msg.ObjectType) != 1 {
+ return errors.New("invalid length for Describe.ObjectType")
+ }
+
+ dst.ObjectType = byte(msg.ObjectType[0])
+ dst.Name = msg.Name
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/doc.go b/vendor/github.com/jackc/pgproto3/v2/doc.go
new file mode 100644
index 000000000..8226dc983
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/doc.go
@@ -0,0 +1,4 @@
+// Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3.
+//
+// See https://www.postgresql.org/docs/current/protocol-message-formats.html for meanings of the different messages.
+package pgproto3
diff --git a/vendor/github.com/jackc/pgproto3/v2/empty_query_response.go b/vendor/github.com/jackc/pgproto3/v2/empty_query_response.go
new file mode 100644
index 000000000..2b85e744b
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/empty_query_response.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type EmptyQueryResponse struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*EmptyQueryResponse) Backend() {}
+
+// 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 *EmptyQueryResponse) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "EmptyQueryResponse", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'I', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src EmptyQueryResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "EmptyQueryResponse",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/error_response.go b/vendor/github.com/jackc/pgproto3/v2/error_response.go
new file mode 100644
index 000000000..ec51e0192
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/error_response.go
@@ -0,0 +1,334 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "strconv"
+)
+
+type ErrorResponse struct {
+ Severity string
+ SeverityUnlocalized string // only in 9.6 and greater
+ Code string
+ Message string
+ Detail string
+ Hint string
+ Position int32
+ InternalPosition int32
+ InternalQuery string
+ Where string
+ SchemaName string
+ TableName string
+ ColumnName string
+ DataTypeName string
+ ConstraintName string
+ File string
+ Line int32
+ Routine string
+
+ UnknownFields map[byte]string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ErrorResponse) Backend() {}
+
+// 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 *ErrorResponse) Decode(src []byte) error {
+ *dst = ErrorResponse{}
+
+ buf := bytes.NewBuffer(src)
+
+ for {
+ k, err := buf.ReadByte()
+ if err != nil {
+ return err
+ }
+ if k == 0 {
+ break
+ }
+
+ vb, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ v := string(vb[:len(vb)-1])
+
+ switch k {
+ case 'S':
+ dst.Severity = v
+ case 'V':
+ dst.SeverityUnlocalized = v
+ case 'C':
+ dst.Code = v
+ case 'M':
+ dst.Message = v
+ case 'D':
+ dst.Detail = v
+ case 'H':
+ dst.Hint = v
+ case 'P':
+ s := v
+ n, _ := strconv.ParseInt(s, 10, 32)
+ dst.Position = int32(n)
+ case 'p':
+ s := v
+ n, _ := strconv.ParseInt(s, 10, 32)
+ dst.InternalPosition = int32(n)
+ case 'q':
+ dst.InternalQuery = v
+ case 'W':
+ dst.Where = v
+ case 's':
+ dst.SchemaName = v
+ case 't':
+ dst.TableName = v
+ case 'c':
+ dst.ColumnName = v
+ case 'd':
+ dst.DataTypeName = v
+ case 'n':
+ dst.ConstraintName = v
+ case 'F':
+ dst.File = v
+ case 'L':
+ s := v
+ n, _ := strconv.ParseInt(s, 10, 32)
+ dst.Line = int32(n)
+ case 'R':
+ dst.Routine = v
+
+ default:
+ if dst.UnknownFields == nil {
+ dst.UnknownFields = make(map[byte]string)
+ }
+ dst.UnknownFields[k] = v
+ }
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, src.marshalBinary('E')...)
+}
+
+func (src *ErrorResponse) marshalBinary(typeByte byte) []byte {
+ var bigEndian BigEndianBuf
+ buf := &bytes.Buffer{}
+
+ buf.WriteByte(typeByte)
+ buf.Write(bigEndian.Uint32(0))
+
+ if src.Severity != "" {
+ buf.WriteByte('S')
+ buf.WriteString(src.Severity)
+ buf.WriteByte(0)
+ }
+ if src.SeverityUnlocalized != "" {
+ buf.WriteByte('V')
+ buf.WriteString(src.SeverityUnlocalized)
+ buf.WriteByte(0)
+ }
+ if src.Code != "" {
+ buf.WriteByte('C')
+ buf.WriteString(src.Code)
+ buf.WriteByte(0)
+ }
+ if src.Message != "" {
+ buf.WriteByte('M')
+ buf.WriteString(src.Message)
+ buf.WriteByte(0)
+ }
+ if src.Detail != "" {
+ buf.WriteByte('D')
+ buf.WriteString(src.Detail)
+ buf.WriteByte(0)
+ }
+ if src.Hint != "" {
+ buf.WriteByte('H')
+ buf.WriteString(src.Hint)
+ buf.WriteByte(0)
+ }
+ if src.Position != 0 {
+ buf.WriteByte('P')
+ buf.WriteString(strconv.Itoa(int(src.Position)))
+ buf.WriteByte(0)
+ }
+ if src.InternalPosition != 0 {
+ buf.WriteByte('p')
+ buf.WriteString(strconv.Itoa(int(src.InternalPosition)))
+ buf.WriteByte(0)
+ }
+ if src.InternalQuery != "" {
+ buf.WriteByte('q')
+ buf.WriteString(src.InternalQuery)
+ buf.WriteByte(0)
+ }
+ if src.Where != "" {
+ buf.WriteByte('W')
+ buf.WriteString(src.Where)
+ buf.WriteByte(0)
+ }
+ if src.SchemaName != "" {
+ buf.WriteByte('s')
+ buf.WriteString(src.SchemaName)
+ buf.WriteByte(0)
+ }
+ if src.TableName != "" {
+ buf.WriteByte('t')
+ buf.WriteString(src.TableName)
+ buf.WriteByte(0)
+ }
+ if src.ColumnName != "" {
+ buf.WriteByte('c')
+ buf.WriteString(src.ColumnName)
+ buf.WriteByte(0)
+ }
+ if src.DataTypeName != "" {
+ buf.WriteByte('d')
+ buf.WriteString(src.DataTypeName)
+ buf.WriteByte(0)
+ }
+ if src.ConstraintName != "" {
+ buf.WriteByte('n')
+ buf.WriteString(src.ConstraintName)
+ buf.WriteByte(0)
+ }
+ if src.File != "" {
+ buf.WriteByte('F')
+ buf.WriteString(src.File)
+ buf.WriteByte(0)
+ }
+ if src.Line != 0 {
+ buf.WriteByte('L')
+ buf.WriteString(strconv.Itoa(int(src.Line)))
+ buf.WriteByte(0)
+ }
+ if src.Routine != "" {
+ buf.WriteByte('R')
+ buf.WriteString(src.Routine)
+ buf.WriteByte(0)
+ }
+
+ for k, v := range src.UnknownFields {
+ buf.WriteByte(k)
+ buf.WriteByte(0)
+ buf.WriteString(v)
+ buf.WriteByte(0)
+ }
+
+ buf.WriteByte(0)
+
+ binary.BigEndian.PutUint32(buf.Bytes()[1:5], uint32(buf.Len()-1))
+
+ return buf.Bytes()
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ErrorResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Severity string
+ SeverityUnlocalized string // only in 9.6 and greater
+ Code string
+ Message string
+ Detail string
+ Hint string
+ Position int32
+ InternalPosition int32
+ InternalQuery string
+ Where string
+ SchemaName string
+ TableName string
+ ColumnName string
+ DataTypeName string
+ ConstraintName string
+ File string
+ Line int32
+ Routine string
+
+ UnknownFields map[byte]string
+ }{
+ Type: "ErrorResponse",
+ Severity: src.Severity,
+ SeverityUnlocalized: src.SeverityUnlocalized,
+ Code: src.Code,
+ Message: src.Message,
+ Detail: src.Detail,
+ Hint: src.Hint,
+ Position: src.Position,
+ InternalPosition: src.InternalPosition,
+ InternalQuery: src.InternalQuery,
+ Where: src.Where,
+ SchemaName: src.SchemaName,
+ TableName: src.TableName,
+ ColumnName: src.ColumnName,
+ DataTypeName: src.DataTypeName,
+ ConstraintName: src.ConstraintName,
+ File: src.File,
+ Line: src.Line,
+ Routine: src.Routine,
+ UnknownFields: src.UnknownFields,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *ErrorResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Type string
+ Severity string
+ SeverityUnlocalized string // only in 9.6 and greater
+ Code string
+ Message string
+ Detail string
+ Hint string
+ Position int32
+ InternalPosition int32
+ InternalQuery string
+ Where string
+ SchemaName string
+ TableName string
+ ColumnName string
+ DataTypeName string
+ ConstraintName string
+ File string
+ Line int32
+ Routine string
+
+ UnknownFields map[byte]string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+
+ dst.Severity = msg.Severity
+ dst.SeverityUnlocalized = msg.SeverityUnlocalized
+ dst.Code = msg.Code
+ dst.Message = msg.Message
+ dst.Detail = msg.Detail
+ dst.Hint = msg.Hint
+ dst.Position = msg.Position
+ dst.InternalPosition = msg.InternalPosition
+ dst.InternalQuery = msg.InternalQuery
+ dst.Where = msg.Where
+ dst.SchemaName = msg.SchemaName
+ dst.TableName = msg.TableName
+ dst.ColumnName = msg.ColumnName
+ dst.DataTypeName = msg.DataTypeName
+ dst.ConstraintName = msg.ConstraintName
+ dst.File = msg.File
+ dst.Line = msg.Line
+ dst.Routine = msg.Routine
+
+ dst.UnknownFields = msg.UnknownFields
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/execute.go b/vendor/github.com/jackc/pgproto3/v2/execute.go
new file mode 100644
index 000000000..8bae61332
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/execute.go
@@ -0,0 +1,65 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type Execute struct {
+ Portal string
+ MaxRows uint32
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Execute) 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 *Execute) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ b, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ dst.Portal = string(b[:len(b)-1])
+
+ if buf.Len() < 4 {
+ return &invalidMessageFormatErr{messageType: "Execute"}
+ }
+ dst.MaxRows = binary.BigEndian.Uint32(buf.Next(4))
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'E')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.Portal...)
+ dst = append(dst, 0)
+
+ dst = pgio.AppendUint32(dst, src.MaxRows)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Execute) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Portal string
+ MaxRows uint32
+ }{
+ Type: "Execute",
+ Portal: src.Portal,
+ MaxRows: src.MaxRows,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/flush.go b/vendor/github.com/jackc/pgproto3/v2/flush.go
new file mode 100644
index 000000000..2725f6894
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/flush.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type Flush struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Flush) 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 *Flush) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "Flush", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'H', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Flush) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "Flush",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/frontend.go b/vendor/github.com/jackc/pgproto3/v2/frontend.go
new file mode 100644
index 000000000..c33dfb084
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/frontend.go
@@ -0,0 +1,201 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// Frontend acts as a client for the PostgreSQL wire protocol version 3.
+type Frontend struct {
+ cr ChunkReader
+ w io.Writer
+
+ // Backend message flyweights
+ authenticationOk AuthenticationOk
+ authenticationCleartextPassword AuthenticationCleartextPassword
+ authenticationMD5Password AuthenticationMD5Password
+ authenticationSASL AuthenticationSASL
+ authenticationSASLContinue AuthenticationSASLContinue
+ authenticationSASLFinal AuthenticationSASLFinal
+ backendKeyData BackendKeyData
+ bindComplete BindComplete
+ closeComplete CloseComplete
+ commandComplete CommandComplete
+ copyBothResponse CopyBothResponse
+ copyData CopyData
+ copyInResponse CopyInResponse
+ copyOutResponse CopyOutResponse
+ copyDone CopyDone
+ dataRow DataRow
+ emptyQueryResponse EmptyQueryResponse
+ errorResponse ErrorResponse
+ functionCallResponse FunctionCallResponse
+ noData NoData
+ noticeResponse NoticeResponse
+ notificationResponse NotificationResponse
+ parameterDescription ParameterDescription
+ parameterStatus ParameterStatus
+ parseComplete ParseComplete
+ readyForQuery ReadyForQuery
+ rowDescription RowDescription
+ portalSuspended PortalSuspended
+
+ bodyLen int
+ msgType byte
+ partialMsg bool
+ authType uint32
+}
+
+// NewFrontend creates a new Frontend.
+func NewFrontend(cr ChunkReader, w io.Writer) *Frontend {
+ return &Frontend{cr: cr, w: w}
+}
+
+// Send sends a message to the backend.
+func (f *Frontend) Send(msg FrontendMessage) error {
+ _, err := f.w.Write(msg.Encode(nil))
+ return err
+}
+
+func translateEOFtoErrUnexpectedEOF(err error) error {
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ return err
+}
+
+// Receive receives a message from the backend. The returned message is only valid until the next call to Receive.
+func (f *Frontend) Receive() (BackendMessage, error) {
+ if !f.partialMsg {
+ header, err := f.cr.Next(5)
+ if err != nil {
+ return nil, translateEOFtoErrUnexpectedEOF(err)
+ }
+
+ f.msgType = header[0]
+ f.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
+ f.partialMsg = true
+ }
+
+ msgBody, err := f.cr.Next(f.bodyLen)
+ if err != nil {
+ return nil, translateEOFtoErrUnexpectedEOF(err)
+ }
+
+ f.partialMsg = false
+
+ var msg BackendMessage
+ switch f.msgType {
+ case '1':
+ msg = &f.parseComplete
+ case '2':
+ msg = &f.bindComplete
+ case '3':
+ msg = &f.closeComplete
+ case 'A':
+ msg = &f.notificationResponse
+ case 'c':
+ msg = &f.copyDone
+ case 'C':
+ msg = &f.commandComplete
+ case 'd':
+ msg = &f.copyData
+ case 'D':
+ msg = &f.dataRow
+ case 'E':
+ msg = &f.errorResponse
+ case 'G':
+ msg = &f.copyInResponse
+ case 'H':
+ msg = &f.copyOutResponse
+ case 'I':
+ msg = &f.emptyQueryResponse
+ case 'K':
+ msg = &f.backendKeyData
+ case 'n':
+ msg = &f.noData
+ case 'N':
+ msg = &f.noticeResponse
+ case 'R':
+ var err error
+ msg, err = f.findAuthenticationMessageType(msgBody)
+ if err != nil {
+ return nil, err
+ }
+ case 's':
+ msg = &f.portalSuspended
+ case 'S':
+ msg = &f.parameterStatus
+ case 't':
+ msg = &f.parameterDescription
+ case 'T':
+ msg = &f.rowDescription
+ case 'V':
+ msg = &f.functionCallResponse
+ case 'W':
+ msg = &f.copyBothResponse
+ case 'Z':
+ msg = &f.readyForQuery
+ default:
+ return nil, fmt.Errorf("unknown message type: %c", f.msgType)
+ }
+
+ err = msg.Decode(msgBody)
+ return msg, err
+}
+
+// Authentication message type constants.
+// See src/include/libpq/pqcomm.h for all
+// constants.
+const (
+ AuthTypeOk = 0
+ AuthTypeCleartextPassword = 3
+ AuthTypeMD5Password = 5
+ AuthTypeSCMCreds = 6
+ AuthTypeGSS = 7
+ AuthTypeGSSCont = 8
+ AuthTypeSSPI = 9
+ AuthTypeSASL = 10
+ AuthTypeSASLContinue = 11
+ AuthTypeSASLFinal = 12
+)
+
+func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, error) {
+ if len(src) < 4 {
+ return nil, errors.New("authentication message too short")
+ }
+ f.authType = binary.BigEndian.Uint32(src[:4])
+
+ switch f.authType {
+ case AuthTypeOk:
+ return &f.authenticationOk, nil
+ case AuthTypeCleartextPassword:
+ return &f.authenticationCleartextPassword, nil
+ case AuthTypeMD5Password:
+ return &f.authenticationMD5Password, nil
+ case AuthTypeSCMCreds:
+ return nil, errors.New("AuthTypeSCMCreds is unimplemented")
+ case AuthTypeGSS:
+ return nil, errors.New("AuthTypeGSS is unimplemented")
+ case AuthTypeGSSCont:
+ return nil, errors.New("AuthTypeGSSCont is unimplemented")
+ case AuthTypeSSPI:
+ return nil, errors.New("AuthTypeSSPI is unimplemented")
+ case AuthTypeSASL:
+ return &f.authenticationSASL, nil
+ case AuthTypeSASLContinue:
+ return &f.authenticationSASLContinue, nil
+ case AuthTypeSASLFinal:
+ return &f.authenticationSASLFinal, nil
+ default:
+ return nil, fmt.Errorf("unknown authentication type: %d", f.authType)
+ }
+}
+
+// GetAuthType returns the authType used in the current state of the frontend.
+// See SetAuthType for more information.
+func (f *Frontend) GetAuthType() uint32 {
+ return f.authType
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/function_call_response.go b/vendor/github.com/jackc/pgproto3/v2/function_call_response.go
new file mode 100644
index 000000000..53d642221
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/function_call_response.go
@@ -0,0 +1,101 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type FunctionCallResponse struct {
+ Result []byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*FunctionCallResponse) Backend() {}
+
+// 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 *FunctionCallResponse) Decode(src []byte) error {
+ if len(src) < 4 {
+ return &invalidMessageFormatErr{messageType: "FunctionCallResponse"}
+ }
+ rp := 0
+ resultSize := int(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ if resultSize == -1 {
+ dst.Result = nil
+ return nil
+ }
+
+ if len(src[rp:]) != resultSize {
+ return &invalidMessageFormatErr{messageType: "FunctionCallResponse"}
+ }
+
+ dst.Result = src[rp:]
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'V')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ if src.Result == nil {
+ dst = pgio.AppendInt32(dst, -1)
+ } else {
+ dst = pgio.AppendInt32(dst, int32(len(src.Result)))
+ dst = append(dst, src.Result...)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src FunctionCallResponse) MarshalJSON() ([]byte, error) {
+ var formattedValue map[string]string
+ var hasNonPrintable bool
+ for _, b := range src.Result {
+ if b < 32 {
+ hasNonPrintable = true
+ break
+ }
+ }
+
+ if hasNonPrintable {
+ formattedValue = map[string]string{"binary": hex.EncodeToString(src.Result)}
+ } else {
+ formattedValue = map[string]string{"text": string(src.Result)}
+ }
+
+ return json.Marshal(struct {
+ Type string
+ Result map[string]string
+ }{
+ Type: "FunctionCallResponse",
+ Result: formattedValue,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *FunctionCallResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ Result map[string]string
+ }
+ err := json.Unmarshal(data, &msg)
+ if err != nil {
+ return err
+ }
+ dst.Result, err = getValueFromJSON(msg.Result)
+ return err
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/go.mod b/vendor/github.com/jackc/pgproto3/v2/go.mod
new file mode 100644
index 000000000..36041a94a
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/go.mod
@@ -0,0 +1,9 @@
+module github.com/jackc/pgproto3/v2
+
+go 1.12
+
+require (
+ github.com/jackc/chunkreader/v2 v2.0.0
+ github.com/jackc/pgio v1.0.0
+ github.com/stretchr/testify v1.4.0
+)
diff --git a/vendor/github.com/jackc/pgproto3/v2/go.sum b/vendor/github.com/jackc/pgproto3/v2/go.sum
new file mode 100644
index 000000000..dd9cd044f
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/go.sum
@@ -0,0 +1,14 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/jackc/chunkreader/v2 v2.0.0 h1:DUwgMQuuPnS0rhMXenUtZpqZqrR/30NWY+qQvTpSvEs=
+github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/jackc/pgproto3/v2/gss_enc_request.go b/vendor/github.com/jackc/pgproto3/v2/gss_enc_request.go
new file mode 100644
index 000000000..cf405a3e0
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/gss_enc_request.go
@@ -0,0 +1,49 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+const gssEncReqNumber = 80877104
+
+type GSSEncRequest struct {
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*GSSEncRequest) Frontend() {}
+
+func (dst *GSSEncRequest) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("gss encoding request too short")
+ }
+
+ requestCode := binary.BigEndian.Uint32(src)
+
+ if requestCode != gssEncReqNumber {
+ return errors.New("bad gss encoding request code")
+ }
+
+ return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *GSSEncRequest) Encode(dst []byte) []byte {
+ dst = pgio.AppendInt32(dst, 8)
+ dst = pgio.AppendInt32(dst, gssEncReqNumber)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src GSSEncRequest) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ProtocolVersion uint32
+ Parameters map[string]string
+ }{
+ Type: "GSSEncRequest",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/no_data.go b/vendor/github.com/jackc/pgproto3/v2/no_data.go
new file mode 100644
index 000000000..d8f85d38a
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/no_data.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type NoData struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NoData) Backend() {}
+
+// 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 *NoData) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "NoData", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'n', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src NoData) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "NoData",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/notice_response.go b/vendor/github.com/jackc/pgproto3/v2/notice_response.go
new file mode 100644
index 000000000..4ac28a791
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/notice_response.go
@@ -0,0 +1,17 @@
+package pgproto3
+
+type NoticeResponse ErrorResponse
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NoticeResponse) Backend() {}
+
+// 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 *NoticeResponse) Decode(src []byte) error {
+ return (*ErrorResponse)(dst).Decode(src)
+}
+
+// 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 {
+ return append(dst, (*ErrorResponse)(src).marshalBinary('N')...)
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/notification_response.go b/vendor/github.com/jackc/pgproto3/v2/notification_response.go
new file mode 100644
index 000000000..e762eb967
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/notification_response.go
@@ -0,0 +1,73 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type NotificationResponse struct {
+ PID uint32
+ Channel string
+ Payload string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*NotificationResponse) Backend() {}
+
+// 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 *NotificationResponse) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ pid := binary.BigEndian.Uint32(buf.Next(4))
+
+ b, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ channel := string(b[:len(b)-1])
+
+ b, err = buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ payload := string(b[:len(b)-1])
+
+ *dst = NotificationResponse{PID: pid, Channel: channel, Payload: payload}
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'A')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint32(dst, src.PID)
+ dst = append(dst, src.Channel...)
+ dst = append(dst, 0)
+ dst = append(dst, src.Payload...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src NotificationResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ PID uint32
+ Channel string
+ Payload string
+ }{
+ Type: "NotificationResponse",
+ PID: src.PID,
+ Channel: src.Channel,
+ Payload: src.Payload,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/parameter_description.go b/vendor/github.com/jackc/pgproto3/v2/parameter_description.go
new file mode 100644
index 000000000..e28965c8a
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/parameter_description.go
@@ -0,0 +1,66 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type ParameterDescription struct {
+ ParameterOIDs []uint32
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParameterDescription) Backend() {}
+
+// 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 *ParameterDescription) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ if buf.Len() < 2 {
+ return &invalidMessageFormatErr{messageType: "ParameterDescription"}
+ }
+
+ // Reported parameter count will be incorrect when number of args is greater than uint16
+ buf.Next(2)
+ // Instead infer parameter count by remaining size of message
+ parameterCount := buf.Len() / 4
+
+ *dst = ParameterDescription{ParameterOIDs: make([]uint32, parameterCount)}
+
+ for i := 0; i < parameterCount; i++ {
+ dst.ParameterOIDs[i] = binary.BigEndian.Uint32(buf.Next(4))
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 't')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
+ for _, oid := range src.ParameterOIDs {
+ dst = pgio.AppendUint32(dst, oid)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ParameterDescription) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ParameterOIDs []uint32
+ }{
+ Type: "ParameterDescription",
+ ParameterOIDs: src.ParameterOIDs,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/parameter_status.go b/vendor/github.com/jackc/pgproto3/v2/parameter_status.go
new file mode 100644
index 000000000..c4021d92f
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/parameter_status.go
@@ -0,0 +1,66 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type ParameterStatus struct {
+ Name string
+ Value string
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParameterStatus) Backend() {}
+
+// 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 *ParameterStatus) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ b, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ name := string(b[:len(b)-1])
+
+ b, err = buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ value := string(b[:len(b)-1])
+
+ *dst = ParameterStatus{Name: name, Value: value}
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'S')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.Name...)
+ dst = append(dst, 0)
+ dst = append(dst, src.Value...)
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (ps ParameterStatus) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Name string
+ Value string
+ }{
+ Type: "ParameterStatus",
+ Name: ps.Name,
+ Value: ps.Value,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/parse.go b/vendor/github.com/jackc/pgproto3/v2/parse.go
new file mode 100644
index 000000000..723885d41
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/parse.go
@@ -0,0 +1,88 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type Parse struct {
+ Name string
+ Query string
+ ParameterOIDs []uint32
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Parse) 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 *Parse) Decode(src []byte) error {
+ *dst = Parse{}
+
+ buf := bytes.NewBuffer(src)
+
+ b, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ dst.Name = string(b[:len(b)-1])
+
+ b, err = buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ dst.Query = string(b[:len(b)-1])
+
+ if buf.Len() < 2 {
+ return &invalidMessageFormatErr{messageType: "Parse"}
+ }
+ parameterOIDCount := int(binary.BigEndian.Uint16(buf.Next(2)))
+
+ for i := 0; i < parameterOIDCount; i++ {
+ if buf.Len() < 4 {
+ return &invalidMessageFormatErr{messageType: "Parse"}
+ }
+ dst.ParameterOIDs = append(dst.ParameterOIDs, binary.BigEndian.Uint32(buf.Next(4)))
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'P')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, src.Name...)
+ dst = append(dst, 0)
+ dst = append(dst, src.Query...)
+ dst = append(dst, 0)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.ParameterOIDs)))
+ for _, oid := range src.ParameterOIDs {
+ dst = pgio.AppendUint32(dst, oid)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Parse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Name string
+ Query string
+ ParameterOIDs []uint32
+ }{
+ Type: "Parse",
+ Name: src.Name,
+ Query: src.Query,
+ ParameterOIDs: src.ParameterOIDs,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/parse_complete.go b/vendor/github.com/jackc/pgproto3/v2/parse_complete.go
new file mode 100644
index 000000000..92c9498b6
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/parse_complete.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type ParseComplete struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ParseComplete) Backend() {}
+
+// 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 *ParseComplete) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "ParseComplete", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, '1', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ParseComplete) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "ParseComplete",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/password_message.go b/vendor/github.com/jackc/pgproto3/v2/password_message.go
new file mode 100644
index 000000000..cae76c50c
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/password_message.go
@@ -0,0 +1,54 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type PasswordMessage struct {
+ Password string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*PasswordMessage) Frontend() {}
+
+// Frontend identifies this message as an authentication response.
+func (*PasswordMessage) InitialResponse() {}
+
+// 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 *PasswordMessage) Decode(src []byte) error {
+ buf := bytes.NewBuffer(src)
+
+ b, err := buf.ReadBytes(0)
+ if err != nil {
+ return err
+ }
+ dst.Password = string(b[:len(b)-1])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'p')
+ dst = pgio.AppendInt32(dst, int32(4+len(src.Password)+1))
+
+ dst = append(dst, src.Password...)
+ dst = append(dst, 0)
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src PasswordMessage) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Password string
+ }{
+ Type: "PasswordMessage",
+ Password: src.Password,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/pgproto3.go b/vendor/github.com/jackc/pgproto3/v2/pgproto3.go
new file mode 100644
index 000000000..70c825e3c
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/pgproto3.go
@@ -0,0 +1,65 @@
+package pgproto3
+
+import (
+ "encoding/hex"
+ "errors"
+ "fmt"
+)
+
+// Message is the interface implemented by an object that can decode and encode
+// a particular PostgreSQL message.
+type Message interface {
+ // Decode is allowed and expected to retain a reference to data after
+ // returning (unlike encoding.BinaryUnmarshaler).
+ Decode(data []byte) error
+
+ // Encode appends itself to dst and returns the new buffer.
+ Encode(dst []byte) []byte
+}
+
+type FrontendMessage interface {
+ Message
+ Frontend() // no-op method to distinguish frontend from backend methods
+}
+
+type BackendMessage interface {
+ Message
+ Backend() // no-op method to distinguish frontend from backend methods
+}
+
+type AuthenticationResponseMessage interface {
+ BackendMessage
+ AuthenticationResponse() // no-op method to distinguish authentication responses
+}
+
+type invalidMessageLenErr struct {
+ messageType string
+ expectedLen int
+ actualLen int
+}
+
+func (e *invalidMessageLenErr) Error() string {
+ return fmt.Sprintf("%s body must have length of %d, but it is %d", e.messageType, e.expectedLen, e.actualLen)
+}
+
+type invalidMessageFormatErr struct {
+ messageType string
+}
+
+func (e *invalidMessageFormatErr) Error() string {
+ return fmt.Sprintf("%s body is invalid", e.messageType)
+}
+
+// getValueFromJSON gets the value from a protocol message representation in JSON.
+func getValueFromJSON(v map[string]string) ([]byte, error) {
+ if v == nil {
+ return nil, nil
+ }
+ if text, ok := v["text"]; ok {
+ return []byte(text), nil
+ }
+ if binary, ok := v["binary"]; ok {
+ return hex.DecodeString(binary)
+ }
+ return nil, errors.New("unknown protocol representation")
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/portal_suspended.go b/vendor/github.com/jackc/pgproto3/v2/portal_suspended.go
new file mode 100644
index 000000000..1a9e7bfb1
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/portal_suspended.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type PortalSuspended struct{}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*PortalSuspended) Backend() {}
+
+// 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 *PortalSuspended) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "PortalSuspended", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 's', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src PortalSuspended) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "PortalSuspended",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/query.go b/vendor/github.com/jackc/pgproto3/v2/query.go
new file mode 100644
index 000000000..41c93b4a8
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/query.go
@@ -0,0 +1,50 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type Query struct {
+ String string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Query) 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 *Query) Decode(src []byte) error {
+ i := bytes.IndexByte(src, 0)
+ if i != len(src)-1 {
+ return &invalidMessageFormatErr{messageType: "Query"}
+ }
+
+ dst.String = string(src[:i])
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'Q')
+ dst = pgio.AppendInt32(dst, int32(4+len(src.String)+1))
+
+ dst = append(dst, src.String...)
+ dst = append(dst, 0)
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Query) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ String string
+ }{
+ Type: "Query",
+ String: src.String,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/ready_for_query.go b/vendor/github.com/jackc/pgproto3/v2/ready_for_query.go
new file mode 100644
index 000000000..67a39be39
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/ready_for_query.go
@@ -0,0 +1,61 @@
+package pgproto3
+
+import (
+ "encoding/json"
+ "errors"
+)
+
+type ReadyForQuery struct {
+ TxStatus byte
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*ReadyForQuery) Backend() {}
+
+// 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 *ReadyForQuery) Decode(src []byte) error {
+ if len(src) != 1 {
+ return &invalidMessageLenErr{messageType: "ReadyForQuery", expectedLen: 1, actualLen: len(src)}
+ }
+
+ dst.TxStatus = src[0]
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'Z', 0, 0, 0, 5, src.TxStatus)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src ReadyForQuery) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ TxStatus string
+ }{
+ Type: "ReadyForQuery",
+ TxStatus: string(src.TxStatus),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *ReadyForQuery) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ TxStatus string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+ if len(msg.TxStatus) != 1 {
+ return errors.New("invalid length for ReadyForQuery.TxStatus")
+ }
+ dst.TxStatus = msg.TxStatus[0]
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/row_description.go b/vendor/github.com/jackc/pgproto3/v2/row_description.go
new file mode 100644
index 000000000..a2e0d28e2
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/row_description.go
@@ -0,0 +1,165 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+const (
+ TextFormat = 0
+ BinaryFormat = 1
+)
+
+type FieldDescription struct {
+ Name []byte
+ TableOID uint32
+ TableAttributeNumber uint16
+ DataTypeOID uint32
+ DataTypeSize int16
+ TypeModifier int32
+ Format int16
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (fd FieldDescription) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Name string
+ TableOID uint32
+ TableAttributeNumber uint16
+ DataTypeOID uint32
+ DataTypeSize int16
+ TypeModifier int32
+ Format int16
+ }{
+ Name: string(fd.Name),
+ TableOID: fd.TableOID,
+ TableAttributeNumber: fd.TableAttributeNumber,
+ DataTypeOID: fd.DataTypeOID,
+ DataTypeSize: fd.DataTypeSize,
+ TypeModifier: fd.TypeModifier,
+ Format: fd.Format,
+ })
+}
+
+type RowDescription struct {
+ Fields []FieldDescription
+}
+
+// Backend identifies this message as sendable by the PostgreSQL backend.
+func (*RowDescription) Backend() {}
+
+// 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 *RowDescription) Decode(src []byte) error {
+
+ if len(src) < 2 {
+ return &invalidMessageFormatErr{messageType: "RowDescription"}
+ }
+ fieldCount := int(binary.BigEndian.Uint16(src))
+ rp := 2
+
+ dst.Fields = dst.Fields[0:0]
+
+ for i := 0; i < fieldCount; i++ {
+ var fd FieldDescription
+
+ idx := bytes.IndexByte(src[rp:], 0)
+ if idx < 0 {
+ return &invalidMessageFormatErr{messageType: "RowDescription"}
+ }
+ fd.Name = src[rp : rp+idx]
+ rp += idx + 1
+
+ // Since buf.Next() doesn't return an error if we hit the end of the buffer
+ // check Len ahead of time
+ if len(src[rp:]) < 18 {
+ return &invalidMessageFormatErr{messageType: "RowDescription"}
+ }
+
+ fd.TableOID = binary.BigEndian.Uint32(src[rp:])
+ rp += 4
+ fd.TableAttributeNumber = binary.BigEndian.Uint16(src[rp:])
+ rp += 2
+ fd.DataTypeOID = binary.BigEndian.Uint32(src[rp:])
+ rp += 4
+ fd.DataTypeSize = int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ fd.TypeModifier = int32(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+ fd.Format = int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ dst.Fields = append(dst.Fields, fd)
+ }
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'T')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint16(dst, uint16(len(src.Fields)))
+ for _, fd := range src.Fields {
+ dst = append(dst, fd.Name...)
+ dst = append(dst, 0)
+
+ dst = pgio.AppendUint32(dst, fd.TableOID)
+ dst = pgio.AppendUint16(dst, fd.TableAttributeNumber)
+ dst = pgio.AppendUint32(dst, fd.DataTypeOID)
+ dst = pgio.AppendInt16(dst, fd.DataTypeSize)
+ dst = pgio.AppendInt32(dst, fd.TypeModifier)
+ dst = pgio.AppendInt16(dst, fd.Format)
+ }
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src RowDescription) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Fields []FieldDescription
+ }{
+ Type: "RowDescription",
+ Fields: src.Fields,
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *RowDescription) UnmarshalJSON(data []byte) error {
+ var msg struct {
+ Fields []struct {
+ Name string
+ TableOID uint32
+ TableAttributeNumber uint16
+ DataTypeOID uint32
+ DataTypeSize int16
+ TypeModifier int32
+ Format int16
+ }
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+ dst.Fields = make([]FieldDescription, len(msg.Fields))
+ for n, field := range msg.Fields {
+ dst.Fields[n] = FieldDescription{
+ Name: []byte(field.Name),
+ TableOID: field.TableOID,
+ TableAttributeNumber: field.TableAttributeNumber,
+ DataTypeOID: field.DataTypeOID,
+ DataTypeSize: field.DataTypeSize,
+ TypeModifier: field.TypeModifier,
+ Format: field.Format,
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go b/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go
new file mode 100644
index 000000000..f7e5f36a9
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go
@@ -0,0 +1,94 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+type SASLInitialResponse struct {
+ AuthMechanism string
+ Data []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SASLInitialResponse) 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 *SASLInitialResponse) Decode(src []byte) error {
+ *dst = SASLInitialResponse{}
+
+ rp := 0
+
+ idx := bytes.IndexByte(src, 0)
+ if idx < 0 {
+ return errors.New("invalid SASLInitialResponse")
+ }
+
+ dst.AuthMechanism = string(src[rp:idx])
+ rp = idx + 1
+
+ rp += 4 // The rest of the message is data so we can just skip the size
+ dst.Data = src[rp:]
+
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'p')
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = append(dst, []byte(src.AuthMechanism)...)
+ dst = append(dst, 0)
+
+ dst = pgio.AppendInt32(dst, int32(len(src.Data)))
+ dst = append(dst, src.Data...)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SASLInitialResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ AuthMechanism string
+ Data string
+ }{
+ Type: "SASLInitialResponse",
+ AuthMechanism: src.AuthMechanism,
+ Data: hex.EncodeToString(src.Data),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *SASLInitialResponse) UnmarshalJSON(data []byte) error {
+ // Ignore null, like in the main JSON package.
+ if string(data) == "null" {
+ return nil
+ }
+
+ var msg struct {
+ AuthMechanism string
+ Data string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+ dst.AuthMechanism = msg.AuthMechanism
+ if msg.Data != "" {
+ decoded, err := hex.DecodeString(msg.Data)
+ if err != nil {
+ return err
+ }
+ dst.Data = decoded
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/sasl_response.go b/vendor/github.com/jackc/pgproto3/v2/sasl_response.go
new file mode 100644
index 000000000..41fb4c397
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/sasl_response.go
@@ -0,0 +1,61 @@
+package pgproto3
+
+import (
+ "encoding/hex"
+ "encoding/json"
+
+ "github.com/jackc/pgio"
+)
+
+type SASLResponse struct {
+ Data []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SASLResponse) 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 *SASLResponse) Decode(src []byte) error {
+ *dst = SASLResponse{Data: src}
+ return nil
+}
+
+// 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 {
+ dst = append(dst, 'p')
+ dst = pgio.AppendInt32(dst, int32(4+len(src.Data)))
+
+ dst = append(dst, src.Data...)
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SASLResponse) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ Data string
+ }{
+ Type: "SASLResponse",
+ Data: hex.EncodeToString(src.Data),
+ })
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (dst *SASLResponse) UnmarshalJSON(data []byte) error {
+ var msg struct {
+ Data string
+ }
+ if err := json.Unmarshal(data, &msg); err != nil {
+ return err
+ }
+ if msg.Data != "" {
+ decoded, err := hex.DecodeString(msg.Data)
+ if err != nil {
+ return err
+ }
+ dst.Data = decoded
+ }
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/ssl_request.go b/vendor/github.com/jackc/pgproto3/v2/ssl_request.go
new file mode 100644
index 000000000..96ce489e5
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/ssl_request.go
@@ -0,0 +1,49 @@
+package pgproto3
+
+import (
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+
+ "github.com/jackc/pgio"
+)
+
+const sslRequestNumber = 80877103
+
+type SSLRequest struct {
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*SSLRequest) Frontend() {}
+
+func (dst *SSLRequest) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("ssl request too short")
+ }
+
+ requestCode := binary.BigEndian.Uint32(src)
+
+ if requestCode != sslRequestNumber {
+ return errors.New("bad ssl request code")
+ }
+
+ return nil
+}
+
+// Encode encodes src into dst. dst will include the 4 byte message length.
+func (src *SSLRequest) Encode(dst []byte) []byte {
+ dst = pgio.AppendInt32(dst, 8)
+ dst = pgio.AppendInt32(dst, sslRequestNumber)
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src SSLRequest) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ProtocolVersion uint32
+ Parameters map[string]string
+ }{
+ Type: "SSLRequest",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/startup_message.go b/vendor/github.com/jackc/pgproto3/v2/startup_message.go
new file mode 100644
index 000000000..5f1cd24f7
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/startup_message.go
@@ -0,0 +1,96 @@
+package pgproto3
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/json"
+ "errors"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+const ProtocolVersionNumber = 196608 // 3.0
+
+type StartupMessage struct {
+ ProtocolVersion uint32
+ Parameters map[string]string
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*StartupMessage) 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 *StartupMessage) Decode(src []byte) error {
+ if len(src) < 4 {
+ return errors.New("startup message too short")
+ }
+
+ dst.ProtocolVersion = binary.BigEndian.Uint32(src)
+ rp := 4
+
+ if dst.ProtocolVersion != ProtocolVersionNumber {
+ return fmt.Errorf("Bad startup message version number. Expected %d, got %d", ProtocolVersionNumber, dst.ProtocolVersion)
+ }
+
+ dst.Parameters = make(map[string]string)
+ for {
+ idx := bytes.IndexByte(src[rp:], 0)
+ if idx < 0 {
+ return &invalidMessageFormatErr{messageType: "StartupMesage"}
+ }
+ key := string(src[rp : rp+idx])
+ rp += idx + 1
+
+ idx = bytes.IndexByte(src[rp:], 0)
+ if idx < 0 {
+ return &invalidMessageFormatErr{messageType: "StartupMesage"}
+ }
+ value := string(src[rp : rp+idx])
+ rp += idx + 1
+
+ dst.Parameters[key] = value
+
+ if len(src[rp:]) == 1 {
+ if src[rp] != 0 {
+ return fmt.Errorf("Bad startup message last byte. Expected 0, got %d", src[rp])
+ }
+ break
+ }
+ }
+
+ return nil
+}
+
+// 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 {
+ sp := len(dst)
+ dst = pgio.AppendInt32(dst, -1)
+
+ dst = pgio.AppendUint32(dst, src.ProtocolVersion)
+ for k, v := range src.Parameters {
+ dst = append(dst, k...)
+ dst = append(dst, 0)
+ dst = append(dst, v...)
+ dst = append(dst, 0)
+ }
+ dst = append(dst, 0)
+
+ pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
+
+ return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src StartupMessage) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ ProtocolVersion uint32
+ Parameters map[string]string
+ }{
+ Type: "StartupMessage",
+ ProtocolVersion: src.ProtocolVersion,
+ Parameters: src.Parameters,
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/sync.go b/vendor/github.com/jackc/pgproto3/v2/sync.go
new file mode 100644
index 000000000..5db8e07ac
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/sync.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type Sync struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Sync) 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 *Sync) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "Sync", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'S', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Sync) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "Sync",
+ })
+}
diff --git a/vendor/github.com/jackc/pgproto3/v2/terminate.go b/vendor/github.com/jackc/pgproto3/v2/terminate.go
new file mode 100644
index 000000000..135191eae
--- /dev/null
+++ b/vendor/github.com/jackc/pgproto3/v2/terminate.go
@@ -0,0 +1,34 @@
+package pgproto3
+
+import (
+ "encoding/json"
+)
+
+type Terminate struct{}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (*Terminate) 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 *Terminate) Decode(src []byte) error {
+ if len(src) != 0 {
+ return &invalidMessageLenErr{messageType: "Terminate", expectedLen: 0, actualLen: len(src)}
+ }
+
+ return nil
+}
+
+// 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 {
+ return append(dst, 'X', 0, 0, 0, 4)
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (src Terminate) MarshalJSON() ([]byte, error) {
+ return json.Marshal(struct {
+ Type string
+ }{
+ Type: "Terminate",
+ })
+}
diff --git a/vendor/github.com/jackc/pgservicefile/.travis.yml b/vendor/github.com/jackc/pgservicefile/.travis.yml
new file mode 100644
index 000000000..e176228e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/.travis.yml
@@ -0,0 +1,9 @@
+language: go
+
+go:
+ - 1.x
+ - tip
+
+matrix:
+ allow_failures:
+ - go: tip
diff --git a/vendor/github.com/jackc/pgservicefile/LICENSE b/vendor/github.com/jackc/pgservicefile/LICENSE
new file mode 100644
index 000000000..f1b4c2892
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2020 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgservicefile/README.md b/vendor/github.com/jackc/pgservicefile/README.md
new file mode 100644
index 000000000..e50ca1262
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/README.md
@@ -0,0 +1,6 @@
+[![](https://godoc.org/github.com/jackc/pgservicefile?status.svg)](https://godoc.org/github.com/jackc/pgservicefile)
+[![Build Status](https://travis-ci.org/jackc/pgservicefile.svg)](https://travis-ci.org/jackc/pgservicefile)
+
+# pgservicefile
+
+Package pgservicefile is a parser for PostgreSQL service files (e.g. `.pg_service.conf`).
diff --git a/vendor/github.com/jackc/pgservicefile/go.mod b/vendor/github.com/jackc/pgservicefile/go.mod
new file mode 100644
index 000000000..051e9e0f4
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/go.mod
@@ -0,0 +1,5 @@
+module github.com/jackc/pgservicefile
+
+go 1.14
+
+require github.com/stretchr/testify v1.5.1
diff --git a/vendor/github.com/jackc/pgservicefile/go.sum b/vendor/github.com/jackc/pgservicefile/go.sum
new file mode 100644
index 000000000..a80206ab1
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/go.sum
@@ -0,0 +1,10 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/vendor/github.com/jackc/pgservicefile/pgservicefile.go b/vendor/github.com/jackc/pgservicefile/pgservicefile.go
new file mode 100644
index 000000000..797bbab9e
--- /dev/null
+++ b/vendor/github.com/jackc/pgservicefile/pgservicefile.go
@@ -0,0 +1,79 @@
+// Package pgservicefile is a parser for PostgreSQL service files (e.g. .pg_service.conf).
+package pgservicefile
+
+import (
+ "bufio"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+)
+
+type Service struct {
+ Name string
+ Settings map[string]string
+}
+
+type Servicefile struct {
+ Services []*Service
+ servicesByName map[string]*Service
+}
+
+// GetService returns the named service.
+func (sf *Servicefile) GetService(name string) (*Service, error) {
+ service, present := sf.servicesByName[name]
+ if !present {
+ return nil, errors.New("not found")
+ }
+ return service, nil
+}
+
+// ReadServicefile reads the file at path and parses it into a Servicefile.
+func ReadServicefile(path string) (*Servicefile, error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ return ParseServicefile(f)
+}
+
+// ParseServicefile reads r and parses it into a Servicefile.
+func ParseServicefile(r io.Reader) (*Servicefile, error) {
+ servicefile := &Servicefile{}
+
+ var service *Service
+ scanner := bufio.NewScanner(r)
+ lineNum := 0
+ for scanner.Scan() {
+ lineNum += 1
+ line := scanner.Text()
+ line = strings.TrimSpace(line)
+
+ if line == "" || strings.HasPrefix(line, "#") {
+ // ignore comments and empty lines
+ } else if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
+ service = &Service{Name: line[1 : len(line)-1], Settings: make(map[string]string)}
+ servicefile.Services = append(servicefile.Services, service)
+ } else {
+ parts := strings.SplitN(line, "=", 2)
+ if len(parts) != 2 {
+ return nil, fmt.Errorf("unable to parse line %d", lineNum)
+ }
+
+ key := strings.TrimSpace(parts[0])
+ value := strings.TrimSpace(parts[1])
+
+ service.Settings[key] = value
+ }
+ }
+
+ servicefile.servicesByName = make(map[string]*Service, len(servicefile.Services))
+ for _, service := range servicefile.Services {
+ servicefile.servicesByName[service.Name] = service
+ }
+
+ return servicefile, scanner.Err()
+}
diff --git a/vendor/github.com/jackc/pgtype/.travis.yml b/vendor/github.com/jackc/pgtype/.travis.yml
new file mode 100644
index 000000000..d67627350
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/.travis.yml
@@ -0,0 +1,34 @@
+# 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 \ No newline at end of file
diff --git a/vendor/github.com/jackc/pgtype/CHANGELOG.md b/vendor/github.com/jackc/pgtype/CHANGELOG.md
new file mode 100644
index 000000000..64d96fa00
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/CHANGELOG.md
@@ -0,0 +1,103 @@
+# 1.8.1 (July 24, 2021)
+
+* Cleaned up Go module dependency chain
+
+# 1.8.0 (July 10, 2021)
+
+* Maintain host bits for inet types (Cameron Daniel)
+* Support pointers of wrapping structs (Ivan Daunis)
+* Register JSONBArray at NewConnInfo() (Rueian)
+* CompositeTextScanner handles backslash escapes
+
+# 1.7.0 (March 25, 2021)
+
+* Fix scanning int into **sql.Scanner implementor
+* Add tsrange array type (Vasilii Novikov)
+* Fix: escaped strings when they start or end with a newline char (Stephane Martin)
+* Accept nil *time.Time in Time.Set
+* Fix numeric NaN support
+* Use Go 1.13 errors instead of xerrors
+
+# 1.6.2 (December 3, 2020)
+
+* Fix panic on assigning empty array to non-slice or array
+* Fix text array parsing disambiguates NULL and "NULL"
+* Fix Timestamptz.DecodeText with too short text
+
+# 1.6.1 (October 31, 2020)
+
+* Fix simple protocol empty array support
+
+# 1.6.0 (October 24, 2020)
+
+* Fix AssignTo pointer to pointer to slice and named types.
+* Fix zero length array assignment (Simo Haasanen)
+* Add float64, float32 convert to int2, int4, int8 (lqu3j)
+* Support setting infinite timestamps (Erik Agsjö)
+* Polygon improvements (duohedron)
+* Fix Inet.Set with nil (Tomas Volf)
+
+# 1.5.0 (September 26, 2020)
+
+* Add slice of slice mapping to multi-dimensional arrays (Simo Haasanen)
+* Fix JSONBArray
+* Fix selecting empty array
+* Text formatted values except bytea can be directly scanned to []byte
+* Add JSON marshalling for UUID (bakmataliev)
+* Improve point type conversions (bakmataliev)
+
+# 1.4.2 (July 22, 2020)
+
+* Fix encoding of a large composite data type (Yaz Saito)
+
+# 1.4.1 (July 14, 2020)
+
+* Fix ArrayType DecodeBinary empty array breaks future reads
+
+# 1.4.0 (June 27, 2020)
+
+* Add JSON support to ext/gofrs-uuid
+* Performance improvements in Scan path
+* Improved ext/shopspring-numeric binary decoding performance
+* Add composite type support (Maxim Ivanov and Jack Christensen)
+* Add better generic enum type support
+* Add generic array type support
+* Clarify and normalize Value semantics
+* Fix hstore with empty string values
+* Numeric supports NaN values (leighhopcroft)
+* Add slice of pointer support to array types (megaturbo)
+* Add jsonb array type (tserakhau)
+* Allow converting intervals with months and days to duration
+
+# 1.3.0 (March 30, 2020)
+
+* Get implemented on T instead of *T
+* Set will call Get on src if possible
+* Range types Set method supports its own type, string, and nil
+* Date.Set parses string
+* Fix correct format verb for unknown type error (Robert Welin)
+* Truncate nanoseconds in EncodeText for Timestamptz and Timestamp
+
+# 1.2.0 (February 5, 2020)
+
+* Add zeronull package for easier NULL <-> zero conversion
+* Add JSON marshalling for shopspring-numeric extension
+* Add JSON marshalling for Bool, Date, JSON/B, Timestamptz (Jeffrey Stiles)
+* Fix null status in UnmarshalJSON for some types (Jeffrey Stiles)
+
+# 1.1.0 (January 11, 2020)
+
+* Add PostgreSQL time type support
+* Add more automatic conversions of integer arrays of different types (Jean-Philippe Quéméner)
+
+# 1.0.3 (November 16, 2019)
+
+* Support initializing Array types from a slice of the value (Alex Gaynor)
+
+# 1.0.2 (October 22, 2019)
+
+* Fix scan into null into pointer to pointer implementing Decode* interface. (Jeremy Altavilla)
+
+# 1.0.1 (September 19, 2019)
+
+* Fix daterange OID
diff --git a/vendor/github.com/jackc/pgtype/LICENSE b/vendor/github.com/jackc/pgtype/LICENSE
new file mode 100644
index 000000000..5c486c39a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2021 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgtype/README.md b/vendor/github.com/jackc/pgtype/README.md
new file mode 100644
index 000000000..77d59b313
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/README.md
@@ -0,0 +1,8 @@
+[![](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)
+
+# pgtype
+
+pgtype implements Go types for over 70 PostgreSQL types. pgtype is the type system underlying the
+https://github.com/jackc/pgx PostgreSQL driver. These types support the binary format for enhanced performance with pgx.
+They also support the database/sql `Scan` and `Value` interfaces and can be used with https://github.com/lib/pq.
diff --git a/vendor/github.com/jackc/pgtype/aclitem.go b/vendor/github.com/jackc/pgtype/aclitem.go
new file mode 100644
index 000000000..9f6587be7
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/aclitem.go
@@ -0,0 +1,138 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+)
+
+// ACLItem is used for PostgreSQL's aclitem data type. A sample aclitem
+// might look like this:
+//
+// postgres=arwdDxt/postgres
+//
+// Note, however, that because the user/role name part of an aclitem is
+// an identifier, it follows all the usual formatting rules for SQL
+// identifiers: if it contains spaces and other special characters,
+// it should appear in double-quotes:
+//
+// postgres=arwdDxt/"role with spaces"
+//
+type ACLItem struct {
+ String string
+ Status Status
+}
+
+func (dst *ACLItem) Set(src interface{}) error {
+ if src == nil {
+ *dst = ACLItem{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case string:
+ *dst = ACLItem{String: value, Status: Present}
+ case *string:
+ if value == nil {
+ *dst = ACLItem{Status: Null}
+ } else {
+ *dst = ACLItem{String: *value, Status: Present}
+ }
+ default:
+ if originalSrc, ok := underlyingStringType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to ACLItem", value)
+ }
+
+ return nil
+}
+
+func (dst ACLItem) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.String
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *ACLItem) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *string:
+ *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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *ACLItem) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = ACLItem{Status: Null}
+ return nil
+ }
+
+ *dst = ACLItem{String: string(src), Status: Present}
+ return nil
+}
+
+func (src ACLItem) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.String...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *ACLItem) Scan(src interface{}) error {
+ if src == nil {
+ *dst = ACLItem{Status: Null}
+ return 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 ACLItem) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.String, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/aclitem_array.go b/vendor/github.com/jackc/pgtype/aclitem_array.go
new file mode 100644
index 000000000..4e3be3bda
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/aclitem_array.go
@@ -0,0 +1,428 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+)
+
+type ACLItemArray struct {
+ Elements []ACLItem
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *ACLItemArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = ACLItemArray{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 = ACLItemArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = ACLItemArray{Status: Present}
+ } else {
+ elements := make([]ACLItem, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = ACLItemArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = ACLItemArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = ACLItemArray{Status: Present}
+ } else {
+ elements := make([]ACLItem, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = ACLItemArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []ACLItem:
+ if value == nil {
+ *dst = ACLItemArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = ACLItemArray{Status: Present}
+ } else {
+ *dst = ACLItemArray{
+ 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 = ACLItemArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for ACLItemArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = ACLItemArray{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 ACLItemArray", src)
+ }
+
+ *dst = ACLItemArray{
+ Elements: make([]ACLItem, 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([]ACLItem, 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 ACLItemArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *ACLItemArray) 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 ACLItemArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in ACLItemArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst ACLItemArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *ACLItemArray) 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 *[]*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
+
+ }
+ }
+
+ // 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 *ACLItemArray) 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 ACLItemArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from ACLItemArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *ACLItemArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = ACLItemArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []ACLItem
+
+ if len(uta.Elements) > 0 {
+ elements = make([]ACLItem, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem ACLItem
+ 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 = ACLItemArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (src ACLItemArray) 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
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *ACLItemArray) 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 ACLItemArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/array.go b/vendor/github.com/jackc/pgtype/array.go
new file mode 100644
index 000000000..3d5930c1c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/array.go
@@ -0,0 +1,381 @@
+package pgtype
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "github.com/jackc/pgio"
+)
+
+// Information on the internals of PostgreSQL arrays can be found in
+// src/include/utils/array.h and src/backend/utils/adt/arrayfuncs.c. Of
+// particular interest is the array_send function.
+
+type ArrayHeader struct {
+ ContainsNull bool
+ ElementOID int32
+ Dimensions []ArrayDimension
+}
+
+type ArrayDimension struct {
+ Length int32
+ LowerBound int32
+}
+
+func (dst *ArrayHeader) DecodeBinary(ci *ConnInfo, src []byte) (int, error) {
+ if len(src) < 12 {
+ return 0, fmt.Errorf("array header too short: %d", len(src))
+ }
+
+ rp := 0
+
+ numDims := int(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ dst.ContainsNull = binary.BigEndian.Uint32(src[rp:]) == 1
+ rp += 4
+
+ dst.ElementOID = int32(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ if numDims > 0 {
+ dst.Dimensions = make([]ArrayDimension, numDims)
+ }
+ if len(src) < 12+numDims*8 {
+ return 0, fmt.Errorf("array header too short for %d dimensions: %d", numDims, len(src))
+ }
+ for i := range dst.Dimensions {
+ dst.Dimensions[i].Length = int32(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ dst.Dimensions[i].LowerBound = int32(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+ }
+
+ return rp, nil
+}
+
+func (src ArrayHeader) EncodeBinary(ci *ConnInfo, buf []byte) []byte {
+ buf = pgio.AppendInt32(buf, int32(len(src.Dimensions)))
+
+ var containsNull int32
+ if src.ContainsNull {
+ containsNull = 1
+ }
+ buf = pgio.AppendInt32(buf, containsNull)
+
+ buf = pgio.AppendInt32(buf, src.ElementOID)
+
+ for i := range src.Dimensions {
+ buf = pgio.AppendInt32(buf, src.Dimensions[i].Length)
+ buf = pgio.AppendInt32(buf, src.Dimensions[i].LowerBound)
+ }
+
+ return buf
+}
+
+type UntypedTextArray struct {
+ Elements []string
+ Quoted []bool
+ Dimensions []ArrayDimension
+}
+
+func ParseUntypedTextArray(src string) (*UntypedTextArray, error) {
+ dst := &UntypedTextArray{}
+
+ buf := bytes.NewBufferString(src)
+
+ skipWhitespace(buf)
+
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ var explicitDimensions []ArrayDimension
+
+ // Array has explicit dimensions
+ if r == '[' {
+ buf.UnreadRune()
+
+ for {
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ if r == '=' {
+ break
+ } else if r != '[' {
+ return nil, fmt.Errorf("invalid array, expected '[' or '=' got %v", r)
+ }
+
+ lower, err := arrayParseInteger(buf)
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ if r != ':' {
+ return nil, fmt.Errorf("invalid array, expected ':' got %v", r)
+ }
+
+ upper, err := arrayParseInteger(buf)
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ if r != ']' {
+ return nil, fmt.Errorf("invalid array, expected ']' got %v", r)
+ }
+
+ explicitDimensions = append(explicitDimensions, ArrayDimension{LowerBound: lower, Length: upper - lower + 1})
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+ }
+
+ if r != '{' {
+ return nil, fmt.Errorf("invalid array, expected '{': %v", err)
+ }
+
+ implicitDimensions := []ArrayDimension{{LowerBound: 1, Length: 0}}
+
+ // Consume all initial opening brackets. This provides number of dimensions.
+ for {
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ if r == '{' {
+ implicitDimensions[len(implicitDimensions)-1].Length = 1
+ implicitDimensions = append(implicitDimensions, ArrayDimension{LowerBound: 1})
+ } else {
+ buf.UnreadRune()
+ break
+ }
+ }
+ currentDim := len(implicitDimensions) - 1
+ counterDim := currentDim
+
+ for {
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid array: %v", err)
+ }
+
+ switch r {
+ case '{':
+ if currentDim == counterDim {
+ implicitDimensions[currentDim].Length++
+ }
+ currentDim++
+ case ',':
+ case '}':
+ currentDim--
+ if currentDim < counterDim {
+ counterDim = currentDim
+ }
+ default:
+ buf.UnreadRune()
+ value, quoted, err := arrayParseValue(buf)
+ if err != nil {
+ return nil, fmt.Errorf("invalid array value: %v", err)
+ }
+ if currentDim == counterDim {
+ implicitDimensions[currentDim].Length++
+ }
+ dst.Quoted = append(dst.Quoted, quoted)
+ dst.Elements = append(dst.Elements, value)
+ }
+
+ if currentDim < 0 {
+ break
+ }
+ }
+
+ skipWhitespace(buf)
+
+ if buf.Len() > 0 {
+ return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
+ }
+
+ if len(dst.Elements) == 0 {
+ dst.Dimensions = nil
+ } else if len(explicitDimensions) > 0 {
+ dst.Dimensions = explicitDimensions
+ } else {
+ dst.Dimensions = implicitDimensions
+ }
+
+ return dst, nil
+}
+
+func skipWhitespace(buf *bytes.Buffer) {
+ var r rune
+ var err error
+ for r, _, _ = buf.ReadRune(); unicode.IsSpace(r); r, _, _ = buf.ReadRune() {
+ }
+
+ if err != io.EOF {
+ buf.UnreadRune()
+ }
+}
+
+func arrayParseValue(buf *bytes.Buffer) (string, bool, error) {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", false, err
+ }
+ if r == '"' {
+ return arrayParseQuotedValue(buf)
+ }
+ buf.UnreadRune()
+
+ s := &bytes.Buffer{}
+
+ for {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", false, err
+ }
+
+ switch r {
+ case ',', '}':
+ buf.UnreadRune()
+ return s.String(), false, nil
+ }
+
+ s.WriteRune(r)
+ }
+}
+
+func arrayParseQuotedValue(buf *bytes.Buffer) (string, bool, error) {
+ s := &bytes.Buffer{}
+
+ for {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", false, err
+ }
+
+ switch r {
+ case '\\':
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return "", false, err
+ }
+ case '"':
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return "", false, err
+ }
+ buf.UnreadRune()
+ return s.String(), true, nil
+ }
+ s.WriteRune(r)
+ }
+}
+
+func arrayParseInteger(buf *bytes.Buffer) (int32, error) {
+ s := &bytes.Buffer{}
+
+ for {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return 0, err
+ }
+
+ if '0' <= r && r <= '9' {
+ s.WriteRune(r)
+ } else {
+ buf.UnreadRune()
+ n, err := strconv.ParseInt(s.String(), 10, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(n), nil
+ }
+ }
+}
+
+func EncodeTextArrayDimensions(buf []byte, dimensions []ArrayDimension) []byte {
+ var customDimensions bool
+ for _, dim := range dimensions {
+ if dim.LowerBound != 1 {
+ customDimensions = true
+ }
+ }
+
+ if !customDimensions {
+ return buf
+ }
+
+ for _, dim := range dimensions {
+ buf = append(buf, '[')
+ buf = append(buf, strconv.FormatInt(int64(dim.LowerBound), 10)...)
+ buf = append(buf, ':')
+ buf = append(buf, strconv.FormatInt(int64(dim.LowerBound+dim.Length-1), 10)...)
+ buf = append(buf, ']')
+ }
+
+ return append(buf, '=')
+}
+
+var quoteArrayReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
+
+func quoteArrayElement(src string) string {
+ return `"` + quoteArrayReplacer.Replace(src) + `"`
+}
+
+func isSpace(ch byte) bool {
+ // see https://github.com/postgres/postgres/blob/REL_12_STABLE/src/backend/parser/scansup.c#L224
+ return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == '\f'
+}
+
+func QuoteArrayElementIfNeeded(src string) string {
+ if src == "" || (len(src) == 4 && strings.ToLower(src) == "null") || isSpace(src[0]) || isSpace(src[len(src)-1]) || strings.ContainsAny(src, `{},"\`) {
+ return quoteArrayElement(src)
+ }
+ return src
+}
+
+func findDimensionsFromValue(value reflect.Value, dimensions []ArrayDimension, elementsLength int) ([]ArrayDimension, int, bool) {
+ switch value.Kind() {
+ case reflect.Array:
+ fallthrough
+ case reflect.Slice:
+ length := value.Len()
+ if 0 == elementsLength {
+ elementsLength = length
+ } else {
+ elementsLength *= length
+ }
+ dimensions = append(dimensions, ArrayDimension{Length: int32(length), LowerBound: 1})
+ for i := 0; i < length; i++ {
+ if d, l, ok := findDimensionsFromValue(value.Index(i), dimensions, elementsLength); ok {
+ return d, l, true
+ }
+ }
+ }
+ return dimensions, elementsLength, true
+}
diff --git a/vendor/github.com/jackc/pgtype/array_type.go b/vendor/github.com/jackc/pgtype/array_type.go
new file mode 100644
index 000000000..1bd0244b7
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/array_type.go
@@ -0,0 +1,353 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+// 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
+// type for types that do not have an concrete array type.
+type ArrayType struct {
+ elements []ValueTranscoder
+ dimensions []ArrayDimension
+
+ typeName string
+ newElement func() ValueTranscoder
+
+ elementOID uint32
+ status Status
+}
+
+func NewArrayType(typeName string, elementOID uint32, newElement func() ValueTranscoder) *ArrayType {
+ return &ArrayType{typeName: typeName, elementOID: elementOID, newElement: newElement}
+}
+
+func (at *ArrayType) NewTypeValue() Value {
+ return &ArrayType{
+ elements: at.elements,
+ dimensions: at.dimensions,
+ status: at.status,
+
+ typeName: at.typeName,
+ elementOID: at.elementOID,
+ newElement: at.newElement,
+ }
+}
+
+func (at *ArrayType) TypeName() string {
+ return at.typeName
+}
+
+func (dst *ArrayType) setNil() {
+ dst.elements = nil
+ dst.dimensions = nil
+ dst.status = Null
+}
+
+func (dst *ArrayType) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ dst.setNil()
+ return nil
+ }
+
+ sliceVal := reflect.ValueOf(src)
+ if sliceVal.Kind() != reflect.Slice {
+ return fmt.Errorf("cannot set non-slice")
+ }
+
+ if sliceVal.IsNil() {
+ dst.setNil()
+ return nil
+ }
+
+ dst.elements = make([]ValueTranscoder, sliceVal.Len())
+ for i := range dst.elements {
+ v := dst.newElement()
+ err := v.Set(sliceVal.Index(i).Interface())
+ if err != nil {
+ return err
+ }
+
+ dst.elements[i] = v
+ }
+ dst.dimensions = []ArrayDimension{{Length: int32(len(dst.elements)), LowerBound: 1}}
+ dst.status = Present
+
+ return nil
+}
+
+func (dst ArrayType) Get() interface{} {
+ switch dst.status {
+ case Present:
+ elementValues := make([]interface{}, len(dst.elements))
+ for i := range dst.elements {
+ elementValues[i] = dst.elements[i].Get()
+ }
+ return elementValues
+ case Null:
+ return nil
+ default:
+ return dst.status
+ }
+}
+
+func (src *ArrayType) AssignTo(dst interface{}) error {
+ ptrSlice := reflect.ValueOf(dst)
+ if ptrSlice.Kind() != reflect.Ptr {
+ return fmt.Errorf("cannot assign to non-pointer")
+ }
+
+ sliceVal := ptrSlice.Elem()
+ sliceType := sliceVal.Type()
+
+ if sliceType.Kind() != reflect.Slice {
+ return fmt.Errorf("cannot assign to pointer to non-slice")
+ }
+
+ switch src.status {
+ case Present:
+ slice := reflect.MakeSlice(sliceType, len(src.elements), len(src.elements))
+ elemType := sliceType.Elem()
+
+ for i := range src.elements {
+ ptrElem := reflect.New(elemType)
+ err := src.elements[i].AssignTo(ptrElem.Interface())
+ if err != nil {
+ return err
+ }
+
+ slice.Index(i).Set(ptrElem.Elem())
+ }
+
+ sliceVal.Set(slice)
+ return nil
+ case Null:
+ sliceVal.Set(reflect.Zero(sliceType))
+ return nil
+ }
+
+ return fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *ArrayType) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ dst.setNil()
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []ValueTranscoder
+
+ if len(uta.Elements) > 0 {
+ elements = make([]ValueTranscoder, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ elem := dst.newElement()
+ var elemSrc []byte
+ if s != "NULL" {
+ elemSrc = []byte(s)
+ }
+ err = elem.DecodeText(ci, elemSrc)
+ if err != nil {
+ return err
+ }
+
+ elements[i] = elem
+ }
+ }
+
+ dst.elements = elements
+ dst.dimensions = uta.Dimensions
+ dst.status = Present
+
+ return nil
+}
+
+func (dst *ArrayType) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ dst.setNil()
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ var elements []ValueTranscoder
+
+ if len(arrayHeader.Dimensions) == 0 {
+ dst.elements = elements
+ dst.dimensions = arrayHeader.Dimensions
+ dst.status = Present
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements = make([]ValueTranscoder, elementCount)
+
+ for i := range elements {
+ elem := dst.newElement()
+ elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+ var elemSrc []byte
+ if elemLen >= 0 {
+ elemSrc = src[rp : rp+elemLen]
+ rp += elemLen
+ }
+ err = elem.DecodeBinary(ci, elemSrc)
+ if err != nil {
+ return err
+ }
+
+ elements[i] = elem
+ }
+
+ dst.elements = elements
+ dst.dimensions = arrayHeader.Dimensions
+ dst.status = Present
+
+ return nil
+}
+
+func (src ArrayType) 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 ArrayType) 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,
+ ElementOID: int32(src.elementOID),
+ }
+
+ for i := range src.elements {
+ if src.elements[i].Get() == nil {
+ 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 *ArrayType) 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 ArrayType) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/bit.go b/vendor/github.com/jackc/pgtype/bit.go
new file mode 100644
index 000000000..c1709e6b9
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bit.go
@@ -0,0 +1,45 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+type Bit Varbit
+
+func (dst *Bit) Set(src interface{}) error {
+ return (*Varbit)(dst).Set(src)
+}
+
+func (dst Bit) Get() interface{} {
+ return (Varbit)(dst).Get()
+}
+
+func (src *Bit) AssignTo(dst interface{}) error {
+ return (*Varbit)(src).AssignTo(dst)
+}
+
+func (dst *Bit) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Varbit)(dst).DecodeBinary(ci, src)
+}
+
+func (src Bit) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Varbit)(src).EncodeBinary(ci, buf)
+}
+
+func (dst *Bit) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Varbit)(dst).DecodeText(ci, src)
+}
+
+func (src Bit) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Varbit)(src).EncodeText(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Bit) Scan(src interface{}) error {
+ return (*Varbit)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Bit) Value() (driver.Value, error) {
+ return (Varbit)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/bool.go b/vendor/github.com/jackc/pgtype/bool.go
new file mode 100644
index 000000000..676c8e5d3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bool.go
@@ -0,0 +1,217 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+ "strconv"
+)
+
+type Bool struct {
+ Bool bool
+ Status Status
+}
+
+func (dst *Bool) Set(src interface{}) error {
+ if src == nil {
+ *dst = Bool{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case bool:
+ *dst = Bool{Bool: value, Status: Present}
+ case string:
+ bb, err := strconv.ParseBool(value)
+ if err != nil {
+ return err
+ }
+ *dst = Bool{Bool: bb, Status: Present}
+ case *bool:
+ if value == nil {
+ *dst = Bool{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Bool{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingBoolType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Bool", value)
+ }
+
+ return nil
+}
+
+func (dst Bool) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Bool
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Bool) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *bool:
+ *v = src.Bool
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Bool) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Bool{Status: Null}
+ return nil
+ }
+
+ if len(src) != 1 {
+ return fmt.Errorf("invalid length for bool: %v", len(src))
+ }
+
+ *dst = Bool{Bool: src[0] == 't', Status: Present}
+ return nil
+}
+
+func (dst *Bool) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Bool{Status: Null}
+ return nil
+ }
+
+ if len(src) != 1 {
+ return fmt.Errorf("invalid length for bool: %v", len(src))
+ }
+
+ *dst = Bool{Bool: src[0] == 1, Status: Present}
+ return nil
+}
+
+func (src Bool) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.Bool {
+ buf = append(buf, 't')
+ } else {
+ buf = append(buf, 'f')
+ }
+
+ return buf, nil
+}
+
+func (src Bool) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.Bool {
+ buf = append(buf, 1)
+ } else {
+ buf = append(buf, 0)
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Bool) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Bool{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case bool:
+ *dst = Bool{Bool: src, Status: Present}
+ return nil
+ 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 Bool) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.Bool, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Bool) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ if src.Bool {
+ return []byte("true"), nil
+ } else {
+ return []byte("false"), nil
+ }
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
+
+func (dst *Bool) UnmarshalJSON(b []byte) error {
+ var v *bool
+ err := json.Unmarshal(b, &v)
+ if err != nil {
+ return err
+ }
+
+ if v == nil {
+ *dst = Bool{Status: Null}
+ } else {
+ *dst = Bool{Bool: *v, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/bool_array.go b/vendor/github.com/jackc/pgtype/bool_array.go
new file mode 100644
index 000000000..6558d971c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bool_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type BoolArray struct {
+ Elements []Bool
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *BoolArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = BoolArray{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 []bool:
+ if value == nil {
+ *dst = BoolArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BoolArray{Status: Present}
+ } else {
+ elements := make([]Bool, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = BoolArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*bool:
+ if value == nil {
+ *dst = BoolArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BoolArray{Status: Present}
+ } else {
+ elements := make([]Bool, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = BoolArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Bool:
+ if value == nil {
+ *dst = BoolArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BoolArray{Status: Present}
+ } else {
+ *dst = BoolArray{
+ 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 = BoolArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for BoolArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = BoolArray{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 BoolArray", src)
+ }
+
+ *dst = BoolArray{
+ Elements: make([]Bool, 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([]Bool, 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 BoolArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *BoolArray) 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 BoolArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in BoolArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst BoolArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *BoolArray) 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 *[]bool:
+ *v = make([]bool, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*bool:
+ *v = make([]*bool, 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 *BoolArray) 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 BoolArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from BoolArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *BoolArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = BoolArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Bool
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Bool, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Bool
+ 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 = BoolArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *BoolArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = BoolArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = BoolArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Bool, 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 = BoolArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src BoolArray) 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 BoolArray) 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("bool"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "bool")
+ }
+
+ 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 *BoolArray) 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 BoolArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/box.go b/vendor/github.com/jackc/pgtype/box.go
new file mode 100644
index 000000000..27fb829ee
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/box.go
@@ -0,0 +1,165 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Box struct {
+ P [2]Vec2
+ Status Status
+}
+
+func (dst *Box) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Box", src)
+}
+
+func (dst Box) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Box) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Box) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Box{Status: Null}
+ return nil
+ }
+
+ if len(src) < 11 {
+ return fmt.Errorf("invalid length for Box: %v", len(src))
+ }
+
+ str := string(src[1:])
+
+ var end int
+ end = strings.IndexByte(str, ',')
+
+ x1, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1:]
+ end = strings.IndexByte(str, ')')
+
+ y1, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+3:]
+ end = strings.IndexByte(str, ',')
+
+ x2, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1 : len(str)-1]
+
+ y2, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Box{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present}
+ return nil
+}
+
+func (dst *Box) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Box{Status: Null}
+ return nil
+ }
+
+ if len(src) != 32 {
+ return fmt.Errorf("invalid length for Box: %v", len(src))
+ }
+
+ x1 := binary.BigEndian.Uint64(src)
+ y1 := binary.BigEndian.Uint64(src[8:])
+ x2 := binary.BigEndian.Uint64(src[16:])
+ y2 := binary.BigEndian.Uint64(src[24:])
+
+ *dst = Box{
+ P: [2]Vec2{
+ {math.Float64frombits(x1), math.Float64frombits(y1)},
+ {math.Float64frombits(x2), math.Float64frombits(y2)},
+ },
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Box) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`,
+ strconv.FormatFloat(src.P[0].X, '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].Y, 'f', -1, 64),
+ )...)
+ return buf, nil
+}
+
+func (src Box) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Box) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Box{Status: Null}
+ return 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 Box) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/bpchar.go b/vendor/github.com/jackc/pgtype/bpchar.go
new file mode 100644
index 000000000..e4d058e92
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bpchar.go
@@ -0,0 +1,76 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// BPChar is fixed-length, blank padded char type
+// character(n), char(n)
+type BPChar Text
+
+// Set converts from src to dst.
+func (dst *BPChar) Set(src interface{}) error {
+ return (*Text)(dst).Set(src)
+}
+
+// Get returns underlying value
+func (dst BPChar) Get() interface{} {
+ return (Text)(dst).Get()
+}
+
+// AssignTo assigns from src to dst.
+func (src *BPChar) AssignTo(dst interface{}) error {
+ if src.Status == Present {
+ switch v := dst.(type) {
+ case *rune:
+ runes := []rune(src.String)
+ if len(runes) == 1 {
+ *v = runes[0]
+ return nil
+ }
+ }
+ }
+ return (*Text)(src).AssignTo(dst)
+}
+
+func (BPChar) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *BPChar) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeText(ci, src)
+}
+
+func (dst *BPChar) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeBinary(ci, src)
+}
+
+func (BPChar) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src BPChar) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeText(ci, buf)
+}
+
+func (src BPChar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *BPChar) Scan(src interface{}) error {
+ return (*Text)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src BPChar) Value() (driver.Value, error) {
+ return (Text)(src).Value()
+}
+
+func (src BPChar) MarshalJSON() ([]byte, error) {
+ return (Text)(src).MarshalJSON()
+}
+
+func (dst *BPChar) UnmarshalJSON(b []byte) error {
+ return (*Text)(dst).UnmarshalJSON(b)
+}
diff --git a/vendor/github.com/jackc/pgtype/bpchar_array.go b/vendor/github.com/jackc/pgtype/bpchar_array.go
new file mode 100644
index 000000000..8e7922142
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bpchar_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type BPCharArray struct {
+ Elements []BPChar
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *BPCharArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = BPCharArray{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 = BPCharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BPCharArray{Status: Present}
+ } else {
+ elements := make([]BPChar, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = BPCharArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = BPCharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BPCharArray{Status: Present}
+ } else {
+ elements := make([]BPChar, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = BPCharArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []BPChar:
+ if value == nil {
+ *dst = BPCharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = BPCharArray{Status: Present}
+ } else {
+ *dst = BPCharArray{
+ 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 = BPCharArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for BPCharArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = BPCharArray{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 BPCharArray", src)
+ }
+
+ *dst = BPCharArray{
+ Elements: make([]BPChar, 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([]BPChar, 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 BPCharArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *BPCharArray) 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 BPCharArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in BPCharArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst BPCharArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *BPCharArray) 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 *[]*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
+
+ }
+ }
+
+ // 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 *BPCharArray) 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 BPCharArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from BPCharArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *BPCharArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = BPCharArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []BPChar
+
+ if len(uta.Elements) > 0 {
+ elements = make([]BPChar, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem BPChar
+ 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 = BPCharArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *BPCharArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = BPCharArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = BPCharArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]BPChar, 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 = BPCharArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src BPCharArray) 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 BPCharArray) 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("bpchar"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "bpchar")
+ }
+
+ 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 *BPCharArray) 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 BPCharArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/bytea.go b/vendor/github.com/jackc/pgtype/bytea.go
new file mode 100644
index 000000000..67eba3502
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bytea.go
@@ -0,0 +1,163 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/hex"
+ "fmt"
+)
+
+type Bytea struct {
+ Bytes []byte
+ Status Status
+}
+
+func (dst *Bytea) Set(src interface{}) error {
+ if src == nil {
+ *dst = Bytea{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case []byte:
+ if value != nil {
+ *dst = Bytea{Bytes: value, Status: Present}
+ } else {
+ *dst = Bytea{Status: Null}
+ }
+ default:
+ if originalSrc, ok := underlyingBytesType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Bytea", value)
+ }
+
+ return nil
+}
+
+func (dst Bytea) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Bytes
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Bytea) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *[]byte:
+ buf := make([]byte, len(src.Bytes))
+ copy(buf, src.Bytes)
+ *v = buf
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+// DecodeText only supports the hex format. This has been the default since
+// PostgreSQL 9.0.
+func (dst *Bytea) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Bytea{Status: Null}
+ return nil
+ }
+
+ if len(src) < 2 || src[0] != '\\' || src[1] != 'x' {
+ return fmt.Errorf("invalid hex format")
+ }
+
+ buf := make([]byte, (len(src)-2)/2)
+ _, err := hex.Decode(buf, src[2:])
+ if err != nil {
+ return err
+ }
+
+ *dst = Bytea{Bytes: buf, Status: Present}
+ return nil
+}
+
+func (dst *Bytea) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Bytea{Status: Null}
+ return nil
+ }
+
+ *dst = Bytea{Bytes: src, Status: Present}
+ return nil
+}
+
+func (src Bytea) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, `\x`...)
+ buf = append(buf, hex.EncodeToString(src.Bytes)...)
+ return buf, nil
+}
+
+func (src Bytea) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.Bytes...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Bytea) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Bytea{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case string:
+ return dst.DecodeText(nil, []byte(src))
+ case []byte:
+ buf := make([]byte, len(src))
+ copy(buf, src)
+ *dst = Bytea{Bytes: buf, Status: Present}
+ return nil
+ }
+
+ return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Bytea) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.Bytes, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/bytea_array.go b/vendor/github.com/jackc/pgtype/bytea_array.go
new file mode 100644
index 000000000..69d1ceb98
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/bytea_array.go
@@ -0,0 +1,489 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type ByteaArray struct {
+ Elements []Bytea
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *ByteaArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = ByteaArray{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 [][]byte:
+ if value == nil {
+ *dst = ByteaArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = ByteaArray{Status: Present}
+ } else {
+ elements := make([]Bytea, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = ByteaArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Bytea:
+ if value == nil {
+ *dst = ByteaArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = ByteaArray{Status: Present}
+ } else {
+ *dst = ByteaArray{
+ 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 = ByteaArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for ByteaArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = ByteaArray{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 ByteaArray", src)
+ }
+
+ *dst = ByteaArray{
+ Elements: make([]Bytea, 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([]Bytea, 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 ByteaArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *ByteaArray) 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 ByteaArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in ByteaArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst ByteaArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *ByteaArray) 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 *[][]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
+
+ }
+ }
+
+ // 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 *ByteaArray) 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 ByteaArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from ByteaArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *ByteaArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = ByteaArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Bytea
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Bytea, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Bytea
+ 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 = ByteaArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *ByteaArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = ByteaArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = ByteaArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Bytea, 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 = ByteaArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src ByteaArray) 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 ByteaArray) 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("bytea"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "bytea")
+ }
+
+ 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 *ByteaArray) 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 ByteaArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/cid.go b/vendor/github.com/jackc/pgtype/cid.go
new file mode 100644
index 000000000..b944748c7
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/cid.go
@@ -0,0 +1,61 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// CID is PostgreSQL's Command Identifier type.
+//
+// When one does
+//
+// select cmin, cmax, * from some_table;
+//
+// it is the data type of the cmin and cmax hidden system columns.
+//
+// It is currently implemented as an unsigned four byte integer.
+// Its definition can be found in src/include/c.h as CommandId
+// in the PostgreSQL sources.
+type CID pguint32
+
+// Set converts from src to dst. Note that as CID is not a general
+// number type Set does not do automatic type conversion as other number
+// types do.
+func (dst *CID) Set(src interface{}) error {
+ return (*pguint32)(dst).Set(src)
+}
+
+func (dst CID) Get() interface{} {
+ return (pguint32)(dst).Get()
+}
+
+// AssignTo assigns from src to dst. Note that as CID is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *CID) AssignTo(dst interface{}) error {
+ return (*pguint32)(src).AssignTo(dst)
+}
+
+func (dst *CID) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeText(ci, src)
+}
+
+func (dst *CID) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeBinary(ci, src)
+}
+
+func (src CID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeText(ci, buf)
+}
+
+func (src CID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *CID) Scan(src interface{}) error {
+ return (*pguint32)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src CID) Value() (driver.Value, error) {
+ return (pguint32)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/cidr.go b/vendor/github.com/jackc/pgtype/cidr.go
new file mode 100644
index 000000000..2241ca1c0
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/cidr.go
@@ -0,0 +1,31 @@
+package pgtype
+
+type CIDR Inet
+
+func (dst *CIDR) Set(src interface{}) error {
+ return (*Inet)(dst).Set(src)
+}
+
+func (dst CIDR) Get() interface{} {
+ return (Inet)(dst).Get()
+}
+
+func (src *CIDR) AssignTo(dst interface{}) error {
+ return (*Inet)(src).AssignTo(dst)
+}
+
+func (dst *CIDR) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Inet)(dst).DecodeText(ci, src)
+}
+
+func (dst *CIDR) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Inet)(dst).DecodeBinary(ci, src)
+}
+
+func (src CIDR) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Inet)(src).EncodeText(ci, buf)
+}
+
+func (src CIDR) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Inet)(src).EncodeBinary(ci, buf)
+}
diff --git a/vendor/github.com/jackc/pgtype/cidr_array.go b/vendor/github.com/jackc/pgtype/cidr_array.go
new file mode 100644
index 000000000..783c599c4
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/cidr_array.go
@@ -0,0 +1,546 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "net"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type CIDRArray struct {
+ Elements []CIDR
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *CIDRArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = CIDRArray{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 []*net.IPNet:
+ if value == nil {
+ *dst = CIDRArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = CIDRArray{Status: Present}
+ } else {
+ elements := make([]CIDR, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = CIDRArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []net.IP:
+ if value == nil {
+ *dst = CIDRArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = CIDRArray{Status: Present}
+ } else {
+ elements := make([]CIDR, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = CIDRArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*net.IP:
+ if value == nil {
+ *dst = CIDRArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = CIDRArray{Status: Present}
+ } else {
+ elements := make([]CIDR, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = CIDRArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []CIDR:
+ if value == nil {
+ *dst = CIDRArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = CIDRArray{Status: Present}
+ } else {
+ *dst = CIDRArray{
+ 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 = CIDRArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for CIDRArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = CIDRArray{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 CIDRArray", src)
+ }
+
+ *dst = CIDRArray{
+ Elements: make([]CIDR, 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([]CIDR, 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 CIDRArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *CIDRArray) 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 CIDRArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in CIDRArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst CIDRArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *CIDRArray) 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 *[]*net.IPNet:
+ *v = make([]*net.IPNet, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]net.IP:
+ *v = make([]net.IP, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*net.IP:
+ *v = make([]*net.IP, 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 *CIDRArray) 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 CIDRArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from CIDRArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *CIDRArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = CIDRArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []CIDR
+
+ if len(uta.Elements) > 0 {
+ elements = make([]CIDR, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem CIDR
+ 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 = CIDRArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *CIDRArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = CIDRArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = CIDRArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]CIDR, 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 = CIDRArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src CIDRArray) 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 CIDRArray) 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("cidr"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "cidr")
+ }
+
+ 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 *CIDRArray) 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 CIDRArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/circle.go b/vendor/github.com/jackc/pgtype/circle.go
new file mode 100644
index 000000000..4279650e3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/circle.go
@@ -0,0 +1,150 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Circle struct {
+ P Vec2
+ R float64
+ Status Status
+}
+
+func (dst *Circle) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Circle", src)
+}
+
+func (dst Circle) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Circle) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Circle) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Circle{Status: Null}
+ return nil
+ }
+
+ if len(src) < 9 {
+ return fmt.Errorf("invalid length for Circle: %v", len(src))
+ }
+
+ str := string(src[2:])
+ end := strings.IndexByte(str, ',')
+ x, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1:]
+ end = strings.IndexByte(str, ')')
+
+ y, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+2 : len(str)-1]
+
+ r, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Circle{P: Vec2{x, y}, R: r, Status: Present}
+ return nil
+}
+
+func (dst *Circle) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Circle{Status: Null}
+ return nil
+ }
+
+ if len(src) != 24 {
+ return fmt.Errorf("invalid length for Circle: %v", len(src))
+ }
+
+ x := binary.BigEndian.Uint64(src)
+ y := binary.BigEndian.Uint64(src[8:])
+ r := binary.BigEndian.Uint64(src[16:])
+
+ *dst = Circle{
+ P: Vec2{math.Float64frombits(x), math.Float64frombits(y)},
+ R: math.Float64frombits(r),
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Circle) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, fmt.Sprintf(`<(%s,%s),%s>`,
+ strconv.FormatFloat(src.P.X, 'f', -1, 64),
+ strconv.FormatFloat(src.P.Y, 'f', -1, 64),
+ strconv.FormatFloat(src.R, 'f', -1, 64),
+ )...)
+
+ return buf, nil
+}
+
+func (src Circle) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P.X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P.Y))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.R))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Circle) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Circle{Status: Null}
+ return 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 Circle) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/composite_fields.go b/vendor/github.com/jackc/pgtype/composite_fields.go
new file mode 100644
index 000000000..b6d09fcf2
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/composite_fields.go
@@ -0,0 +1,107 @@
+package pgtype
+
+import "fmt"
+
+// CompositeFields scans the fields of a composite type into the elements of the CompositeFields value. To scan a
+// nullable value use a *CompositeFields. It will be set to nil in case of null.
+//
+// CompositeFields implements EncodeBinary and EncodeText. However, functionality is limited due to CompositeFields not
+// knowing the PostgreSQL schema of the composite type. Prefer using a registered CompositeType.
+type CompositeFields []interface{}
+
+func (cf CompositeFields) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if len(cf) == 0 {
+ return fmt.Errorf("cannot decode into empty CompositeFields")
+ }
+
+ if src == nil {
+ return fmt.Errorf("cannot decode unexpected null into CompositeFields")
+ }
+
+ scanner := NewCompositeBinaryScanner(ci, src)
+
+ for _, f := range cf {
+ scanner.ScanValue(f)
+ }
+
+ if scanner.Err() != nil {
+ return scanner.Err()
+ }
+
+ return nil
+}
+
+func (cf CompositeFields) DecodeText(ci *ConnInfo, src []byte) error {
+ if len(cf) == 0 {
+ return fmt.Errorf("cannot decode into empty CompositeFields")
+ }
+
+ if src == nil {
+ return fmt.Errorf("cannot decode unexpected null into CompositeFields")
+ }
+
+ scanner := NewCompositeTextScanner(ci, src)
+
+ for _, f := range cf {
+ scanner.ScanValue(f)
+ }
+
+ if scanner.Err() != nil {
+ return scanner.Err()
+ }
+
+ return nil
+}
+
+// EncodeText encodes composite fields into the text format. Prefer registering a CompositeType to using
+// CompositeFields to encode directly.
+func (cf CompositeFields) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ b := NewCompositeTextBuilder(ci, buf)
+
+ for _, f := range cf {
+ if textEncoder, ok := f.(TextEncoder); ok {
+ b.AppendEncoder(textEncoder)
+ } else {
+ b.AppendValue(f)
+ }
+ }
+
+ return b.Finish()
+}
+
+// EncodeBinary encodes composite fields into the binary format. Unlike CompositeType the schema of the destination is
+// unknown. Prefer registering a CompositeType to using CompositeFields to encode directly. Because the binary
+// composite format requires the OID of each field to be specified the only types that will work are those known to
+// ConnInfo.
+//
+// In particular:
+//
+// * Nil cannot be used because there is no way to determine what type it.
+// * Integer types must be exact matches. e.g. A Go int32 into a PostgreSQL bigint will fail.
+// * No dereferencing will be done. e.g. *Text must be used instead of Text.
+func (cf CompositeFields) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ b := NewCompositeBinaryBuilder(ci, buf)
+
+ for _, f := range cf {
+ dt, ok := ci.DataTypeForValue(f)
+ if !ok {
+ return nil, fmt.Errorf("Unknown OID for %#v", f)
+ }
+
+ if binaryEncoder, ok := f.(BinaryEncoder); ok {
+ b.AppendEncoder(dt.OID, binaryEncoder)
+ } else {
+ err := dt.Value.Set(f)
+ if err != nil {
+ return nil, err
+ }
+ if binaryEncoder, ok := dt.Value.(BinaryEncoder); ok {
+ b.AppendEncoder(dt.OID, binaryEncoder)
+ } else {
+ return nil, fmt.Errorf("Cannot encode binary format for %v", f)
+ }
+ }
+ }
+
+ return b.Finish()
+}
diff --git a/vendor/github.com/jackc/pgtype/composite_type.go b/vendor/github.com/jackc/pgtype/composite_type.go
new file mode 100644
index 000000000..32e0aa26b
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/composite_type.go
@@ -0,0 +1,682 @@
+package pgtype
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "reflect"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type CompositeTypeField struct {
+ Name string
+ OID uint32
+}
+
+type CompositeType struct {
+ status Status
+
+ typeName string
+
+ fields []CompositeTypeField
+ valueTranscoders []ValueTranscoder
+}
+
+// NewCompositeType creates a CompositeType from fields and ci. ci is used to find the ValueTranscoders used
+// for fields. All field OIDs must be previously registered in ci.
+func NewCompositeType(typeName string, fields []CompositeTypeField, ci *ConnInfo) (*CompositeType, error) {
+ valueTranscoders := make([]ValueTranscoder, len(fields))
+
+ for i := range fields {
+ dt, ok := ci.DataTypeForOID(fields[i].OID)
+ if !ok {
+ return nil, fmt.Errorf("no data type registered for oid: %d", fields[i].OID)
+ }
+
+ value := NewValue(dt.Value)
+ valueTranscoder, ok := value.(ValueTranscoder)
+ if !ok {
+ return nil, fmt.Errorf("data type for oid does not implement ValueTranscoder: %d", fields[i].OID)
+ }
+
+ valueTranscoders[i] = valueTranscoder
+ }
+
+ return &CompositeType{typeName: typeName, fields: fields, valueTranscoders: valueTranscoders}, nil
+}
+
+// NewCompositeTypeValues creates a CompositeType from fields and values. fields and values must have the same length.
+// Prefer NewCompositeType unless overriding the transcoding of fields is required.
+func NewCompositeTypeValues(typeName string, fields []CompositeTypeField, values []ValueTranscoder) (*CompositeType, error) {
+ if len(fields) != len(values) {
+ return nil, errors.New("fields and valueTranscoders must have same length")
+ }
+
+ return &CompositeType{typeName: typeName, fields: fields, valueTranscoders: values}, nil
+}
+
+func (src CompositeType) Get() interface{} {
+ switch src.status {
+ case Present:
+ results := make(map[string]interface{}, len(src.valueTranscoders))
+ for i := range src.valueTranscoders {
+ results[src.fields[i].Name] = src.valueTranscoders[i].Get()
+ }
+ return results
+ case Null:
+ return nil
+ default:
+ return src.status
+ }
+}
+
+func (ct *CompositeType) NewTypeValue() Value {
+ a := &CompositeType{
+ typeName: ct.typeName,
+ fields: ct.fields,
+ valueTranscoders: make([]ValueTranscoder, len(ct.valueTranscoders)),
+ }
+
+ for i := range ct.valueTranscoders {
+ a.valueTranscoders[i] = NewValue(ct.valueTranscoders[i]).(ValueTranscoder)
+ }
+
+ return a
+}
+
+func (ct *CompositeType) TypeName() string {
+ return ct.typeName
+}
+
+func (ct *CompositeType) Fields() []CompositeTypeField {
+ return ct.fields
+}
+
+func (dst *CompositeType) Set(src interface{}) error {
+ if src == nil {
+ dst.status = Null
+ return nil
+ }
+
+ switch value := src.(type) {
+ case []interface{}:
+ if len(value) != len(dst.valueTranscoders) {
+ return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(dst.valueTranscoders))
+ }
+ for i, v := range value {
+ if err := dst.valueTranscoders[i].Set(v); err != nil {
+ return err
+ }
+ }
+ dst.status = Present
+ case *[]interface{}:
+ if value == nil {
+ dst.status = Null
+ return nil
+ }
+ return dst.Set(*value)
+ default:
+ return fmt.Errorf("Can not convert %v to Composite", src)
+ }
+
+ return nil
+}
+
+// AssignTo should never be called on composite value directly
+func (src CompositeType) AssignTo(dst interface{}) error {
+ switch src.status {
+ case Present:
+ switch v := dst.(type) {
+ case []interface{}:
+ if len(v) != len(src.valueTranscoders) {
+ return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(src.valueTranscoders))
+ }
+ for i := range src.valueTranscoders {
+ if v[i] == nil {
+ continue
+ }
+
+ err := assignToOrSet(src.valueTranscoders[i], v[i])
+ if err != nil {
+ return fmt.Errorf("unable to assign to dst[%d]: %v", i, err)
+ }
+ }
+ return nil
+ case *[]interface{}:
+ return src.AssignTo(*v)
+ default:
+ if isPtrStruct, err := src.assignToPtrStruct(dst); isPtrStruct {
+ return err
+ }
+
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func assignToOrSet(src Value, dst interface{}) error {
+ assignToErr := src.AssignTo(dst)
+ if assignToErr != nil {
+ // Try to use get / set instead -- this avoids every type having to be able to AssignTo type of self.
+ setSucceeded := false
+ if setter, ok := dst.(Value); ok {
+ err := setter.Set(src.Get())
+ setSucceeded = err == nil
+ }
+ if !setSucceeded {
+ return assignToErr
+ }
+ }
+
+ return nil
+}
+
+func (src CompositeType) assignToPtrStruct(dst interface{}) (bool, error) {
+ dstValue := reflect.ValueOf(dst)
+ if dstValue.Kind() != reflect.Ptr {
+ return false, nil
+ }
+
+ if dstValue.IsNil() {
+ return false, nil
+ }
+
+ dstElemValue := dstValue.Elem()
+ dstElemType := dstElemValue.Type()
+
+ if dstElemType.Kind() != reflect.Struct {
+ return false, nil
+ }
+
+ exportedFields := make([]int, 0, dstElemType.NumField())
+ for i := 0; i < dstElemType.NumField(); i++ {
+ sf := dstElemType.Field(i)
+ if sf.PkgPath == "" {
+ exportedFields = append(exportedFields, i)
+ }
+ }
+
+ if len(exportedFields) != len(src.valueTranscoders) {
+ return false, nil
+ }
+
+ for i := range exportedFields {
+ err := assignToOrSet(src.valueTranscoders[i], dstElemValue.Field(exportedFields[i]).Addr().Interface())
+ if err != nil {
+ return true, fmt.Errorf("unable to assign to field %s: %v", dstElemType.Field(exportedFields[i]).Name, err)
+ }
+ }
+
+ return true, nil
+}
+
+func (src CompositeType) EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error) {
+ switch src.status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ b := NewCompositeBinaryBuilder(ci, buf)
+ for i := range src.valueTranscoders {
+ b.AppendEncoder(src.fields[i].OID, src.valueTranscoders[i])
+ }
+
+ return b.Finish()
+}
+
+// DecodeBinary implements BinaryDecoder interface.
+// Opposite to Record, fields in a composite act as a "schema"
+// and decoding fails if SQL value can't be assigned due to
+// type mismatch
+func (dst *CompositeType) DecodeBinary(ci *ConnInfo, buf []byte) error {
+ if buf == nil {
+ dst.status = Null
+ return nil
+ }
+
+ scanner := NewCompositeBinaryScanner(ci, buf)
+
+ for _, f := range dst.valueTranscoders {
+ scanner.ScanDecoder(f)
+ }
+
+ if scanner.Err() != nil {
+ return scanner.Err()
+ }
+
+ dst.status = Present
+
+ return nil
+}
+
+func (dst *CompositeType) DecodeText(ci *ConnInfo, buf []byte) error {
+ if buf == nil {
+ dst.status = Null
+ return nil
+ }
+
+ scanner := NewCompositeTextScanner(ci, buf)
+
+ for _, f := range dst.valueTranscoders {
+ scanner.ScanDecoder(f)
+ }
+
+ if scanner.Err() != nil {
+ return scanner.Err()
+ }
+
+ dst.status = Present
+
+ return nil
+}
+
+func (src CompositeType) EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error) {
+ switch src.status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ b := NewCompositeTextBuilder(ci, buf)
+ for _, f := range src.valueTranscoders {
+ b.AppendEncoder(f)
+ }
+
+ return b.Finish()
+}
+
+type CompositeBinaryScanner struct {
+ ci *ConnInfo
+ rp int
+ src []byte
+
+ fieldCount int32
+ fieldBytes []byte
+ fieldOID uint32
+ err error
+}
+
+// NewCompositeBinaryScanner a scanner over a binary encoded composite balue.
+func NewCompositeBinaryScanner(ci *ConnInfo, src []byte) *CompositeBinaryScanner {
+ rp := 0
+ if len(src[rp:]) < 4 {
+ return &CompositeBinaryScanner{err: fmt.Errorf("Record incomplete %v", src)}
+ }
+
+ fieldCount := int32(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ return &CompositeBinaryScanner{
+ ci: ci,
+ rp: rp,
+ src: src,
+ fieldCount: fieldCount,
+ }
+}
+
+// ScanDecoder calls Next and decodes the result with d.
+func (cfs *CompositeBinaryScanner) ScanDecoder(d BinaryDecoder) {
+ if cfs.err != nil {
+ return
+ }
+
+ if cfs.Next() {
+ cfs.err = d.DecodeBinary(cfs.ci, cfs.fieldBytes)
+ } else {
+ cfs.err = errors.New("read past end of composite")
+ }
+}
+
+// ScanDecoder calls Next and scans the result into d.
+func (cfs *CompositeBinaryScanner) ScanValue(d interface{}) {
+ if cfs.err != nil {
+ return
+ }
+
+ if cfs.Next() {
+ cfs.err = cfs.ci.Scan(cfs.OID(), BinaryFormatCode, cfs.Bytes(), d)
+ } else {
+ cfs.err = errors.New("read past end of composite")
+ }
+}
+
+// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
+// Next returns false, the Err method can be called to check if any errors occurred.
+func (cfs *CompositeBinaryScanner) Next() bool {
+ if cfs.err != nil {
+ return false
+ }
+
+ if cfs.rp == len(cfs.src) {
+ return false
+ }
+
+ if len(cfs.src[cfs.rp:]) < 8 {
+ cfs.err = fmt.Errorf("Record incomplete %v", cfs.src)
+ return false
+ }
+ cfs.fieldOID = binary.BigEndian.Uint32(cfs.src[cfs.rp:])
+ cfs.rp += 4
+
+ fieldLen := int(int32(binary.BigEndian.Uint32(cfs.src[cfs.rp:])))
+ cfs.rp += 4
+
+ if fieldLen >= 0 {
+ if len(cfs.src[cfs.rp:]) < fieldLen {
+ cfs.err = fmt.Errorf("Record incomplete rp=%d src=%v", cfs.rp, cfs.src)
+ return false
+ }
+ cfs.fieldBytes = cfs.src[cfs.rp : cfs.rp+fieldLen]
+ cfs.rp += fieldLen
+ } else {
+ cfs.fieldBytes = nil
+ }
+
+ return true
+}
+
+func (cfs *CompositeBinaryScanner) FieldCount() int {
+ return int(cfs.fieldCount)
+}
+
+// Bytes returns the bytes of the field most recently read by Scan().
+func (cfs *CompositeBinaryScanner) Bytes() []byte {
+ return cfs.fieldBytes
+}
+
+// OID returns the OID of the field most recently read by Scan().
+func (cfs *CompositeBinaryScanner) OID() uint32 {
+ return cfs.fieldOID
+}
+
+// Err returns any error encountered by the scanner.
+func (cfs *CompositeBinaryScanner) Err() error {
+ return cfs.err
+}
+
+type CompositeTextScanner struct {
+ ci *ConnInfo
+ rp int
+ src []byte
+
+ fieldBytes []byte
+ err error
+}
+
+// NewCompositeTextScanner a scanner over a text encoded composite value.
+func NewCompositeTextScanner(ci *ConnInfo, src []byte) *CompositeTextScanner {
+ if len(src) < 2 {
+ return &CompositeTextScanner{err: fmt.Errorf("Record incomplete %v", src)}
+ }
+
+ if src[0] != '(' {
+ return &CompositeTextScanner{err: fmt.Errorf("composite text format must start with '('")}
+ }
+
+ if src[len(src)-1] != ')' {
+ return &CompositeTextScanner{err: fmt.Errorf("composite text format must end with ')'")}
+ }
+
+ return &CompositeTextScanner{
+ ci: ci,
+ rp: 1,
+ src: src,
+ }
+}
+
+// ScanDecoder calls Next and decodes the result with d.
+func (cfs *CompositeTextScanner) ScanDecoder(d TextDecoder) {
+ if cfs.err != nil {
+ return
+ }
+
+ if cfs.Next() {
+ cfs.err = d.DecodeText(cfs.ci, cfs.fieldBytes)
+ } else {
+ cfs.err = errors.New("read past end of composite")
+ }
+}
+
+// ScanDecoder calls Next and scans the result into d.
+func (cfs *CompositeTextScanner) ScanValue(d interface{}) {
+ if cfs.err != nil {
+ return
+ }
+
+ if cfs.Next() {
+ cfs.err = cfs.ci.Scan(0, TextFormatCode, cfs.Bytes(), d)
+ } else {
+ cfs.err = errors.New("read past end of composite")
+ }
+}
+
+// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
+// Next returns false, the Err method can be called to check if any errors occurred.
+func (cfs *CompositeTextScanner) Next() bool {
+ if cfs.err != nil {
+ return false
+ }
+
+ if cfs.rp == len(cfs.src) {
+ return false
+ }
+
+ switch cfs.src[cfs.rp] {
+ case ',', ')': // null
+ cfs.rp++
+ cfs.fieldBytes = nil
+ return true
+ case '"': // quoted value
+ cfs.rp++
+ cfs.fieldBytes = make([]byte, 0, 16)
+ for {
+ ch := cfs.src[cfs.rp]
+
+ if ch == '"' {
+ cfs.rp++
+ if cfs.src[cfs.rp] == '"' {
+ cfs.fieldBytes = append(cfs.fieldBytes, '"')
+ cfs.rp++
+ } else {
+ break
+ }
+ } else if ch == '\\' {
+ cfs.rp++
+ cfs.fieldBytes = append(cfs.fieldBytes, cfs.src[cfs.rp])
+ cfs.rp++
+ } else {
+ cfs.fieldBytes = append(cfs.fieldBytes, ch)
+ cfs.rp++
+ }
+ }
+ cfs.rp++
+ return true
+ default: // unquoted value
+ start := cfs.rp
+ for {
+ ch := cfs.src[cfs.rp]
+ if ch == ',' || ch == ')' {
+ break
+ }
+ cfs.rp++
+ }
+ cfs.fieldBytes = cfs.src[start:cfs.rp]
+ cfs.rp++
+ return true
+ }
+}
+
+// Bytes returns the bytes of the field most recently read by Scan().
+func (cfs *CompositeTextScanner) Bytes() []byte {
+ return cfs.fieldBytes
+}
+
+// Err returns any error encountered by the scanner.
+func (cfs *CompositeTextScanner) Err() error {
+ return cfs.err
+}
+
+type CompositeBinaryBuilder struct {
+ ci *ConnInfo
+ buf []byte
+ startIdx int
+ fieldCount uint32
+ err error
+}
+
+func NewCompositeBinaryBuilder(ci *ConnInfo, buf []byte) *CompositeBinaryBuilder {
+ startIdx := len(buf)
+ buf = append(buf, 0, 0, 0, 0) // allocate room for number of fields
+ return &CompositeBinaryBuilder{ci: ci, buf: buf, startIdx: startIdx}
+}
+
+func (b *CompositeBinaryBuilder) AppendValue(oid uint32, field interface{}) {
+ if b.err != nil {
+ return
+ }
+
+ dt, ok := b.ci.DataTypeForOID(oid)
+ if !ok {
+ b.err = fmt.Errorf("unknown data type for OID: %d", oid)
+ return
+ }
+
+ err := dt.Value.Set(field)
+ if err != nil {
+ b.err = err
+ return
+ }
+
+ binaryEncoder, ok := dt.Value.(BinaryEncoder)
+ if !ok {
+ b.err = fmt.Errorf("unable to encode binary for OID: %d", oid)
+ return
+ }
+
+ b.AppendEncoder(oid, binaryEncoder)
+}
+
+func (b *CompositeBinaryBuilder) AppendEncoder(oid uint32, field BinaryEncoder) {
+ if b.err != nil {
+ return
+ }
+
+ b.buf = pgio.AppendUint32(b.buf, oid)
+ lengthPos := len(b.buf)
+ b.buf = pgio.AppendInt32(b.buf, -1)
+ fieldBuf, err := field.EncodeBinary(b.ci, b.buf)
+ if err != nil {
+ b.err = err
+ return
+ }
+ if fieldBuf != nil {
+ binary.BigEndian.PutUint32(fieldBuf[lengthPos:], uint32(len(fieldBuf)-len(b.buf)))
+ b.buf = fieldBuf
+ }
+
+ b.fieldCount++
+}
+
+func (b *CompositeBinaryBuilder) Finish() ([]byte, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ binary.BigEndian.PutUint32(b.buf[b.startIdx:], b.fieldCount)
+ return b.buf, nil
+}
+
+type CompositeTextBuilder struct {
+ ci *ConnInfo
+ buf []byte
+ startIdx int
+ fieldCount uint32
+ err error
+ fieldBuf [32]byte
+}
+
+func NewCompositeTextBuilder(ci *ConnInfo, buf []byte) *CompositeTextBuilder {
+ buf = append(buf, '(') // allocate room for number of fields
+ return &CompositeTextBuilder{ci: ci, buf: buf}
+}
+
+func (b *CompositeTextBuilder) AppendValue(field interface{}) {
+ if b.err != nil {
+ return
+ }
+
+ if field == nil {
+ b.buf = append(b.buf, ',')
+ return
+ }
+
+ dt, ok := b.ci.DataTypeForValue(field)
+ if !ok {
+ b.err = fmt.Errorf("unknown data type for field: %v", field)
+ return
+ }
+
+ err := dt.Value.Set(field)
+ if err != nil {
+ b.err = err
+ return
+ }
+
+ textEncoder, ok := dt.Value.(TextEncoder)
+ if !ok {
+ b.err = fmt.Errorf("unable to encode text for value: %v", field)
+ return
+ }
+
+ b.AppendEncoder(textEncoder)
+}
+
+func (b *CompositeTextBuilder) AppendEncoder(field TextEncoder) {
+ if b.err != nil {
+ return
+ }
+
+ fieldBuf, err := field.EncodeText(b.ci, b.fieldBuf[0:0])
+ if err != nil {
+ b.err = err
+ return
+ }
+ if fieldBuf != nil {
+ b.buf = append(b.buf, quoteCompositeFieldIfNeeded(string(fieldBuf))...)
+ }
+
+ b.buf = append(b.buf, ',')
+}
+
+func (b *CompositeTextBuilder) Finish() ([]byte, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ b.buf[len(b.buf)-1] = ')'
+ return b.buf, nil
+}
+
+var quoteCompositeReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
+
+func quoteCompositeField(src string) string {
+ return `"` + quoteCompositeReplacer.Replace(src) + `"`
+}
+
+func quoteCompositeFieldIfNeeded(src string) string {
+ if src == "" || src[0] == ' ' || src[len(src)-1] == ' ' || strings.ContainsAny(src, `(),"\`) {
+ return quoteCompositeField(src)
+ }
+ return src
+}
diff --git a/vendor/github.com/jackc/pgtype/convert.go b/vendor/github.com/jackc/pgtype/convert.go
new file mode 100644
index 000000000..de9ba9ba3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/convert.go
@@ -0,0 +1,472 @@
+package pgtype
+
+import (
+ "database/sql"
+ "fmt"
+ "math"
+ "reflect"
+ "time"
+)
+
+const (
+ maxUint = ^uint(0)
+ maxInt = int(maxUint >> 1)
+ minInt = -maxInt - 1
+)
+
+// underlyingNumberType gets the underlying type that can be converted to Int2, Int4, Int8, Float4, or Float8
+func underlyingNumberType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ case reflect.Int:
+ convVal := int(refVal.Int())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Int8:
+ convVal := int8(refVal.Int())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Int16:
+ convVal := int16(refVal.Int())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Int32:
+ convVal := int32(refVal.Int())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Int64:
+ convVal := int64(refVal.Int())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Uint:
+ convVal := uint(refVal.Uint())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Uint8:
+ convVal := uint8(refVal.Uint())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Uint16:
+ convVal := uint16(refVal.Uint())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Uint32:
+ convVal := uint32(refVal.Uint())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Uint64:
+ convVal := uint64(refVal.Uint())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Float32:
+ convVal := float32(refVal.Float())
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.Float64:
+ convVal := refVal.Float()
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ case reflect.String:
+ convVal := refVal.String()
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ }
+
+ return nil, false
+}
+
+// underlyingBoolType gets the underlying type that can be converted to Bool
+func underlyingBoolType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ case reflect.Bool:
+ convVal := refVal.Bool()
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ }
+
+ return nil, false
+}
+
+// underlyingBytesType gets the underlying type that can be converted to []byte
+func underlyingBytesType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ case reflect.Slice:
+ if refVal.Type().Elem().Kind() == reflect.Uint8 {
+ convVal := refVal.Bytes()
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ }
+ }
+
+ return nil, false
+}
+
+// underlyingStringType gets the underlying type that can be converted to String
+func underlyingStringType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ case reflect.String:
+ convVal := refVal.String()
+ return convVal, reflect.TypeOf(convVal) != refVal.Type()
+ }
+
+ return nil, false
+}
+
+// underlyingPtrType dereferences a pointer
+func underlyingPtrType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ }
+
+ return nil, false
+}
+
+// underlyingTimeType gets the underlying type that can be converted to time.Time
+func underlyingTimeType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ }
+
+ timeType := reflect.TypeOf(time.Time{})
+ if refVal.Type().ConvertibleTo(timeType) {
+ return refVal.Convert(timeType).Interface(), true
+ }
+
+ return nil, false
+}
+
+// underlyingUUIDType gets the underlying type that can be converted to [16]byte
+func underlyingUUIDType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return time.Time{}, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ }
+
+ uuidType := reflect.TypeOf([16]byte{})
+ if refVal.Type().ConvertibleTo(uuidType) {
+ return refVal.Convert(uuidType).Interface(), true
+ }
+
+ return nil, false
+}
+
+// underlyingSliceType gets the underlying slice type
+func underlyingSliceType(val interface{}) (interface{}, bool) {
+ refVal := reflect.ValueOf(val)
+
+ switch refVal.Kind() {
+ case reflect.Ptr:
+ if refVal.IsNil() {
+ return nil, false
+ }
+ convVal := refVal.Elem().Interface()
+ return convVal, true
+ case reflect.Slice:
+ baseSliceType := reflect.SliceOf(refVal.Type().Elem())
+ if refVal.Type().ConvertibleTo(baseSliceType) {
+ convVal := refVal.Convert(baseSliceType)
+ return convVal.Interface(), reflect.TypeOf(convVal.Interface()) != refVal.Type()
+ }
+ }
+
+ return nil, false
+}
+
+func int64AssignTo(srcVal int64, srcStatus Status, dst interface{}) error {
+ if srcStatus == Present {
+ switch v := dst.(type) {
+ case *int:
+ if srcVal < int64(minInt) {
+ return fmt.Errorf("%d is less than minimum value for int", srcVal)
+ } else if srcVal > int64(maxInt) {
+ return fmt.Errorf("%d is greater than maximum value for int", srcVal)
+ }
+ *v = int(srcVal)
+ case *int8:
+ if srcVal < math.MinInt8 {
+ return fmt.Errorf("%d is less than minimum value for int8", srcVal)
+ } else if srcVal > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for int8", srcVal)
+ }
+ *v = int8(srcVal)
+ case *int16:
+ if srcVal < math.MinInt16 {
+ return fmt.Errorf("%d is less than minimum value for int16", srcVal)
+ } else if srcVal > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for int16", srcVal)
+ }
+ *v = int16(srcVal)
+ case *int32:
+ if srcVal < math.MinInt32 {
+ return fmt.Errorf("%d is less than minimum value for int32", srcVal)
+ } else if srcVal > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for int32", srcVal)
+ }
+ *v = int32(srcVal)
+ case *int64:
+ if srcVal < math.MinInt64 {
+ return fmt.Errorf("%d is less than minimum value for int64", srcVal)
+ } else if srcVal > math.MaxInt64 {
+ return fmt.Errorf("%d is greater than maximum value for int64", srcVal)
+ }
+ *v = int64(srcVal)
+ case *uint:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for uint", srcVal)
+ } else if uint64(srcVal) > uint64(maxUint) {
+ return fmt.Errorf("%d is greater than maximum value for uint", srcVal)
+ }
+ *v = uint(srcVal)
+ case *uint8:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for uint8", srcVal)
+ } else if srcVal > math.MaxUint8 {
+ return fmt.Errorf("%d is greater than maximum value for uint8", srcVal)
+ }
+ *v = uint8(srcVal)
+ case *uint16:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for uint32", srcVal)
+ } else if srcVal > math.MaxUint16 {
+ return fmt.Errorf("%d is greater than maximum value for uint16", srcVal)
+ }
+ *v = uint16(srcVal)
+ case *uint32:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for uint32", srcVal)
+ } else if srcVal > math.MaxUint32 {
+ return fmt.Errorf("%d is greater than maximum value for uint32", srcVal)
+ }
+ *v = uint32(srcVal)
+ case *uint64:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for uint64", srcVal)
+ }
+ *v = uint64(srcVal)
+ case sql.Scanner:
+ return v.Scan(srcVal)
+ default:
+ if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
+ el := v.Elem()
+ switch el.Kind() {
+ // if dst is a pointer to pointer, strip the pointer and try again
+ case reflect.Ptr:
+ if el.IsNil() {
+ // allocate destination
+ el.Set(reflect.New(el.Type().Elem()))
+ }
+ return int64AssignTo(srcVal, srcStatus, el.Interface())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ if el.OverflowInt(int64(srcVal)) {
+ return fmt.Errorf("cannot put %d into %T", srcVal, dst)
+ }
+ el.SetInt(int64(srcVal))
+ return nil
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ if srcVal < 0 {
+ return fmt.Errorf("%d is less than zero for %T", srcVal, dst)
+ }
+ if el.OverflowUint(uint64(srcVal)) {
+ return fmt.Errorf("cannot put %d into %T", srcVal, dst)
+ }
+ el.SetUint(uint64(srcVal))
+ return nil
+ }
+ }
+ return fmt.Errorf("cannot assign %v into %T", srcVal, dst)
+ }
+ return nil
+ }
+
+ // if dst is a pointer to pointer and srcStatus is not Present, nil it out
+ if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
+ el := v.Elem()
+ if el.Kind() == reflect.Ptr {
+ el.Set(reflect.Zero(el.Type()))
+ return nil
+ }
+ }
+
+ return fmt.Errorf("cannot assign %v %v into %T", srcVal, srcStatus, dst)
+}
+
+func float64AssignTo(srcVal float64, srcStatus Status, dst interface{}) error {
+ if srcStatus == Present {
+ switch v := dst.(type) {
+ case *float32:
+ *v = float32(srcVal)
+ case *float64:
+ *v = srcVal
+ default:
+ if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
+ el := v.Elem()
+ switch el.Kind() {
+ // if dst is a pointer to pointer, strip the pointer and try again
+ case reflect.Ptr:
+ if el.IsNil() {
+ // allocate destination
+ el.Set(reflect.New(el.Type().Elem()))
+ }
+ return float64AssignTo(srcVal, srcStatus, el.Interface())
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ i64 := int64(srcVal)
+ if float64(i64) == srcVal {
+ return int64AssignTo(i64, srcStatus, dst)
+ }
+ }
+ }
+ return fmt.Errorf("cannot assign %v into %T", srcVal, dst)
+ }
+ return nil
+ }
+
+ // if dst is a pointer to pointer and srcStatus is not Present, nil it out
+ if v := reflect.ValueOf(dst); v.Kind() == reflect.Ptr {
+ el := v.Elem()
+ if el.Kind() == reflect.Ptr {
+ el.Set(reflect.Zero(el.Type()))
+ return nil
+ }
+ }
+
+ return fmt.Errorf("cannot assign %v %v into %T", srcVal, srcStatus, dst)
+}
+
+func NullAssignTo(dst interface{}) error {
+ dstPtr := reflect.ValueOf(dst)
+
+ // AssignTo dst must always be a pointer
+ if dstPtr.Kind() != reflect.Ptr {
+ return &nullAssignmentError{dst: dst}
+ }
+
+ dstVal := dstPtr.Elem()
+
+ switch dstVal.Kind() {
+ case reflect.Ptr, reflect.Slice, reflect.Map:
+ dstVal.Set(reflect.Zero(dstVal.Type()))
+ return nil
+ }
+
+ return &nullAssignmentError{dst: dst}
+}
+
+var kindTypes map[reflect.Kind]reflect.Type
+
+func toInterface(dst reflect.Value, t reflect.Type) (interface{}, bool) {
+ nextDst := dst.Convert(t)
+ return nextDst.Interface(), dst.Type() != nextDst.Type()
+}
+
+// GetAssignToDstType attempts to convert dst to something AssignTo can assign
+// to. If dst is a pointer to pointer it allocates a value and returns the
+// dereferences pointer. If dst is a named type such as *Foo where Foo is type
+// Foo int16, it converts dst to *int16.
+//
+// GetAssignToDstType returns the converted dst and a bool representing if any
+// change was made.
+func GetAssignToDstType(dst interface{}) (interface{}, bool) {
+ dstPtr := reflect.ValueOf(dst)
+
+ // AssignTo dst must always be a pointer
+ if dstPtr.Kind() != reflect.Ptr {
+ return nil, false
+ }
+
+ dstVal := dstPtr.Elem()
+
+ // if dst is a pointer to pointer, allocate space try again with the dereferenced pointer
+ if dstVal.Kind() == reflect.Ptr {
+ dstVal.Set(reflect.New(dstVal.Type().Elem()))
+ return dstVal.Interface(), true
+ }
+
+ // if dst is pointer to a base type that has been renamed
+ if baseValType, ok := kindTypes[dstVal.Kind()]; ok {
+ return toInterface(dstPtr, reflect.PtrTo(baseValType))
+ }
+
+ if dstVal.Kind() == reflect.Slice {
+ if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok {
+ return toInterface(dstPtr, reflect.PtrTo(reflect.SliceOf(baseElemType)))
+ }
+ }
+
+ if dstVal.Kind() == reflect.Array {
+ if baseElemType, ok := kindTypes[dstVal.Type().Elem().Kind()]; ok {
+ return toInterface(dstPtr, reflect.PtrTo(reflect.ArrayOf(dstVal.Len(), baseElemType)))
+ }
+ }
+
+ if dstVal.Kind() == reflect.Struct {
+ if dstVal.Type().NumField() == 1 && dstVal.Type().Field(0).Anonymous {
+ dstPtr = dstVal.Field(0).Addr()
+ nested := dstVal.Type().Field(0).Type
+ if nested.Kind() == reflect.Array {
+ if baseElemType, ok := kindTypes[nested.Elem().Kind()]; ok {
+ return toInterface(dstPtr, reflect.PtrTo(reflect.ArrayOf(nested.Len(), baseElemType)))
+ }
+ }
+ if _, ok := kindTypes[nested.Kind()]; ok && dstPtr.CanInterface() {
+ return dstPtr.Interface(), true
+ }
+ }
+ }
+
+ return nil, false
+}
+
+func init() {
+ kindTypes = map[reflect.Kind]reflect.Type{
+ reflect.Bool: reflect.TypeOf(false),
+ reflect.Float32: reflect.TypeOf(float32(0)),
+ reflect.Float64: reflect.TypeOf(float64(0)),
+ reflect.Int: reflect.TypeOf(int(0)),
+ reflect.Int8: reflect.TypeOf(int8(0)),
+ reflect.Int16: reflect.TypeOf(int16(0)),
+ reflect.Int32: reflect.TypeOf(int32(0)),
+ reflect.Int64: reflect.TypeOf(int64(0)),
+ reflect.Uint: reflect.TypeOf(uint(0)),
+ reflect.Uint8: reflect.TypeOf(uint8(0)),
+ reflect.Uint16: reflect.TypeOf(uint16(0)),
+ reflect.Uint32: reflect.TypeOf(uint32(0)),
+ reflect.Uint64: reflect.TypeOf(uint64(0)),
+ reflect.String: reflect.TypeOf(""),
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/database_sql.go b/vendor/github.com/jackc/pgtype/database_sql.go
new file mode 100644
index 000000000..9d1cf8226
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/database_sql.go
@@ -0,0 +1,41 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "errors"
+)
+
+func DatabaseSQLValue(ci *ConnInfo, src Value) (interface{}, error) {
+ if valuer, ok := src.(driver.Valuer); ok {
+ return valuer.Value()
+ }
+
+ if textEncoder, ok := src.(TextEncoder); ok {
+ buf, err := textEncoder.EncodeText(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ return string(buf), nil
+ }
+
+ if binaryEncoder, ok := src.(BinaryEncoder); ok {
+ buf, err := binaryEncoder.EncodeBinary(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ return buf, nil
+ }
+
+ return nil, errors.New("cannot convert to database/sql compatible value")
+}
+
+func EncodeValueText(src TextEncoder) (interface{}, error) {
+ buf, err := src.EncodeText(nil, make([]byte, 0, 32))
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ return string(buf), err
+}
diff --git a/vendor/github.com/jackc/pgtype/date.go b/vendor/github.com/jackc/pgtype/date.go
new file mode 100644
index 000000000..e8d21a78c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/date.go
@@ -0,0 +1,287 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+type Date struct {
+ Time time.Time
+ Status Status
+ InfinityModifier InfinityModifier
+}
+
+const (
+ negativeInfinityDayOffset = -2147483648
+ infinityDayOffset = 2147483647
+)
+
+func (dst *Date) Set(src interface{}) error {
+ if src == nil {
+ *dst = Date{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case time.Time:
+ *dst = Date{Time: value, Status: Present}
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ case *time.Time:
+ if value == nil {
+ *dst = Date{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Date{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingTimeType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Date", value)
+ }
+
+ return nil
+}
+
+func (dst Date) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ if dst.InfinityModifier != None {
+ return dst.InfinityModifier
+ }
+ return dst.Time
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Date) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *time.Time:
+ if src.InfinityModifier != None {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+ }
+ *v = src.Time
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Date) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Date{Status: Null}
+ return nil
+ }
+
+ sbuf := string(src)
+ switch sbuf {
+ case "infinity":
+ *dst = Date{Status: Present, InfinityModifier: Infinity}
+ case "-infinity":
+ *dst = Date{Status: Present, InfinityModifier: -Infinity}
+ default:
+ t, err := time.ParseInLocation("2006-01-02", sbuf, time.UTC)
+ if err != nil {
+ return err
+ }
+
+ *dst = Date{Time: t, Status: Present}
+ }
+
+ return nil
+}
+
+func (dst *Date) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Date{Status: Null}
+ return nil
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length for date: %v", len(src))
+ }
+
+ dayOffset := int32(binary.BigEndian.Uint32(src))
+
+ switch dayOffset {
+ case infinityDayOffset:
+ *dst = Date{Status: Present, InfinityModifier: Infinity}
+ case negativeInfinityDayOffset:
+ *dst = Date{Status: Present, InfinityModifier: -Infinity}
+ default:
+ t := time.Date(2000, 1, int(1+dayOffset), 0, 0, 0, 0, time.UTC)
+ *dst = Date{Time: t, Status: Present}
+ }
+
+ return nil
+}
+
+func (src Date) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var s string
+
+ switch src.InfinityModifier {
+ case None:
+ s = src.Time.Format("2006-01-02")
+ case Infinity:
+ s = "infinity"
+ case NegativeInfinity:
+ s = "-infinity"
+ }
+
+ return append(buf, s...), nil
+}
+
+func (src Date) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var daysSinceDateEpoch int32
+ switch src.InfinityModifier {
+ case None:
+ tUnix := time.Date(src.Time.Year(), src.Time.Month(), src.Time.Day(), 0, 0, 0, 0, time.UTC).Unix()
+ dateEpoch := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
+
+ secSinceDateEpoch := tUnix - dateEpoch
+ daysSinceDateEpoch = int32(secSinceDateEpoch / 86400)
+ case Infinity:
+ daysSinceDateEpoch = infinityDayOffset
+ case NegativeInfinity:
+ daysSinceDateEpoch = negativeInfinityDayOffset
+ }
+
+ return pgio.AppendInt32(buf, daysSinceDateEpoch), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Date) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Date{Status: Null}
+ return 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)
+ case time.Time:
+ *dst = Date{Time: src, Status: Present}
+ return nil
+ }
+
+ return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Date) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ if src.InfinityModifier != None {
+ return src.InfinityModifier.String(), nil
+ }
+ return src.Time, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Date) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.Status != Present {
+ return nil, errBadStatus
+ }
+
+ var s string
+
+ switch src.InfinityModifier {
+ case None:
+ s = src.Time.Format("2006-01-02")
+ case Infinity:
+ s = "infinity"
+ case NegativeInfinity:
+ s = "-infinity"
+ }
+
+ return json.Marshal(s)
+}
+
+func (dst *Date) UnmarshalJSON(b []byte) error {
+ var s *string
+ err := json.Unmarshal(b, &s)
+ if err != nil {
+ return err
+ }
+
+ if s == nil {
+ *dst = Date{Status: Null}
+ return nil
+ }
+
+ switch *s {
+ case "infinity":
+ *dst = Date{Status: Present, InfinityModifier: Infinity}
+ case "-infinity":
+ *dst = Date{Status: Present, InfinityModifier: -Infinity}
+ default:
+ t, err := time.ParseInLocation("2006-01-02", *s, time.UTC)
+ if err != nil {
+ return err
+ }
+
+ *dst = Date{Time: t, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/date_array.go b/vendor/github.com/jackc/pgtype/date_array.go
new file mode 100644
index 000000000..24152fa0e
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/date_array.go
@@ -0,0 +1,518 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+type DateArray struct {
+ Elements []Date
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *DateArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = DateArray{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 []time.Time:
+ if value == nil {
+ *dst = DateArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = DateArray{Status: Present}
+ } else {
+ elements := make([]Date, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = DateArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*time.Time:
+ if value == nil {
+ *dst = DateArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = DateArray{Status: Present}
+ } else {
+ elements := make([]Date, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = DateArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Date:
+ if value == nil {
+ *dst = DateArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = DateArray{Status: Present}
+ } else {
+ *dst = DateArray{
+ 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 = DateArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for DateArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = DateArray{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 DateArray", src)
+ }
+
+ *dst = DateArray{
+ Elements: make([]Date, 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([]Date, 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 DateArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *DateArray) 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 DateArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in DateArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst DateArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *DateArray) 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 *[]time.Time:
+ *v = make([]time.Time, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*time.Time:
+ *v = make([]*time.Time, 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 *DateArray) 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 DateArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from DateArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *DateArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = DateArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Date
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Date, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Date
+ 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 = DateArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *DateArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = DateArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = DateArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Date, 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 = DateArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src DateArray) 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 DateArray) 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("date"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "date")
+ }
+
+ 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 *DateArray) 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 DateArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/daterange.go b/vendor/github.com/jackc/pgtype/daterange.go
new file mode 100644
index 000000000..63164a5a5
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/daterange.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Daterange struct {
+ Lower Date
+ Upper Date
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Daterange) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Daterange{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Daterange:
+ *dst = value
+ case *Daterange:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Daterange", src)
+ }
+
+ return nil
+}
+
+func (dst Daterange) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Daterange) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Daterange) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Daterange{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Daterange{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Daterange) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Daterange{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Daterange{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Daterange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Daterange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Daterange) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Daterange{Status: Null}
+ return 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 Daterange) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/enum_array.go b/vendor/github.com/jackc/pgtype/enum_array.go
new file mode 100644
index 000000000..59b5a3edc
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/enum_array.go
@@ -0,0 +1,428 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+)
+
+type EnumArray struct {
+ Elements []GenericText
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *EnumArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = EnumArray{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 = EnumArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = EnumArray{Status: Present}
+ } else {
+ elements := make([]GenericText, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = EnumArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = EnumArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = EnumArray{Status: Present}
+ } else {
+ elements := make([]GenericText, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = EnumArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []GenericText:
+ if value == nil {
+ *dst = EnumArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = EnumArray{Status: Present}
+ } else {
+ *dst = EnumArray{
+ 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 = EnumArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for EnumArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = EnumArray{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 EnumArray", src)
+ }
+
+ *dst = EnumArray{
+ Elements: make([]GenericText, 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([]GenericText, 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 EnumArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *EnumArray) 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 EnumArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in EnumArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst EnumArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *EnumArray) 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 *[]*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
+
+ }
+ }
+
+ // 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 *EnumArray) 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 EnumArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from EnumArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *EnumArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = EnumArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []GenericText
+
+ if len(uta.Elements) > 0 {
+ elements = make([]GenericText, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem GenericText
+ 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 = EnumArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (src EnumArray) 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
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *EnumArray) 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 EnumArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/enum_type.go b/vendor/github.com/jackc/pgtype/enum_type.go
new file mode 100644
index 000000000..d340320fa
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/enum_type.go
@@ -0,0 +1,168 @@
+package pgtype
+
+import "fmt"
+
+// EnumType represents a 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.
+type EnumType struct {
+ value string
+ status Status
+
+ typeName string // PostgreSQL type name
+ members []string // enum members
+ membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
+}
+
+// NewEnumType initializes a new EnumType. It retains a read-only reference to members. members must not be changed.
+func NewEnumType(typeName string, members []string) *EnumType {
+ et := &EnumType{typeName: typeName, members: members}
+ et.membersMap = make(map[string]string, len(members))
+ for _, m := range members {
+ et.membersMap[m] = m
+ }
+ return et
+}
+
+func (et *EnumType) NewTypeValue() Value {
+ return &EnumType{
+ value: et.value,
+ status: et.status,
+
+ typeName: et.typeName,
+ members: et.members,
+ membersMap: et.membersMap,
+ }
+}
+
+func (et *EnumType) TypeName() string {
+ return et.typeName
+}
+
+func (et *EnumType) Members() []string {
+ return et.members
+}
+
+// Set assigns src to dst. Set purposely does not check that src is a member. This allows continued error free
+// operation in the event the PostgreSQL enum type is modified during a connection.
+func (dst *EnumType) Set(src interface{}) error {
+ if src == nil {
+ dst.status = Null
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case string:
+ dst.value = value
+ dst.status = Present
+ case *string:
+ if value == nil {
+ dst.status = Null
+ } else {
+ dst.value = *value
+ dst.status = Present
+ }
+ case []byte:
+ if value == nil {
+ dst.status = Null
+ } else {
+ dst.value = string(value)
+ dst.status = Present
+ }
+ default:
+ if originalSrc, ok := underlyingStringType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to enum %s", value, dst.typeName)
+ }
+
+ return nil
+}
+
+func (dst EnumType) Get() interface{} {
+ switch dst.status {
+ case Present:
+ return dst.value
+ case Null:
+ return nil
+ default:
+ return dst.status
+ }
+}
+
+func (src *EnumType) AssignTo(dst interface{}) error {
+ switch src.status {
+ case Present:
+ switch v := dst.(type) {
+ case *string:
+ *v = src.value
+ return nil
+ case *[]byte:
+ *v = make([]byte, len(src.value))
+ copy(*v, src.value)
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (EnumType) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *EnumType) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ dst.status = Null
+ return nil
+ }
+
+ // Lookup the string in membersMap to avoid an allocation.
+ if s, found := dst.membersMap[string(src)]; found {
+ dst.value = s
+ } else {
+ // If an enum type is modified after the initial connection it is possible to receive an unexpected value.
+ // Gracefully handle this situation. Purposely NOT modifying members and membersMap to allow for sharing members
+ // and membersMap between connections.
+ dst.value = string(src)
+ }
+ dst.status = Present
+
+ return nil
+}
+
+func (dst *EnumType) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return dst.DecodeText(ci, src)
+}
+
+func (EnumType) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src EnumType) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.value...), nil
+}
+
+func (src EnumType) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return src.EncodeText(ci, buf)
+}
diff --git a/vendor/github.com/jackc/pgtype/float4.go b/vendor/github.com/jackc/pgtype/float4.go
new file mode 100644
index 000000000..89b9e8fae
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/float4.go
@@ -0,0 +1,282 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+type Float4 struct {
+ Float float32
+ Status Status
+}
+
+func (dst *Float4) Set(src interface{}) error {
+ if src == nil {
+ *dst = Float4{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case float32:
+ *dst = Float4{Float: value, Status: Present}
+ case float64:
+ *dst = Float4{Float: float32(value), Status: Present}
+ case int8:
+ *dst = Float4{Float: float32(value), Status: Present}
+ case uint8:
+ *dst = Float4{Float: float32(value), Status: Present}
+ case int16:
+ *dst = Float4{Float: float32(value), Status: Present}
+ case uint16:
+ *dst = Float4{Float: float32(value), Status: Present}
+ case int32:
+ f32 := float32(value)
+ if int32(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case uint32:
+ f32 := float32(value)
+ if uint32(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case int64:
+ f32 := float32(value)
+ if int64(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case uint64:
+ f32 := float32(value)
+ if uint64(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case int:
+ f32 := float32(value)
+ if int(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case uint:
+ f32 := float32(value)
+ if uint(f32) == value {
+ *dst = Float4{Float: f32, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float32", value)
+ }
+ case string:
+ num, err := strconv.ParseFloat(value, 32)
+ if err != nil {
+ return err
+ }
+ *dst = Float4{Float: float32(num), Status: Present}
+ case *float64:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int8:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Float4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Float8", value)
+ }
+
+ return nil
+}
+
+func (dst Float4) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Float
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Float4) AssignTo(dst interface{}) error {
+ return float64AssignTo(float64(src.Float), src.Status, dst)
+}
+
+func (dst *Float4) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float4{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseFloat(string(src), 32)
+ if err != nil {
+ return err
+ }
+
+ *dst = Float4{Float: float32(n), Status: Present}
+ return nil
+}
+
+func (dst *Float4) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float4{Status: Null}
+ return nil
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length for float4: %v", len(src))
+ }
+
+ n := int32(binary.BigEndian.Uint32(src))
+
+ *dst = Float4{Float: math.Float32frombits(uint32(n)), Status: Present}
+ return nil
+}
+
+func (src Float4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 32)...)
+ return buf, nil
+}
+
+func (src Float4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint32(buf, math.Float32bits(src.Float))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Float4) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Float4{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case float64:
+ *dst = Float4{Float: float32(src), Status: Present}
+ return nil
+ 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 Float4) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return float64(src.Float), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/float4_array.go b/vendor/github.com/jackc/pgtype/float4_array.go
new file mode 100644
index 000000000..41f2ec8f4
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/float4_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type Float4Array struct {
+ Elements []Float4
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *Float4Array) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Float4Array{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 []float32:
+ if value == nil {
+ *dst = Float4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float4Array{Status: Present}
+ } else {
+ elements := make([]Float4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Float4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*float32:
+ if value == nil {
+ *dst = Float4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float4Array{Status: Present}
+ } else {
+ elements := make([]Float4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Float4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Float4:
+ if value == nil {
+ *dst = Float4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float4Array{Status: Present}
+ } else {
+ *dst = Float4Array{
+ 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 = Float4Array{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for Float4Array", src)
+ }
+ if elementsLength == 0 {
+ *dst = Float4Array{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 Float4Array", src)
+ }
+
+ *dst = Float4Array{
+ Elements: make([]Float4, 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([]Float4, 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 Float4Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *Float4Array) 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 Float4Array")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in Float4Array", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst Float4Array) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Float4Array) 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 *[]float32:
+ *v = make([]float32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*float32:
+ *v = make([]*float32, 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 *Float4Array) 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 Float4Array")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from Float4Array")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *Float4Array) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float4Array{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Float4
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Float4, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Float4
+ 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 = Float4Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *Float4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float4Array{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = Float4Array{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Float4, 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 = Float4Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src Float4Array) 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 Float4Array) 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("float4"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "float4")
+ }
+
+ 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 *Float4Array) 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 Float4Array) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/float8.go b/vendor/github.com/jackc/pgtype/float8.go
new file mode 100644
index 000000000..4d9e7116a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/float8.go
@@ -0,0 +1,272 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+type Float8 struct {
+ Float float64
+ Status Status
+}
+
+func (dst *Float8) Set(src interface{}) error {
+ if src == nil {
+ *dst = Float8{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case float32:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case float64:
+ *dst = Float8{Float: value, Status: Present}
+ case int8:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case uint8:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case int16:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case uint16:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case int32:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case uint32:
+ *dst = Float8{Float: float64(value), Status: Present}
+ case int64:
+ f64 := float64(value)
+ if int64(f64) == value {
+ *dst = Float8{Float: f64, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float64", value)
+ }
+ case uint64:
+ f64 := float64(value)
+ if uint64(f64) == value {
+ *dst = Float8{Float: f64, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float64", value)
+ }
+ case int:
+ f64 := float64(value)
+ if int(f64) == value {
+ *dst = Float8{Float: f64, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float64", value)
+ }
+ case uint:
+ f64 := float64(value)
+ if uint(f64) == value {
+ *dst = Float8{Float: f64, Status: Present}
+ } else {
+ return fmt.Errorf("%v cannot be exactly represented as float64", value)
+ }
+ case string:
+ num, err := strconv.ParseFloat(value, 64)
+ if err != nil {
+ return err
+ }
+ *dst = Float8{Float: float64(num), Status: Present}
+ case *float64:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int8:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Float8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Float8", value)
+ }
+
+ return nil
+}
+
+func (dst Float8) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Float
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Float8) AssignTo(dst interface{}) error {
+ return float64AssignTo(src.Float, src.Status, dst)
+}
+
+func (dst *Float8) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float8{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseFloat(string(src), 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Float8{Float: n, Status: Present}
+ return nil
+}
+
+func (dst *Float8) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float8{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for float4: %v", len(src))
+ }
+
+ n := int64(binary.BigEndian.Uint64(src))
+
+ *dst = Float8{Float: math.Float64frombits(uint64(n)), Status: Present}
+ return nil
+}
+
+func (src Float8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 64)...)
+ return buf, nil
+}
+
+func (src Float8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.Float))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Float8) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Float8{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case float64:
+ *dst = Float8{Float: src, Status: Present}
+ return nil
+ 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 Float8) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.Float, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/float8_array.go b/vendor/github.com/jackc/pgtype/float8_array.go
new file mode 100644
index 000000000..836ee19dc
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/float8_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type Float8Array struct {
+ Elements []Float8
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *Float8Array) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Float8Array{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 []float64:
+ if value == nil {
+ *dst = Float8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float8Array{Status: Present}
+ } else {
+ elements := make([]Float8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Float8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*float64:
+ if value == nil {
+ *dst = Float8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float8Array{Status: Present}
+ } else {
+ elements := make([]Float8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Float8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Float8:
+ if value == nil {
+ *dst = Float8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Float8Array{Status: Present}
+ } else {
+ *dst = Float8Array{
+ 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 = Float8Array{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for Float8Array", src)
+ }
+ if elementsLength == 0 {
+ *dst = Float8Array{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 Float8Array", src)
+ }
+
+ *dst = Float8Array{
+ Elements: make([]Float8, 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([]Float8, 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 Float8Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *Float8Array) 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 Float8Array")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in Float8Array", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst Float8Array) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Float8Array) 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 *[]float64:
+ *v = make([]float64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*float64:
+ *v = make([]*float64, 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 *Float8Array) 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 Float8Array")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from Float8Array")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *Float8Array) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float8Array{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Float8
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Float8, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Float8
+ 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 = Float8Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *Float8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Float8Array{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = Float8Array{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Float8, 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 = Float8Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src Float8Array) 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 Float8Array) 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("float8"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "float8")
+ }
+
+ 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 *Float8Array) 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 Float8Array) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/generic_binary.go b/vendor/github.com/jackc/pgtype/generic_binary.go
new file mode 100644
index 000000000..76a1d3511
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/generic_binary.go
@@ -0,0 +1,39 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// GenericBinary is a placeholder for binary format values that no other type exists
+// to handle.
+type GenericBinary Bytea
+
+func (dst *GenericBinary) Set(src interface{}) error {
+ return (*Bytea)(dst).Set(src)
+}
+
+func (dst GenericBinary) Get() interface{} {
+ return (Bytea)(dst).Get()
+}
+
+func (src *GenericBinary) AssignTo(dst interface{}) error {
+ return (*Bytea)(src).AssignTo(dst)
+}
+
+func (dst *GenericBinary) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Bytea)(dst).DecodeBinary(ci, src)
+}
+
+func (src GenericBinary) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Bytea)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *GenericBinary) Scan(src interface{}) error {
+ return (*Bytea)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src GenericBinary) Value() (driver.Value, error) {
+ return (Bytea)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/generic_text.go b/vendor/github.com/jackc/pgtype/generic_text.go
new file mode 100644
index 000000000..dbf5b47e8
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/generic_text.go
@@ -0,0 +1,39 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// GenericText is a placeholder for text format values that no other type exists
+// to handle.
+type GenericText Text
+
+func (dst *GenericText) Set(src interface{}) error {
+ return (*Text)(dst).Set(src)
+}
+
+func (dst GenericText) Get() interface{} {
+ return (Text)(dst).Get()
+}
+
+func (src *GenericText) AssignTo(dst interface{}) error {
+ return (*Text)(src).AssignTo(dst)
+}
+
+func (dst *GenericText) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeText(ci, src)
+}
+
+func (src GenericText) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeText(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *GenericText) Scan(src interface{}) error {
+ return (*Text)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src GenericText) Value() (driver.Value, error) {
+ return (Text)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/go.mod b/vendor/github.com/jackc/pgtype/go.mod
new file mode 100644
index 000000000..63bae8798
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/go.mod
@@ -0,0 +1,13 @@
+module github.com/jackc/pgtype
+
+go 1.13
+
+require (
+ github.com/gofrs/uuid v4.0.0+incompatible
+ github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530
+ github.com/jackc/pgio v1.0.0
+ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c
+ github.com/lib/pq v1.10.2
+ github.com/shopspring/decimal v1.2.0
+ github.com/stretchr/testify v1.7.0
+)
diff --git a/vendor/github.com/jackc/pgtype/go.sum b/vendor/github.com/jackc/pgtype/go.sum
new file mode 100644
index 000000000..8f2d760e4
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/go.sum
@@ -0,0 +1,175 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+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/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
+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.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530 h1:dUJ578zuPEsXjtzOfEF0q9zDAfljJ9oFnTHcQaNkccw=
+github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+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/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+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/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/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/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/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-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+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-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c h1:Dznn52SgVIVst9UyOT9brctYUgxs+CvVfPaC3jKrA50=
+github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+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 v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
diff --git a/vendor/github.com/jackc/pgtype/hstore.go b/vendor/github.com/jackc/pgtype/hstore.go
new file mode 100644
index 000000000..18b413c6b
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/hstore.go
@@ -0,0 +1,439 @@
+package pgtype
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/jackc/pgio"
+)
+
+// Hstore represents an hstore column that can be null or have null values
+// associated with its keys.
+type Hstore struct {
+ Map map[string]Text
+ Status Status
+}
+
+func (dst *Hstore) Set(src interface{}) error {
+ if src == nil {
+ *dst = Hstore{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case map[string]string:
+ m := make(map[string]Text, len(value))
+ for k, v := range value {
+ m[k] = Text{String: v, Status: Present}
+ }
+ *dst = Hstore{Map: m, Status: Present}
+ default:
+ return fmt.Errorf("cannot convert %v to Hstore", src)
+ }
+
+ return nil
+}
+
+func (dst Hstore) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Map
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Hstore) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *map[string]string:
+ *v = make(map[string]string, len(src.Map))
+ for k, val := range src.Map {
+ if val.Status != Present {
+ return fmt.Errorf("cannot decode %#v into %T", src, dst)
+ }
+ (*v)[k] = val.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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Hstore) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Hstore{Status: Null}
+ return nil
+ }
+
+ keys, values, err := parseHstore(string(src))
+ if err != nil {
+ return err
+ }
+
+ m := make(map[string]Text, len(keys))
+ for i := range keys {
+ m[keys[i]] = values[i]
+ }
+
+ *dst = Hstore{Map: m, Status: Present}
+ return nil
+}
+
+func (dst *Hstore) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Hstore{Status: Null}
+ return nil
+ }
+
+ rp := 0
+
+ if len(src[rp:]) < 4 {
+ return fmt.Errorf("hstore incomplete %v", src)
+ }
+ pairCount := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+
+ m := make(map[string]Text, pairCount)
+
+ for i := 0; i < pairCount; i++ {
+ if len(src[rp:]) < 4 {
+ return fmt.Errorf("hstore incomplete %v", src)
+ }
+ keyLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+
+ if len(src[rp:]) < keyLen {
+ return fmt.Errorf("hstore incomplete %v", src)
+ }
+ key := string(src[rp : rp+keyLen])
+ rp += keyLen
+
+ if len(src[rp:]) < 4 {
+ return fmt.Errorf("hstore incomplete %v", src)
+ }
+ valueLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
+ rp += 4
+
+ var valueBuf []byte
+ if valueLen >= 0 {
+ valueBuf = src[rp : rp+valueLen]
+ }
+ rp += valueLen
+
+ var value Text
+ err := value.DecodeBinary(ci, valueBuf)
+ if err != nil {
+ return err
+ }
+ m[key] = value
+ }
+
+ *dst = Hstore{Map: m, Status: Present}
+
+ return nil
+}
+
+func (src Hstore) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ firstPair := true
+
+ inElemBuf := make([]byte, 0, 32)
+ for k, v := range src.Map {
+ if firstPair {
+ firstPair = false
+ } else {
+ buf = append(buf, ',')
+ }
+
+ buf = append(buf, quoteHstoreElementIfNeeded(k)...)
+ buf = append(buf, "=>"...)
+
+ elemBuf, err := v.EncodeText(ci, inElemBuf)
+ if err != nil {
+ return nil, err
+ }
+
+ if elemBuf == nil {
+ buf = append(buf, "NULL"...)
+ } else {
+ buf = append(buf, quoteHstoreElementIfNeeded(string(elemBuf))...)
+ }
+ }
+
+ return buf, nil
+}
+
+func (src Hstore) 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.Map)))
+
+ var err error
+ for k, v := range src.Map {
+ buf = pgio.AppendInt32(buf, int32(len(k)))
+ buf = append(buf, k...)
+
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ elemBuf, err := v.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if elemBuf != nil {
+ buf = elemBuf
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+ }
+
+ return buf, err
+}
+
+var quoteHstoreReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
+
+func quoteHstoreElement(src string) string {
+ return `"` + quoteArrayReplacer.Replace(src) + `"`
+}
+
+func quoteHstoreElementIfNeeded(src string) string {
+ if src == "" || (len(src) == 4 && strings.ToLower(src) == "null") || strings.ContainsAny(src, ` {},"\=>`) {
+ return quoteArrayElement(src)
+ }
+ return src
+}
+
+const (
+ hsPre = iota
+ hsKey
+ hsSep
+ hsVal
+ hsNul
+ hsNext
+)
+
+type hstoreParser struct {
+ str string
+ pos int
+}
+
+func newHSP(in string) *hstoreParser {
+ return &hstoreParser{
+ pos: 0,
+ str: in,
+ }
+}
+
+func (p *hstoreParser) Consume() (r rune, end bool) {
+ if p.pos >= len(p.str) {
+ end = true
+ return
+ }
+ r, w := utf8.DecodeRuneInString(p.str[p.pos:])
+ p.pos += w
+ return
+}
+
+func (p *hstoreParser) Peek() (r rune, end bool) {
+ if p.pos >= len(p.str) {
+ end = true
+ return
+ }
+ r, _ = utf8.DecodeRuneInString(p.str[p.pos:])
+ return
+}
+
+// parseHstore parses the string representation of an hstore column (the same
+// you would get from an ordinary SELECT) into two slices of keys and values. it
+// is used internally in the default parsing of hstores.
+func parseHstore(s string) (k []string, v []Text, err error) {
+ if s == "" {
+ return
+ }
+
+ buf := bytes.Buffer{}
+ keys := []string{}
+ values := []Text{}
+ p := newHSP(s)
+
+ r, end := p.Consume()
+ state := hsPre
+
+ for !end {
+ switch state {
+ case hsPre:
+ if r == '"' {
+ state = hsKey
+ } else {
+ err = errors.New("String does not begin with \"")
+ }
+ case hsKey:
+ switch r {
+ case '"': //End of the key
+ keys = append(keys, buf.String())
+ buf = bytes.Buffer{}
+ state = hsSep
+ case '\\': //Potential escaped character
+ n, end := p.Consume()
+ switch {
+ case end:
+ err = errors.New("Found EOS in key, expecting character or \"")
+ case n == '"', n == '\\':
+ buf.WriteRune(n)
+ default:
+ buf.WriteRune(r)
+ buf.WriteRune(n)
+ }
+ default: //Any other character
+ buf.WriteRune(r)
+ }
+ case hsSep:
+ if r == '=' {
+ r, end = p.Consume()
+ switch {
+ case end:
+ err = errors.New("Found EOS after '=', expecting '>'")
+ case r == '>':
+ r, end = p.Consume()
+ switch {
+ case end:
+ err = errors.New("Found EOS after '=>', expecting '\"' or 'NULL'")
+ case r == '"':
+ state = hsVal
+ case r == 'N':
+ state = hsNul
+ default:
+ err = fmt.Errorf("Invalid character '%c' after '=>', expecting '\"' or 'NULL'", r)
+ }
+ default:
+ err = fmt.Errorf("Invalid character after '=', expecting '>'")
+ }
+ } else {
+ err = fmt.Errorf("Invalid character '%c' after value, expecting '='", r)
+ }
+ case hsVal:
+ switch r {
+ case '"': //End of the value
+ values = append(values, Text{String: buf.String(), Status: Present})
+ buf = bytes.Buffer{}
+ state = hsNext
+ case '\\': //Potential escaped character
+ n, end := p.Consume()
+ switch {
+ case end:
+ err = errors.New("Found EOS in key, expecting character or \"")
+ case n == '"', n == '\\':
+ buf.WriteRune(n)
+ default:
+ buf.WriteRune(r)
+ buf.WriteRune(n)
+ }
+ default: //Any other character
+ buf.WriteRune(r)
+ }
+ case hsNul:
+ nulBuf := make([]rune, 3)
+ nulBuf[0] = r
+ for i := 1; i < 3; i++ {
+ r, end = p.Consume()
+ if end {
+ err = errors.New("Found EOS in NULL value")
+ return
+ }
+ nulBuf[i] = r
+ }
+ if nulBuf[0] == 'U' && nulBuf[1] == 'L' && nulBuf[2] == 'L' {
+ values = append(values, Text{Status: Null})
+ state = hsNext
+ } else {
+ err = fmt.Errorf("Invalid NULL value: 'N%s'", string(nulBuf))
+ }
+ case hsNext:
+ if r == ',' {
+ r, end = p.Consume()
+ switch {
+ case end:
+ err = errors.New("Found EOS after ',', expcting space")
+ case (unicode.IsSpace(r)):
+ r, end = p.Consume()
+ state = hsKey
+ default:
+ err = fmt.Errorf("Invalid character '%c' after ', ', expecting \"", r)
+ }
+ } else {
+ err = fmt.Errorf("Invalid character '%c' after value, expecting ','", r)
+ }
+ }
+
+ if err != nil {
+ return
+ }
+ r, end = p.Consume()
+ }
+ if state != hsNext {
+ err = errors.New("Improperly formatted hstore")
+ return
+ }
+ k = keys
+ v = values
+ return
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Hstore) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Hstore{Status: Null}
+ return 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 Hstore) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/hstore_array.go b/vendor/github.com/jackc/pgtype/hstore_array.go
new file mode 100644
index 000000000..47b4b3fff
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/hstore_array.go
@@ -0,0 +1,489 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type HstoreArray struct {
+ Elements []Hstore
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *HstoreArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = HstoreArray{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 []map[string]string:
+ if value == nil {
+ *dst = HstoreArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = HstoreArray{Status: Present}
+ } else {
+ elements := make([]Hstore, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = HstoreArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Hstore:
+ if value == nil {
+ *dst = HstoreArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = HstoreArray{Status: Present}
+ } else {
+ *dst = HstoreArray{
+ 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 = HstoreArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for HstoreArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = HstoreArray{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 HstoreArray", src)
+ }
+
+ *dst = HstoreArray{
+ Elements: make([]Hstore, 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([]Hstore, 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 HstoreArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *HstoreArray) 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 HstoreArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in HstoreArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst HstoreArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *HstoreArray) 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 *[]map[string]string:
+ *v = make([]map[string]string, 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 *HstoreArray) 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 HstoreArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from HstoreArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *HstoreArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = HstoreArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Hstore
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Hstore, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Hstore
+ 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 = HstoreArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *HstoreArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = HstoreArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = HstoreArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Hstore, 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 = HstoreArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src HstoreArray) 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 HstoreArray) 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("hstore"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "hstore")
+ }
+
+ 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 *HstoreArray) 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 HstoreArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/inet.go b/vendor/github.com/jackc/pgtype/inet.go
new file mode 100644
index 000000000..1645334e3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/inet.go
@@ -0,0 +1,250 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "net"
+)
+
+// Network address family is dependent on server socket.h value for AF_INET.
+// In practice, all platforms appear to have the same value. See
+// src/include/utils/inet.h for more information.
+const (
+ defaultAFInet = 2
+ defaultAFInet6 = 3
+)
+
+// Inet represents both inet and cidr PostgreSQL types.
+type Inet struct {
+ IPNet *net.IPNet
+ Status Status
+}
+
+func (dst *Inet) Set(src interface{}) error {
+ if src == nil {
+ *dst = Inet{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case net.IPNet:
+ *dst = Inet{IPNet: &value, Status: Present}
+ case net.IP:
+ if len(value) == 0 {
+ *dst = Inet{Status: Null}
+ } else {
+ bitCount := len(value) * 8
+ mask := net.CIDRMask(bitCount, bitCount)
+ *dst = Inet{IPNet: &net.IPNet{Mask: mask, IP: value}, Status: Present}
+ }
+ case string:
+ ip, ipnet, err := net.ParseCIDR(value)
+ if err != nil {
+ return err
+ }
+ ipnet.IP = ip
+ *dst = Inet{IPNet: ipnet, Status: Present}
+ case *net.IPNet:
+ if value == nil {
+ *dst = Inet{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *net.IP:
+ if value == nil {
+ *dst = Inet{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Inet{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingPtrType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Inet", value)
+ }
+
+ return nil
+}
+
+func (dst Inet) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.IPNet
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Inet) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *net.IPNet:
+ *v = net.IPNet{
+ IP: make(net.IP, len(src.IPNet.IP)),
+ Mask: make(net.IPMask, len(src.IPNet.Mask)),
+ }
+ copy(v.IP, src.IPNet.IP)
+ copy(v.Mask, src.IPNet.Mask)
+ return nil
+ case *net.IP:
+ if oneCount, bitCount := src.IPNet.Mask.Size(); oneCount != bitCount {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+ }
+ *v = make(net.IP, len(src.IPNet.IP))
+ copy(*v, src.IPNet.IP)
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Inet) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Inet{Status: Null}
+ return nil
+ }
+
+ var ipnet *net.IPNet
+ var err error
+
+ if ip := net.ParseIP(string(src)); ip != nil {
+ if ipv4 := ip.To4(); ipv4 != nil {
+ ip = ipv4
+ }
+ bitCount := len(ip) * 8
+ mask := net.CIDRMask(bitCount, bitCount)
+ ipnet = &net.IPNet{Mask: mask, IP: ip}
+ } else {
+ ip, ipnet, err = net.ParseCIDR(string(src))
+ if err != nil {
+ return err
+ }
+ if ipv4 := ip.To4(); ipv4 != nil {
+ ip = ipv4
+ }
+ ones, _ := ipnet.Mask.Size()
+ *ipnet = net.IPNet{IP: ip, Mask: net.CIDRMask(ones, len(ip)*8)}
+ }
+
+ *dst = Inet{IPNet: ipnet, Status: Present}
+ return nil
+}
+
+func (dst *Inet) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Inet{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 && len(src) != 20 {
+ return fmt.Errorf("Received an invalid size for a inet: %d", len(src))
+ }
+
+ // ignore family
+ bits := src[1]
+ // ignore is_cidr
+ addressLength := src[3]
+
+ var ipnet net.IPNet
+ ipnet.IP = make(net.IP, int(addressLength))
+ copy(ipnet.IP, src[4:])
+ if ipv4 := ipnet.IP.To4(); ipv4 != nil {
+ ipnet.IP = ipv4
+ }
+ ipnet.Mask = net.CIDRMask(int(bits), len(ipnet.IP)*8)
+
+ *dst = Inet{IPNet: &ipnet, Status: Present}
+
+ return nil
+}
+
+func (src Inet) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.IPNet.String()...), nil
+}
+
+// EncodeBinary encodes src into w.
+func (src Inet) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var family byte
+ switch len(src.IPNet.IP) {
+ case net.IPv4len:
+ family = defaultAFInet
+ case net.IPv6len:
+ family = defaultAFInet6
+ default:
+ return nil, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
+ }
+
+ buf = append(buf, family)
+
+ ones, _ := src.IPNet.Mask.Size()
+ buf = append(buf, byte(ones))
+
+ // is_cidr is ignored on server
+ buf = append(buf, 0)
+
+ buf = append(buf, byte(len(src.IPNet.IP)))
+
+ return append(buf, src.IPNet.IP...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Inet) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Inet{Status: Null}
+ return 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 Inet) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/inet_array.go b/vendor/github.com/jackc/pgtype/inet_array.go
new file mode 100644
index 000000000..2460a1c4d
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/inet_array.go
@@ -0,0 +1,546 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "net"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type InetArray struct {
+ Elements []Inet
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *InetArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = InetArray{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 []*net.IPNet:
+ if value == nil {
+ *dst = InetArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = InetArray{Status: Present}
+ } else {
+ elements := make([]Inet, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = InetArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []net.IP:
+ if value == nil {
+ *dst = InetArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = InetArray{Status: Present}
+ } else {
+ elements := make([]Inet, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = InetArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*net.IP:
+ if value == nil {
+ *dst = InetArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = InetArray{Status: Present}
+ } else {
+ elements := make([]Inet, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = InetArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Inet:
+ if value == nil {
+ *dst = InetArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = InetArray{Status: Present}
+ } else {
+ *dst = InetArray{
+ 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 = InetArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for InetArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = InetArray{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 InetArray", src)
+ }
+
+ *dst = InetArray{
+ Elements: make([]Inet, 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([]Inet, 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 InetArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *InetArray) 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 InetArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in InetArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst InetArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *InetArray) 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 *[]*net.IPNet:
+ *v = make([]*net.IPNet, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]net.IP:
+ *v = make([]net.IP, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*net.IP:
+ *v = make([]*net.IP, 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 *InetArray) 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 InetArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from InetArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *InetArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = InetArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Inet
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Inet, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Inet
+ 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 = InetArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *InetArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = InetArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = InetArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Inet, 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 = InetArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src InetArray) 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 InetArray) 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("inet"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "inet")
+ }
+
+ 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 *InetArray) 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 InetArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/int2.go b/vendor/github.com/jackc/pgtype/int2.go
new file mode 100644
index 000000000..3eb5aeb55
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int2.go
@@ -0,0 +1,304 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+type Int2 struct {
+ Int int16
+ Status Status
+}
+
+func (dst *Int2) Set(src interface{}) error {
+ if src == nil {
+ *dst = Int2{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case int8:
+ *dst = Int2{Int: int16(value), Status: Present}
+ case uint8:
+ *dst = Int2{Int: int16(value), Status: Present}
+ case int16:
+ *dst = Int2{Int: int16(value), Status: Present}
+ case uint16:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case int32:
+ if value < math.MinInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case uint32:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case int64:
+ if value < math.MinInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case uint64:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case int:
+ if value < math.MinInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case uint:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case string:
+ num, err := strconv.ParseInt(value, 10, 16)
+ if err != nil {
+ return err
+ }
+ *dst = Int2{Int: int16(num), Status: Present}
+ case float32:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%f is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case float64:
+ if value > math.MaxInt16 {
+ return fmt.Errorf("%f is greater than maximum value for Int2", value)
+ }
+ *dst = Int2{Int: int16(value), Status: Present}
+ case *int8:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float64:
+ if value == nil {
+ *dst = Int2{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Int2", value)
+ }
+
+ return nil
+}
+
+func (dst Int2) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Int
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int2) AssignTo(dst interface{}) error {
+ return int64AssignTo(int64(src.Int), src.Status, dst)
+}
+
+func (dst *Int2) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int2{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseInt(string(src), 10, 16)
+ if err != nil {
+ return err
+ }
+
+ *dst = Int2{Int: int16(n), Status: Present}
+ return nil
+}
+
+func (dst *Int2) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int2{Status: Null}
+ return nil
+ }
+
+ if len(src) != 2 {
+ return fmt.Errorf("invalid length for int2: %v", len(src))
+ }
+
+ n := int16(binary.BigEndian.Uint16(src))
+ *dst = Int2{Int: n, Status: Present}
+ return nil
+}
+
+func (src Int2) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
+}
+
+func (src Int2) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return pgio.AppendInt16(buf, src.Int), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Int2) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Int2{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case int64:
+ if src < math.MinInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", src)
+ }
+ if src > math.MaxInt16 {
+ return fmt.Errorf("%d is greater than maximum value for Int2", src)
+ }
+ *dst = Int2{Int: int16(src), Status: Present}
+ return nil
+ 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 Int2) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return int64(src.Int), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Int2) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ return []byte(strconv.FormatInt(int64(src.Int), 10)), nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
diff --git a/vendor/github.com/jackc/pgtype/int2_array.go b/vendor/github.com/jackc/pgtype/int2_array.go
new file mode 100644
index 000000000..a51338450
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int2_array.go
@@ -0,0 +1,909 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type Int2Array struct {
+ Elements []Int2
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *Int2Array) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Int2Array{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 []int16:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int16:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint16:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint16:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int32:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int32:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint32:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint32:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int64:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int64:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint64:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint64:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ elements := make([]Int2, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int2Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Int2:
+ if value == nil {
+ *dst = Int2Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int2Array{Status: Present}
+ } else {
+ *dst = Int2Array{
+ 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 = Int2Array{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for Int2Array", src)
+ }
+ if elementsLength == 0 {
+ *dst = Int2Array{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 Int2Array", src)
+ }
+
+ *dst = Int2Array{
+ Elements: make([]Int2, 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([]Int2, 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 Int2Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *Int2Array) 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 Int2Array")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in Int2Array", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst Int2Array) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int2Array) 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 *[]int16:
+ *v = make([]int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int16:
+ *v = make([]*int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint16:
+ *v = make([]uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint16:
+ *v = make([]*uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int32:
+ *v = make([]int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int32:
+ *v = make([]*int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint32:
+ *v = make([]uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint32:
+ *v = make([]*uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int64:
+ *v = make([]int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int64:
+ *v = make([]*int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint64:
+ *v = make([]uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint64:
+ *v = make([]*uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int:
+ *v = make([]int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int:
+ *v = make([]*int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint:
+ *v = make([]uint, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint:
+ *v = make([]*uint, 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 *Int2Array) 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 Int2Array")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from Int2Array")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *Int2Array) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int2Array{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Int2
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Int2, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Int2
+ 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 = Int2Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *Int2Array) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int2Array{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = Int2Array{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Int2, 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 = Int2Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src Int2Array) 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 Int2Array) 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("int2"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "int2")
+ }
+
+ 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 *Int2Array) 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 Int2Array) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/int4.go b/vendor/github.com/jackc/pgtype/int4.go
new file mode 100644
index 000000000..22b48e5e5
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int4.go
@@ -0,0 +1,312 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+type Int4 struct {
+ Int int32
+ Status Status
+}
+
+func (dst *Int4) Set(src interface{}) error {
+ if src == nil {
+ *dst = Int4{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case int8:
+ *dst = Int4{Int: int32(value), Status: Present}
+ case uint8:
+ *dst = Int4{Int: int32(value), Status: Present}
+ case int16:
+ *dst = Int4{Int: int32(value), Status: Present}
+ case uint16:
+ *dst = Int4{Int: int32(value), Status: Present}
+ case int32:
+ *dst = Int4{Int: int32(value), Status: Present}
+ case uint32:
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case int64:
+ if value < math.MinInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case uint64:
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case int:
+ if value < math.MinInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case uint:
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case string:
+ num, err := strconv.ParseInt(value, 10, 32)
+ if err != nil {
+ return err
+ }
+ *dst = Int4{Int: int32(num), Status: Present}
+ case float32:
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%f is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case float64:
+ if value > math.MaxInt32 {
+ return fmt.Errorf("%f is greater than maximum value for Int4", value)
+ }
+ *dst = Int4{Int: int32(value), Status: Present}
+ case *int8:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float64:
+ if value == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Int4", value)
+ }
+
+ return nil
+}
+
+func (dst Int4) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Int
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int4) AssignTo(dst interface{}) error {
+ return int64AssignTo(int64(src.Int), src.Status, dst)
+}
+
+func (dst *Int4) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseInt(string(src), 10, 32)
+ if err != nil {
+ return err
+ }
+
+ *dst = Int4{Int: int32(n), Status: Present}
+ return nil
+}
+
+func (dst *Int4) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4{Status: Null}
+ return nil
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length for int4: %v", len(src))
+ }
+
+ n := int32(binary.BigEndian.Uint32(src))
+ *dst = Int4{Int: n, Status: Present}
+ return nil
+}
+
+func (src Int4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
+}
+
+func (src Int4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return pgio.AppendInt32(buf, src.Int), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Int4) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Int4{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case int64:
+ if src < math.MinInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", src)
+ }
+ if src > math.MaxInt32 {
+ return fmt.Errorf("%d is greater than maximum value for Int4", src)
+ }
+ *dst = Int4{Int: int32(src), Status: Present}
+ return nil
+ 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 Int4) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return int64(src.Int), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Int4) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ return []byte(strconv.FormatInt(int64(src.Int), 10)), nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
+
+func (dst *Int4) UnmarshalJSON(b []byte) error {
+ var n *int32
+ err := json.Unmarshal(b, &n)
+ if err != nil {
+ return err
+ }
+
+ if n == nil {
+ *dst = Int4{Status: Null}
+ } else {
+ *dst = Int4{Int: *n, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/int4_array.go b/vendor/github.com/jackc/pgtype/int4_array.go
new file mode 100644
index 000000000..de26236fd
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int4_array.go
@@ -0,0 +1,909 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type Int4Array struct {
+ Elements []Int4
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *Int4Array) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Int4Array{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 []int16:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int16:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint16:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint16:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int32:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int32:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint32:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint32:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int64:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int64:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint64:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint64:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ elements := make([]Int4, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int4Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Int4:
+ if value == nil {
+ *dst = Int4Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int4Array{Status: Present}
+ } else {
+ *dst = Int4Array{
+ 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 = Int4Array{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for Int4Array", src)
+ }
+ if elementsLength == 0 {
+ *dst = Int4Array{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 Int4Array", src)
+ }
+
+ *dst = Int4Array{
+ Elements: make([]Int4, 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([]Int4, 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 Int4Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *Int4Array) 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 Int4Array")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in Int4Array", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst Int4Array) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int4Array) 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 *[]int16:
+ *v = make([]int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int16:
+ *v = make([]*int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint16:
+ *v = make([]uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint16:
+ *v = make([]*uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int32:
+ *v = make([]int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int32:
+ *v = make([]*int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint32:
+ *v = make([]uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint32:
+ *v = make([]*uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int64:
+ *v = make([]int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int64:
+ *v = make([]*int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint64:
+ *v = make([]uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint64:
+ *v = make([]*uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int:
+ *v = make([]int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int:
+ *v = make([]*int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint:
+ *v = make([]uint, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint:
+ *v = make([]*uint, 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 *Int4Array) 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 Int4Array")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from Int4Array")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *Int4Array) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4Array{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Int4
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Int4, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Int4
+ 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 = Int4Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *Int4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4Array{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = Int4Array{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Int4, 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 = Int4Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src Int4Array) 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 Int4Array) 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("int4"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "int4")
+ }
+
+ 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 *Int4Array) 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 Int4Array) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/int4range.go b/vendor/github.com/jackc/pgtype/int4range.go
new file mode 100644
index 000000000..c7f51fa6a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int4range.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Int4range struct {
+ Lower Int4
+ Upper Int4
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Int4range) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Int4range{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Int4range:
+ *dst = value
+ case *Int4range:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Int4range", src)
+ }
+
+ return nil
+}
+
+func (dst Int4range) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int4range) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Int4range) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4range{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Int4range{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Int4range) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int4range{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Int4range{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Int4range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Int4range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Int4range) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Int4range{Status: Null}
+ return 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 Int4range) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/int8.go b/vendor/github.com/jackc/pgtype/int8.go
new file mode 100644
index 000000000..0e0899795
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int8.go
@@ -0,0 +1,298 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+type Int8 struct {
+ Int int64
+ Status Status
+}
+
+func (dst *Int8) Set(src interface{}) error {
+ if src == nil {
+ *dst = Int8{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case int8:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case uint8:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case int16:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case uint16:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case int32:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case uint32:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case int64:
+ *dst = Int8{Int: int64(value), Status: Present}
+ case uint64:
+ if value > math.MaxInt64 {
+ return fmt.Errorf("%d is greater than maximum value for Int8", value)
+ }
+ *dst = Int8{Int: int64(value), Status: Present}
+ case int:
+ if int64(value) < math.MinInt64 {
+ return fmt.Errorf("%d is greater than maximum value for Int8", value)
+ }
+ if int64(value) > math.MaxInt64 {
+ return fmt.Errorf("%d is greater than maximum value for Int8", value)
+ }
+ *dst = Int8{Int: int64(value), Status: Present}
+ case uint:
+ if uint64(value) > math.MaxInt64 {
+ return fmt.Errorf("%d is greater than maximum value for Int8", value)
+ }
+ *dst = Int8{Int: int64(value), Status: Present}
+ case string:
+ num, err := strconv.ParseInt(value, 10, 64)
+ if err != nil {
+ return err
+ }
+ *dst = Int8{Int: num, Status: Present}
+ case float32:
+ if value > math.MaxInt64 {
+ return fmt.Errorf("%f is greater than maximum value for Int8", value)
+ }
+ *dst = Int8{Int: int64(value), Status: Present}
+ case float64:
+ if value > math.MaxInt64 {
+ return fmt.Errorf("%f is greater than maximum value for Int8", value)
+ }
+ *dst = Int8{Int: int64(value), Status: Present}
+ case *int8:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float64:
+ if value == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Int8", value)
+ }
+
+ return nil
+}
+
+func (dst Int8) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Int
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int8) AssignTo(dst interface{}) error {
+ return int64AssignTo(int64(src.Int), src.Status, dst)
+}
+
+func (dst *Int8) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseInt(string(src), 10, 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Int8{Int: n, Status: Present}
+ return nil
+}
+
+func (dst *Int8) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for int8: %v", len(src))
+ }
+
+ n := int64(binary.BigEndian.Uint64(src))
+
+ *dst = Int8{Int: n, Status: Present}
+ return nil
+}
+
+func (src Int8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, strconv.FormatInt(src.Int, 10)...), nil
+}
+
+func (src Int8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return pgio.AppendInt64(buf, src.Int), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Int8) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Int8{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case int64:
+ *dst = Int8{Int: src, Status: Present}
+ return nil
+ 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 Int8) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return int64(src.Int), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Int8) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ return []byte(strconv.FormatInt(src.Int, 10)), nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
+
+func (dst *Int8) UnmarshalJSON(b []byte) error {
+ var n *int64
+ err := json.Unmarshal(b, &n)
+ if err != nil {
+ return err
+ }
+
+ if n == nil {
+ *dst = Int8{Status: Null}
+ } else {
+ *dst = Int8{Int: *n, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/int8_array.go b/vendor/github.com/jackc/pgtype/int8_array.go
new file mode 100644
index 000000000..e405b326d
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int8_array.go
@@ -0,0 +1,909 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type Int8Array struct {
+ Elements []Int8
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *Int8Array) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Int8Array{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 []int16:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int16:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint16:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint16:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int32:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int32:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint32:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint32:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int64:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int64:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint64:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint64:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ elements := make([]Int8, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = Int8Array{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Int8:
+ if value == nil {
+ *dst = Int8Array{Status: Null}
+ } else if len(value) == 0 {
+ *dst = Int8Array{Status: Present}
+ } else {
+ *dst = Int8Array{
+ 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 = Int8Array{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for Int8Array", src)
+ }
+ if elementsLength == 0 {
+ *dst = Int8Array{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 Int8Array", src)
+ }
+
+ *dst = Int8Array{
+ Elements: make([]Int8, 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([]Int8, 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 Int8Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *Int8Array) 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 Int8Array")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in Int8Array", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst Int8Array) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int8Array) 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 *[]int16:
+ *v = make([]int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int16:
+ *v = make([]*int16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint16:
+ *v = make([]uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint16:
+ *v = make([]*uint16, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int32:
+ *v = make([]int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int32:
+ *v = make([]*int32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint32:
+ *v = make([]uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint32:
+ *v = make([]*uint32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int64:
+ *v = make([]int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int64:
+ *v = make([]*int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint64:
+ *v = make([]uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint64:
+ *v = make([]*uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int:
+ *v = make([]int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int:
+ *v = make([]*int, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint:
+ *v = make([]uint, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint:
+ *v = make([]*uint, 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 *Int8Array) 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 Int8Array")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from Int8Array")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *Int8Array) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8Array{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Int8
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Int8, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Int8
+ 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 = Int8Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *Int8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8Array{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = Int8Array{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Int8, 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 = Int8Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src Int8Array) 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 Int8Array) 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("int8"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "int8")
+ }
+
+ 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 *Int8Array) 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 Int8Array) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/int8range.go b/vendor/github.com/jackc/pgtype/int8range.go
new file mode 100644
index 000000000..71369373f
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/int8range.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Int8range struct {
+ Lower Int8
+ Upper Int8
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Int8range) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Int8range{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Int8range:
+ *dst = value
+ case *Int8range:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Int8range", src)
+ }
+
+ return nil
+}
+
+func (dst Int8range) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Int8range) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Int8range) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8range{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Int8range{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Int8range) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Int8range{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Int8range{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Int8range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Int8range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Int8range) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Int8range{Status: Null}
+ return 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 Int8range) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/interval.go b/vendor/github.com/jackc/pgtype/interval.go
new file mode 100644
index 000000000..b01fbb7cb
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/interval.go
@@ -0,0 +1,257 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+const (
+ microsecondsPerSecond = 1000000
+ microsecondsPerMinute = 60 * microsecondsPerSecond
+ microsecondsPerHour = 60 * microsecondsPerMinute
+ microsecondsPerDay = 24 * microsecondsPerHour
+ microsecondsPerMonth = 30 * microsecondsPerDay
+)
+
+type Interval struct {
+ Microseconds int64
+ Days int32
+ Months int32
+ Status Status
+}
+
+func (dst *Interval) Set(src interface{}) error {
+ if src == nil {
+ *dst = Interval{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case time.Duration:
+ *dst = Interval{Microseconds: int64(value) / 1000, Status: Present}
+ default:
+ if originalSrc, ok := underlyingPtrType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Interval", value)
+ }
+
+ return nil
+}
+
+func (dst Interval) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Interval) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *time.Duration:
+ us := int64(src.Months)*microsecondsPerMonth + int64(src.Days)*microsecondsPerDay + src.Microseconds
+ *v = time.Duration(us) * time.Microsecond
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Interval) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Interval{Status: Null}
+ return nil
+ }
+
+ var microseconds int64
+ var days int32
+ var months int32
+
+ parts := strings.Split(string(src), " ")
+
+ for i := 0; i < len(parts)-1; i += 2 {
+ scalar, err := strconv.ParseInt(parts[i], 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad interval format")
+ }
+
+ switch parts[i+1] {
+ case "year", "years":
+ months += int32(scalar * 12)
+ case "mon", "mons":
+ months += int32(scalar)
+ case "day", "days":
+ days = int32(scalar)
+ }
+ }
+
+ if len(parts)%2 == 1 {
+ timeParts := strings.SplitN(parts[len(parts)-1], ":", 3)
+ if len(timeParts) != 3 {
+ return fmt.Errorf("bad interval format")
+ }
+
+ var negative bool
+ if timeParts[0][0] == '-' {
+ negative = true
+ timeParts[0] = timeParts[0][1:]
+ }
+
+ hours, err := strconv.ParseInt(timeParts[0], 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad interval hour format: %s", timeParts[0])
+ }
+
+ minutes, err := strconv.ParseInt(timeParts[1], 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad interval minute format: %s", timeParts[1])
+ }
+
+ secondParts := strings.SplitN(timeParts[2], ".", 2)
+
+ seconds, err := strconv.ParseInt(secondParts[0], 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad interval second format: %s", secondParts[0])
+ }
+
+ var uSeconds int64
+ if len(secondParts) == 2 {
+ uSeconds, err = strconv.ParseInt(secondParts[1], 10, 64)
+ if err != nil {
+ return fmt.Errorf("bad interval decimal format: %s", secondParts[1])
+ }
+
+ for i := 0; i < 6-len(secondParts[1]); i++ {
+ uSeconds *= 10
+ }
+ }
+
+ microseconds = hours * microsecondsPerHour
+ microseconds += minutes * microsecondsPerMinute
+ microseconds += seconds * microsecondsPerSecond
+ microseconds += uSeconds
+
+ if negative {
+ microseconds = -microseconds
+ }
+ }
+
+ *dst = Interval{Months: months, Days: days, Microseconds: microseconds, Status: Present}
+ return nil
+}
+
+func (dst *Interval) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Interval{Status: Null}
+ return nil
+ }
+
+ if len(src) != 16 {
+ return fmt.Errorf("Received an invalid size for a interval: %d", len(src))
+ }
+
+ microseconds := int64(binary.BigEndian.Uint64(src))
+ days := int32(binary.BigEndian.Uint32(src[8:]))
+ months := int32(binary.BigEndian.Uint32(src[12:]))
+
+ *dst = Interval{Microseconds: microseconds, Days: days, Months: months, Status: Present}
+ return nil
+}
+
+func (src Interval) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.Months != 0 {
+ buf = append(buf, strconv.FormatInt(int64(src.Months), 10)...)
+ buf = append(buf, " mon "...)
+ }
+
+ if src.Days != 0 {
+ buf = append(buf, strconv.FormatInt(int64(src.Days), 10)...)
+ buf = append(buf, " day "...)
+ }
+
+ absMicroseconds := src.Microseconds
+ if absMicroseconds < 0 {
+ absMicroseconds = -absMicroseconds
+ buf = append(buf, '-')
+ }
+
+ hours := absMicroseconds / microsecondsPerHour
+ minutes := (absMicroseconds % microsecondsPerHour) / microsecondsPerMinute
+ seconds := (absMicroseconds % microsecondsPerMinute) / microsecondsPerSecond
+ microseconds := absMicroseconds % microsecondsPerSecond
+
+ timeStr := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, microseconds)
+ return append(buf, timeStr...), nil
+}
+
+// EncodeBinary encodes src into w.
+func (src Interval) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendInt64(buf, src.Microseconds)
+ buf = pgio.AppendInt32(buf, src.Days)
+ return pgio.AppendInt32(buf, src.Months), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Interval) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Interval{Status: Null}
+ return 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 Interval) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/json.go b/vendor/github.com/jackc/pgtype/json.go
new file mode 100644
index 000000000..32bef5e76
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/json.go
@@ -0,0 +1,205 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "errors"
+ "fmt"
+)
+
+type JSON struct {
+ Bytes []byte
+ Status Status
+}
+
+func (dst *JSON) Set(src interface{}) error {
+ if src == nil {
+ *dst = JSON{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case string:
+ *dst = JSON{Bytes: []byte(value), Status: Present}
+ case *string:
+ if value == nil {
+ *dst = JSON{Status: Null}
+ } else {
+ *dst = JSON{Bytes: []byte(*value), Status: Present}
+ }
+ case []byte:
+ if value == nil {
+ *dst = JSON{Status: Null}
+ } else {
+ *dst = JSON{Bytes: value, Status: Present}
+ }
+ // Encode* methods are defined on *JSON. If JSON is passed directly then the
+ // struct itself would be encoded instead of Bytes. This is clearly a footgun
+ // so detect and return an error. See https://github.com/jackc/pgx/issues/350.
+ case JSON:
+ return errors.New("use pointer to pgtype.JSON instead of value")
+ // Same as above but for JSONB (because they share implementation)
+ case JSONB:
+ return errors.New("use pointer to pgtype.JSONB instead of value")
+
+ default:
+ buf, err := json.Marshal(value)
+ if err != nil {
+ return err
+ }
+ *dst = JSON{Bytes: buf, Status: Present}
+ }
+
+ return nil
+}
+
+func (dst JSON) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ var i interface{}
+ err := json.Unmarshal(dst.Bytes, &i)
+ if err != nil {
+ return dst
+ }
+ return i
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *JSON) AssignTo(dst interface{}) error {
+ switch v := dst.(type) {
+ case *string:
+ if src.Status == Present {
+ *v = string(src.Bytes)
+ } else {
+ return fmt.Errorf("cannot assign non-present status to %T", dst)
+ }
+ case **string:
+ if src.Status == Present {
+ s := string(src.Bytes)
+ *v = &s
+ return nil
+ } else {
+ *v = nil
+ return nil
+ }
+ case *[]byte:
+ if src.Status != Present {
+ *v = nil
+ } else {
+ buf := make([]byte, len(src.Bytes))
+ copy(buf, src.Bytes)
+ *v = buf
+ }
+ default:
+ data := src.Bytes
+ if data == nil || src.Status != Present {
+ data = []byte("null")
+ }
+
+ return json.Unmarshal(data, dst)
+ }
+
+ return nil
+}
+
+func (JSON) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *JSON) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = JSON{Status: Null}
+ return nil
+ }
+
+ *dst = JSON{Bytes: src, Status: Present}
+ return nil
+}
+
+func (dst *JSON) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return dst.DecodeText(ci, src)
+}
+
+func (JSON) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src JSON) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.Bytes...), nil
+}
+
+func (src JSON) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return src.EncodeText(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *JSON) Scan(src interface{}) error {
+ if src == nil {
+ *dst = JSON{Status: Null}
+ return 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 JSON) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.Bytes, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src JSON) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ return src.Bytes, nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
+
+func (dst *JSON) UnmarshalJSON(b []byte) error {
+ if b == nil || string(b) == "null" {
+ *dst = JSON{Status: Null}
+ } else {
+ *dst = JSON{Bytes: b, Status: Present}
+ }
+ return nil
+
+}
diff --git a/vendor/github.com/jackc/pgtype/jsonb.go b/vendor/github.com/jackc/pgtype/jsonb.go
new file mode 100644
index 000000000..c9dafc939
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/jsonb.go
@@ -0,0 +1,85 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+)
+
+type JSONB JSON
+
+func (dst *JSONB) Set(src interface{}) error {
+ return (*JSON)(dst).Set(src)
+}
+
+func (dst JSONB) Get() interface{} {
+ return (JSON)(dst).Get()
+}
+
+func (src *JSONB) AssignTo(dst interface{}) error {
+ return (*JSON)(src).AssignTo(dst)
+}
+
+func (JSONB) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *JSONB) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*JSON)(dst).DecodeText(ci, src)
+}
+
+func (dst *JSONB) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = JSONB{Status: Null}
+ return nil
+ }
+
+ if len(src) == 0 {
+ return fmt.Errorf("jsonb too short")
+ }
+
+ if src[0] != 1 {
+ return fmt.Errorf("unknown jsonb version number %d", src[0])
+ }
+
+ *dst = JSONB{Bytes: src[1:], Status: Present}
+ return nil
+
+}
+
+func (JSONB) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src JSONB) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (JSON)(src).EncodeText(ci, buf)
+}
+
+func (src JSONB) 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.Bytes...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *JSONB) Scan(src interface{}) error {
+ return (*JSON)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src JSONB) Value() (driver.Value, error) {
+ return (JSON)(src).Value()
+}
+
+func (src JSONB) MarshalJSON() ([]byte, error) {
+ return (JSON)(src).MarshalJSON()
+}
+
+func (dst *JSONB) UnmarshalJSON(b []byte) error {
+ return (*JSON)(dst).UnmarshalJSON(b)
+}
diff --git a/vendor/github.com/jackc/pgtype/jsonb_array.go b/vendor/github.com/jackc/pgtype/jsonb_array.go
new file mode 100644
index 000000000..c4b7cd3d8
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/jsonb_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type JSONBArray struct {
+ Elements []JSONB
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *JSONBArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = JSONBArray{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 = 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 [][]byte:
+ 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:
+ if value == nil {
+ *dst = JSONBArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = JSONBArray{Status: Present}
+ } else {
+ *dst = JSONBArray{
+ 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 = JSONBArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for JSONBArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = JSONBArray{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 JSONBArray", src)
+ }
+
+ *dst = JSONBArray{
+ Elements: make([]JSONB, 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([]JSONB, 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 JSONBArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *JSONBArray) 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 JSONBArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in JSONBArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst JSONBArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *JSONBArray) 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
+
+ }
+ }
+
+ // 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 *JSONBArray) 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 JSONBArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from JSONBArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *JSONBArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = JSONBArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []JSONB
+
+ if len(uta.Elements) > 0 {
+ elements = make([]JSONB, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem JSONB
+ 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 = JSONBArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *JSONBArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = JSONBArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = JSONBArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]JSONB, 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 = JSONBArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src JSONBArray) 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 JSONBArray) 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("jsonb"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "jsonb")
+ }
+
+ 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 *JSONBArray) 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 JSONBArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/line.go b/vendor/github.com/jackc/pgtype/line.go
new file mode 100644
index 000000000..3564b1748
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/line.go
@@ -0,0 +1,148 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Line struct {
+ A, B, C float64
+ Status Status
+}
+
+func (dst *Line) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Line", src)
+}
+
+func (dst Line) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Line) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Line) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Line{Status: Null}
+ return nil
+ }
+
+ if len(src) < 7 {
+ return fmt.Errorf("invalid length for Line: %v", len(src))
+ }
+
+ parts := strings.SplitN(string(src[1:len(src)-1]), ",", 3)
+ if len(parts) < 3 {
+ return fmt.Errorf("invalid format for line")
+ }
+
+ a, err := strconv.ParseFloat(parts[0], 64)
+ if err != nil {
+ return err
+ }
+
+ b, err := strconv.ParseFloat(parts[1], 64)
+ if err != nil {
+ return err
+ }
+
+ c, err := strconv.ParseFloat(parts[2], 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Line{A: a, B: b, C: c, Status: Present}
+ return nil
+}
+
+func (dst *Line) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Line{Status: Null}
+ return nil
+ }
+
+ if len(src) != 24 {
+ return fmt.Errorf("invalid length for Line: %v", len(src))
+ }
+
+ a := binary.BigEndian.Uint64(src)
+ b := binary.BigEndian.Uint64(src[8:])
+ c := binary.BigEndian.Uint64(src[16:])
+
+ *dst = Line{
+ A: math.Float64frombits(a),
+ B: math.Float64frombits(b),
+ C: math.Float64frombits(c),
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Line) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, fmt.Sprintf(`{%s,%s,%s}`,
+ strconv.FormatFloat(src.A, 'f', -1, 64),
+ strconv.FormatFloat(src.B, 'f', -1, 64),
+ strconv.FormatFloat(src.C, 'f', -1, 64),
+ )...)
+
+ return buf, nil
+}
+
+func (src Line) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.A))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.B))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.C))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Line) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Line{Status: Null}
+ return 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 Line) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/lseg.go b/vendor/github.com/jackc/pgtype/lseg.go
new file mode 100644
index 000000000..5c4babb69
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/lseg.go
@@ -0,0 +1,165 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Lseg struct {
+ P [2]Vec2
+ Status Status
+}
+
+func (dst *Lseg) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Lseg", src)
+}
+
+func (dst Lseg) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Lseg) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Lseg) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Lseg{Status: Null}
+ return nil
+ }
+
+ if len(src) < 11 {
+ return fmt.Errorf("invalid length for Lseg: %v", len(src))
+ }
+
+ str := string(src[2:])
+
+ var end int
+ end = strings.IndexByte(str, ',')
+
+ x1, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1:]
+ end = strings.IndexByte(str, ')')
+
+ y1, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+3:]
+ end = strings.IndexByte(str, ',')
+
+ x2, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1 : len(str)-2]
+
+ y2, err := strconv.ParseFloat(str, 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Lseg{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present}
+ return nil
+}
+
+func (dst *Lseg) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Lseg{Status: Null}
+ return nil
+ }
+
+ if len(src) != 32 {
+ return fmt.Errorf("invalid length for Lseg: %v", len(src))
+ }
+
+ x1 := binary.BigEndian.Uint64(src)
+ y1 := binary.BigEndian.Uint64(src[8:])
+ x2 := binary.BigEndian.Uint64(src[16:])
+ y2 := binary.BigEndian.Uint64(src[24:])
+
+ *dst = Lseg{
+ P: [2]Vec2{
+ {math.Float64frombits(x1), math.Float64frombits(y1)},
+ {math.Float64frombits(x2), math.Float64frombits(y2)},
+ },
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Lseg) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`,
+ strconv.FormatFloat(src.P[0].X, '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].Y, 'f', -1, 64),
+ )...)
+
+ return buf, nil
+}
+
+func (src Lseg) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Lseg) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Lseg{Status: Null}
+ return 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 Lseg) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/macaddr.go b/vendor/github.com/jackc/pgtype/macaddr.go
new file mode 100644
index 000000000..1d3cfe7b1
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/macaddr.go
@@ -0,0 +1,173 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "net"
+)
+
+type Macaddr struct {
+ Addr net.HardwareAddr
+ Status Status
+}
+
+func (dst *Macaddr) Set(src interface{}) error {
+ if src == nil {
+ *dst = Macaddr{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case net.HardwareAddr:
+ addr := make(net.HardwareAddr, len(value))
+ copy(addr, value)
+ *dst = Macaddr{Addr: addr, Status: Present}
+ case string:
+ addr, err := net.ParseMAC(value)
+ if err != nil {
+ return err
+ }
+ *dst = Macaddr{Addr: addr, Status: Present}
+ case *net.HardwareAddr:
+ if value == nil {
+ *dst = Macaddr{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Macaddr{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingPtrType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Macaddr", value)
+ }
+
+ return nil
+}
+
+func (dst Macaddr) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Addr
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Macaddr) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *net.HardwareAddr:
+ *v = make(net.HardwareAddr, len(src.Addr))
+ copy(*v, src.Addr)
+ return nil
+ case *string:
+ *v = src.Addr.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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Macaddr) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Macaddr{Status: Null}
+ return nil
+ }
+
+ addr, err := net.ParseMAC(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Macaddr{Addr: addr, Status: Present}
+ return nil
+}
+
+func (dst *Macaddr) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Macaddr{Status: Null}
+ return nil
+ }
+
+ if len(src) != 6 {
+ return fmt.Errorf("Received an invalid size for a macaddr: %d", len(src))
+ }
+
+ addr := make(net.HardwareAddr, 6)
+ copy(addr, src)
+
+ *dst = Macaddr{Addr: addr, Status: Present}
+
+ return nil
+}
+
+func (src Macaddr) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.Addr.String()...), nil
+}
+
+// EncodeBinary encodes src into w.
+func (src Macaddr) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.Addr...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Macaddr) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Macaddr{Status: Null}
+ return 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 Macaddr) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/macaddr_array.go b/vendor/github.com/jackc/pgtype/macaddr_array.go
new file mode 100644
index 000000000..bdb1f2034
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/macaddr_array.go
@@ -0,0 +1,518 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "net"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type MacaddrArray struct {
+ Elements []Macaddr
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *MacaddrArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = MacaddrArray{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 []net.HardwareAddr:
+ if value == nil {
+ *dst = MacaddrArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = MacaddrArray{Status: Present}
+ } else {
+ elements := make([]Macaddr, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = MacaddrArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*net.HardwareAddr:
+ if value == nil {
+ *dst = MacaddrArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = MacaddrArray{Status: Present}
+ } else {
+ elements := make([]Macaddr, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = MacaddrArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Macaddr:
+ if value == nil {
+ *dst = MacaddrArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = MacaddrArray{Status: Present}
+ } else {
+ *dst = MacaddrArray{
+ 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 = MacaddrArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for MacaddrArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = MacaddrArray{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 MacaddrArray", src)
+ }
+
+ *dst = MacaddrArray{
+ Elements: make([]Macaddr, 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([]Macaddr, 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 MacaddrArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *MacaddrArray) 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 MacaddrArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in MacaddrArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst MacaddrArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *MacaddrArray) 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 *[]net.HardwareAddr:
+ *v = make([]net.HardwareAddr, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*net.HardwareAddr:
+ *v = make([]*net.HardwareAddr, 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 *MacaddrArray) 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 MacaddrArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from MacaddrArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *MacaddrArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = MacaddrArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Macaddr
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Macaddr, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Macaddr
+ 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 = MacaddrArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *MacaddrArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = MacaddrArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = MacaddrArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Macaddr, 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 = MacaddrArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src MacaddrArray) 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 MacaddrArray) 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("macaddr"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "macaddr")
+ }
+
+ 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 *MacaddrArray) 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 MacaddrArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/name.go b/vendor/github.com/jackc/pgtype/name.go
new file mode 100644
index 000000000..7ce8d25e9
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/name.go
@@ -0,0 +1,58 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// Name is a type used for PostgreSQL's special 63-byte
+// name data type, used for identifiers like table names.
+// The pg_class.relname column is a good example of where the
+// name data type is used.
+//
+// Note that the underlying Go data type of pgx.Name is string,
+// so there is no way to enforce the 63-byte length. Inputting
+// a longer name into PostgreSQL will result in silent truncation
+// to 63 bytes.
+//
+// Also, if you have custom-compiled PostgreSQL and set
+// NAMEDATALEN to a different value, obviously that number of
+// bytes applies, rather than the default 63.
+type Name Text
+
+func (dst *Name) Set(src interface{}) error {
+ return (*Text)(dst).Set(src)
+}
+
+func (dst Name) Get() interface{} {
+ return (Text)(dst).Get()
+}
+
+func (src *Name) AssignTo(dst interface{}) error {
+ return (*Text)(src).AssignTo(dst)
+}
+
+func (dst *Name) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeText(ci, src)
+}
+
+func (dst *Name) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeBinary(ci, src)
+}
+
+func (src Name) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeText(ci, buf)
+}
+
+func (src Name) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Name) Scan(src interface{}) error {
+ return (*Text)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Name) Value() (driver.Value, error) {
+ return (Text)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/numeric.go b/vendor/github.com/jackc/pgtype/numeric.go
new file mode 100644
index 000000000..a7efa704c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/numeric.go
@@ -0,0 +1,716 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "math/big"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+// PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
+const nbase = 10000
+
+const (
+ pgNumericNaN = 0x00000000c0000000
+ pgNumericNaNSign = 0xc000
+)
+
+var big0 *big.Int = big.NewInt(0)
+var big1 *big.Int = big.NewInt(1)
+var big10 *big.Int = big.NewInt(10)
+var big100 *big.Int = big.NewInt(100)
+var big1000 *big.Int = big.NewInt(1000)
+
+var bigMaxInt8 *big.Int = big.NewInt(math.MaxInt8)
+var bigMinInt8 *big.Int = big.NewInt(math.MinInt8)
+var bigMaxInt16 *big.Int = big.NewInt(math.MaxInt16)
+var bigMinInt16 *big.Int = big.NewInt(math.MinInt16)
+var bigMaxInt32 *big.Int = big.NewInt(math.MaxInt32)
+var bigMinInt32 *big.Int = big.NewInt(math.MinInt32)
+var bigMaxInt64 *big.Int = big.NewInt(math.MaxInt64)
+var bigMinInt64 *big.Int = big.NewInt(math.MinInt64)
+var bigMaxInt *big.Int = big.NewInt(int64(maxInt))
+var bigMinInt *big.Int = big.NewInt(int64(minInt))
+
+var bigMaxUint8 *big.Int = big.NewInt(math.MaxUint8)
+var bigMaxUint16 *big.Int = big.NewInt(math.MaxUint16)
+var bigMaxUint32 *big.Int = big.NewInt(math.MaxUint32)
+var bigMaxUint64 *big.Int = (&big.Int{}).SetUint64(uint64(math.MaxUint64))
+var bigMaxUint *big.Int = (&big.Int{}).SetUint64(uint64(maxUint))
+
+var bigNBase *big.Int = big.NewInt(nbase)
+var bigNBaseX2 *big.Int = big.NewInt(nbase * nbase)
+var bigNBaseX3 *big.Int = big.NewInt(nbase * nbase * nbase)
+var bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase)
+
+type Numeric struct {
+ Int *big.Int
+ Exp int32
+ Status Status
+ NaN bool
+}
+
+func (dst *Numeric) Set(src interface{}) error {
+ if src == nil {
+ *dst = Numeric{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case float32:
+ if math.IsNaN(float64(value)) {
+ *dst = Numeric{Status: Present, NaN: true}
+ return nil
+ }
+ num, exp, err := parseNumericString(strconv.FormatFloat(float64(value), 'f', -1, 64))
+ if err != nil {
+ return err
+ }
+ *dst = Numeric{Int: num, Exp: exp, Status: Present}
+ case float64:
+ if math.IsNaN(value) {
+ *dst = Numeric{Status: Present, NaN: true}
+ return nil
+ }
+ num, exp, err := parseNumericString(strconv.FormatFloat(value, 'f', -1, 64))
+ if err != nil {
+ return err
+ }
+ *dst = Numeric{Int: num, Exp: exp, Status: Present}
+ case int8:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case uint8:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case int16:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case uint16:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case int32:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case uint32:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case int64:
+ *dst = Numeric{Int: big.NewInt(value), Status: Present}
+ case uint64:
+ *dst = Numeric{Int: (&big.Int{}).SetUint64(value), Status: Present}
+ case int:
+ *dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
+ case uint:
+ *dst = Numeric{Int: (&big.Int{}).SetUint64(uint64(value)), Status: Present}
+ case string:
+ num, exp, err := parseNumericString(value)
+ if err != nil {
+ return err
+ }
+ *dst = Numeric{Int: num, Exp: exp, Status: Present}
+ case *float64:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *float32:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int8:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint8:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int16:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint16:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int32:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint32:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int64:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint64:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *int:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *uint:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case *string:
+ if value == nil {
+ *dst = Numeric{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Numeric", value)
+ }
+
+ return nil
+}
+
+func (dst Numeric) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Numeric) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *float32:
+ f, err := src.toFloat64()
+ if err != nil {
+ return err
+ }
+ return float64AssignTo(f, src.Status, dst)
+ case *float64:
+ f, err := src.toFloat64()
+ if err != nil {
+ return err
+ }
+ return float64AssignTo(f, src.Status, dst)
+ case *int:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(bigMaxInt) > 0 {
+ return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
+ }
+ if normalizedInt.Cmp(bigMinInt) < 0 {
+ return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
+ }
+ *v = int(normalizedInt.Int64())
+ case *int8:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(bigMaxInt8) > 0 {
+ return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
+ }
+ if normalizedInt.Cmp(bigMinInt8) < 0 {
+ return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
+ }
+ *v = int8(normalizedInt.Int64())
+ case *int16:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(bigMaxInt16) > 0 {
+ return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
+ }
+ if normalizedInt.Cmp(bigMinInt16) < 0 {
+ return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
+ }
+ *v = int16(normalizedInt.Int64())
+ case *int32:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(bigMaxInt32) > 0 {
+ return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
+ }
+ if normalizedInt.Cmp(bigMinInt32) < 0 {
+ return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
+ }
+ *v = int32(normalizedInt.Int64())
+ case *int64:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(bigMaxInt64) > 0 {
+ return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
+ }
+ if normalizedInt.Cmp(bigMinInt64) < 0 {
+ return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
+ }
+ *v = normalizedInt.Int64()
+ case *uint:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(big0) < 0 {
+ return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
+ } else if normalizedInt.Cmp(bigMaxUint) > 0 {
+ return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
+ }
+ *v = uint(normalizedInt.Uint64())
+ case *uint8:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(big0) < 0 {
+ return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
+ } else if normalizedInt.Cmp(bigMaxUint8) > 0 {
+ return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
+ }
+ *v = uint8(normalizedInt.Uint64())
+ case *uint16:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(big0) < 0 {
+ return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
+ } else if normalizedInt.Cmp(bigMaxUint16) > 0 {
+ return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
+ }
+ *v = uint16(normalizedInt.Uint64())
+ case *uint32:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(big0) < 0 {
+ return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
+ } else if normalizedInt.Cmp(bigMaxUint32) > 0 {
+ return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
+ }
+ *v = uint32(normalizedInt.Uint64())
+ case *uint64:
+ normalizedInt, err := src.toBigInt()
+ if err != nil {
+ return err
+ }
+ if normalizedInt.Cmp(big0) < 0 {
+ return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
+ } else if normalizedInt.Cmp(bigMaxUint64) > 0 {
+ return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
+ }
+ *v = normalizedInt.Uint64()
+ 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 nil
+}
+
+func (dst *Numeric) toBigInt() (*big.Int, error) {
+ if dst.Exp == 0 {
+ return dst.Int, nil
+ }
+
+ num := &big.Int{}
+ num.Set(dst.Int)
+ if dst.Exp > 0 {
+ mul := &big.Int{}
+ mul.Exp(big10, big.NewInt(int64(dst.Exp)), nil)
+ num.Mul(num, mul)
+ return num, nil
+ }
+
+ div := &big.Int{}
+ div.Exp(big10, big.NewInt(int64(-dst.Exp)), nil)
+ remainder := &big.Int{}
+ num.DivMod(num, div, remainder)
+ if remainder.Cmp(big0) != 0 {
+ return nil, fmt.Errorf("cannot convert %v to integer", dst)
+ }
+ return num, nil
+}
+
+func (src *Numeric) toFloat64() (float64, error) {
+ if src.NaN {
+ return math.NaN(), nil
+ }
+
+ buf := make([]byte, 0, 32)
+
+ buf = append(buf, src.Int.String()...)
+ buf = append(buf, 'e')
+ buf = append(buf, strconv.FormatInt(int64(src.Exp), 10)...)
+
+ f, err := strconv.ParseFloat(string(buf), 64)
+ if err != nil {
+ return 0, err
+ }
+ return f, nil
+}
+
+func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Numeric{Status: Null}
+ return nil
+ }
+
+ if string(src) == "NaN" {
+ *dst = Numeric{Status: Present, NaN: true}
+ return nil
+ }
+
+ num, exp, err := parseNumericString(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Numeric{Int: num, Exp: exp, Status: Present}
+ return nil
+}
+
+func parseNumericString(str string) (n *big.Int, exp int32, err error) {
+ parts := strings.SplitN(str, ".", 2)
+ digits := strings.Join(parts, "")
+
+ if len(parts) > 1 {
+ exp = int32(-len(parts[1]))
+ } else {
+ for len(digits) > 1 && digits[len(digits)-1] == '0' && digits[len(digits)-2] != '-' {
+ digits = digits[:len(digits)-1]
+ exp++
+ }
+ }
+
+ accum := &big.Int{}
+ if _, ok := accum.SetString(digits, 10); !ok {
+ return nil, 0, fmt.Errorf("%s is not a number", str)
+ }
+
+ return accum, exp, nil
+}
+
+func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Numeric{Status: Null}
+ return nil
+ }
+
+ if len(src) < 8 {
+ return fmt.Errorf("numeric incomplete %v", src)
+ }
+
+ rp := 0
+ ndigits := int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ weight := int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ sign := uint16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ dscale := int16(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+
+ if sign == pgNumericNaNSign {
+ *dst = Numeric{Status: Present, NaN: true}
+ return nil
+ }
+
+ if ndigits == 0 {
+ *dst = Numeric{Int: big.NewInt(0), Status: Present}
+ return nil
+ }
+
+ if len(src[rp:]) < int(ndigits)*2 {
+ return fmt.Errorf("numeric incomplete %v", src)
+ }
+
+ accum := &big.Int{}
+
+ for i := 0; i < int(ndigits+3)/4; i++ {
+ int64accum, bytesRead, digitsRead := nbaseDigitsToInt64(src[rp:])
+ rp += bytesRead
+
+ if i > 0 {
+ var mul *big.Int
+ switch digitsRead {
+ case 1:
+ mul = bigNBase
+ case 2:
+ mul = bigNBaseX2
+ case 3:
+ mul = bigNBaseX3
+ case 4:
+ mul = bigNBaseX4
+ default:
+ return fmt.Errorf("invalid digitsRead: %d (this can't happen)", digitsRead)
+ }
+ accum.Mul(accum, mul)
+ }
+
+ accum.Add(accum, big.NewInt(int64accum))
+ }
+
+ exp := (int32(weight) - int32(ndigits) + 1) * 4
+
+ if dscale > 0 {
+ fracNBaseDigits := ndigits - weight - 1
+ fracDecimalDigits := fracNBaseDigits * 4
+
+ if dscale > fracDecimalDigits {
+ multCount := int(dscale - fracDecimalDigits)
+ for i := 0; i < multCount; i++ {
+ accum.Mul(accum, big10)
+ exp--
+ }
+ } else if dscale < fracDecimalDigits {
+ divCount := int(fracDecimalDigits - dscale)
+ for i := 0; i < divCount; i++ {
+ accum.Div(accum, big10)
+ exp++
+ }
+ }
+ }
+
+ reduced := &big.Int{}
+ remainder := &big.Int{}
+ if exp >= 0 {
+ for {
+ reduced.DivMod(accum, big10, remainder)
+ if remainder.Cmp(big0) != 0 {
+ break
+ }
+ accum.Set(reduced)
+ exp++
+ }
+ }
+
+ if sign != 0 {
+ accum.Neg(accum)
+ }
+
+ *dst = Numeric{Int: accum, Exp: exp, Status: Present}
+
+ return nil
+
+}
+
+func nbaseDigitsToInt64(src []byte) (accum int64, bytesRead, digitsRead int) {
+ digits := len(src) / 2
+ if digits > 4 {
+ digits = 4
+ }
+
+ rp := 0
+
+ for i := 0; i < digits; i++ {
+ if i > 0 {
+ accum *= nbase
+ }
+ accum += int64(binary.BigEndian.Uint16(src[rp:]))
+ rp += 2
+ }
+
+ return accum, rp, digits
+}
+
+func (src Numeric) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.NaN {
+ buf = append(buf, "NaN"...)
+ return buf, nil
+ }
+
+ buf = append(buf, src.Int.String()...)
+ buf = append(buf, 'e')
+ buf = append(buf, strconv.FormatInt(int64(src.Exp), 10)...)
+ return buf, nil
+}
+
+func (src Numeric) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.NaN {
+ buf = pgio.AppendUint64(buf, pgNumericNaN)
+ return buf, nil
+ }
+
+ var sign int16
+ if src.Int.Cmp(big0) < 0 {
+ sign = 16384
+ }
+
+ absInt := &big.Int{}
+ wholePart := &big.Int{}
+ fracPart := &big.Int{}
+ remainder := &big.Int{}
+ absInt.Abs(src.Int)
+
+ // Normalize absInt and exp to where exp is always a multiple of 4. This makes
+ // converting to 16-bit base 10,000 digits easier.
+ var exp int32
+ switch src.Exp % 4 {
+ case 1, -3:
+ exp = src.Exp - 1
+ absInt.Mul(absInt, big10)
+ case 2, -2:
+ exp = src.Exp - 2
+ absInt.Mul(absInt, big100)
+ case 3, -1:
+ exp = src.Exp - 3
+ absInt.Mul(absInt, big1000)
+ default:
+ exp = src.Exp
+ }
+
+ if exp < 0 {
+ divisor := &big.Int{}
+ divisor.Exp(big10, big.NewInt(int64(-exp)), nil)
+ wholePart.DivMod(absInt, divisor, fracPart)
+ fracPart.Add(fracPart, divisor)
+ } else {
+ wholePart = absInt
+ }
+
+ var wholeDigits, fracDigits []int16
+
+ for wholePart.Cmp(big0) != 0 {
+ wholePart.DivMod(wholePart, bigNBase, remainder)
+ wholeDigits = append(wholeDigits, int16(remainder.Int64()))
+ }
+
+ if fracPart.Cmp(big0) != 0 {
+ for fracPart.Cmp(big1) != 0 {
+ fracPart.DivMod(fracPart, bigNBase, remainder)
+ fracDigits = append(fracDigits, int16(remainder.Int64()))
+ }
+ }
+
+ buf = pgio.AppendInt16(buf, int16(len(wholeDigits)+len(fracDigits)))
+
+ var weight int16
+ if len(wholeDigits) > 0 {
+ weight = int16(len(wholeDigits) - 1)
+ if exp > 0 {
+ weight += int16(exp / 4)
+ }
+ } else {
+ weight = int16(exp/4) - 1 + int16(len(fracDigits))
+ }
+ buf = pgio.AppendInt16(buf, weight)
+
+ buf = pgio.AppendInt16(buf, sign)
+
+ var dscale int16
+ if src.Exp < 0 {
+ dscale = int16(-src.Exp)
+ }
+ buf = pgio.AppendInt16(buf, dscale)
+
+ for i := len(wholeDigits) - 1; i >= 0; i-- {
+ buf = pgio.AppendInt16(buf, wholeDigits[i])
+ }
+
+ for i := len(fracDigits) - 1; i >= 0; i-- {
+ buf = pgio.AppendInt16(buf, fracDigits[i])
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Numeric) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Numeric{Status: Null}
+ return 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 Numeric) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ buf, err := src.EncodeText(nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return string(buf), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/numeric_array.go b/vendor/github.com/jackc/pgtype/numeric_array.go
new file mode 100644
index 000000000..31899dec9
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/numeric_array.go
@@ -0,0 +1,685 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type NumericArray struct {
+ Elements []Numeric
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *NumericArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = NumericArray{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 []float32:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*float32:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []float64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*float64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []int64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*int64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []uint64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*uint64:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ elements := make([]Numeric, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = NumericArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Numeric:
+ if value == nil {
+ *dst = NumericArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = NumericArray{Status: Present}
+ } else {
+ *dst = NumericArray{
+ 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 = NumericArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for NumericArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = NumericArray{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 NumericArray", src)
+ }
+
+ *dst = NumericArray{
+ Elements: make([]Numeric, 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([]Numeric, 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 NumericArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *NumericArray) 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 NumericArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in NumericArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst NumericArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *NumericArray) 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 *[]float32:
+ *v = make([]float32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*float32:
+ *v = make([]*float32, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]float64:
+ *v = make([]float64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*float64:
+ *v = make([]*float64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]int64:
+ *v = make([]int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*int64:
+ *v = make([]*int64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]uint64:
+ *v = make([]uint64, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*uint64:
+ *v = make([]*uint64, 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 *NumericArray) 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 NumericArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from NumericArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *NumericArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = NumericArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Numeric
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Numeric, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Numeric
+ 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 = NumericArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *NumericArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = NumericArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = NumericArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Numeric, 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 = NumericArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src NumericArray) 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 NumericArray) 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("numeric"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
+ }
+
+ 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 *NumericArray) 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 NumericArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/numrange.go b/vendor/github.com/jackc/pgtype/numrange.go
new file mode 100644
index 000000000..3d5951a24
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/numrange.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Numrange struct {
+ Lower Numeric
+ Upper Numeric
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Numrange) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Numrange{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Numrange:
+ *dst = value
+ case *Numrange:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Numrange", src)
+ }
+
+ return nil
+}
+
+func (dst Numrange) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Numrange) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Numrange) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Numrange{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Numrange{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Numrange) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Numrange{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Numrange{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Numrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Numrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Numrange) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Numrange{Status: Null}
+ return 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 Numrange) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/oid.go b/vendor/github.com/jackc/pgtype/oid.go
new file mode 100644
index 000000000..31677e894
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/oid.go
@@ -0,0 +1,81 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+// OID (Object Identifier Type) is, according to
+// https://www.postgresql.org/docs/current/static/datatype-oid.html, used
+// internally by PostgreSQL as a primary key for various system tables. It is
+// currently implemented as an unsigned four-byte integer. Its definition can be
+// found in src/include/postgres_ext.h in the PostgreSQL sources. Because it is
+// so frequently required to be in a NOT NULL condition OID cannot be NULL. To
+// allow for NULL OIDs use OIDValue.
+type OID uint32
+
+func (dst *OID) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ return fmt.Errorf("cannot decode nil into OID")
+ }
+
+ n, err := strconv.ParseUint(string(src), 10, 32)
+ if err != nil {
+ return err
+ }
+
+ *dst = OID(n)
+ return nil
+}
+
+func (dst *OID) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ return fmt.Errorf("cannot decode nil into OID")
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length: %v", len(src))
+ }
+
+ n := binary.BigEndian.Uint32(src)
+ *dst = OID(n)
+ return nil
+}
+
+func (src OID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return append(buf, strconv.FormatUint(uint64(src), 10)...), nil
+}
+
+func (src OID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return pgio.AppendUint32(buf, uint32(src)), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *OID) Scan(src interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan NULL into %T", src)
+ }
+
+ switch src := src.(type) {
+ case int64:
+ *dst = OID(src)
+ return nil
+ 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 OID) Value() (driver.Value, error) {
+ return int64(src), nil
+}
diff --git a/vendor/github.com/jackc/pgtype/oid_value.go b/vendor/github.com/jackc/pgtype/oid_value.go
new file mode 100644
index 000000000..5dc9136cb
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/oid_value.go
@@ -0,0 +1,55 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// OIDValue (Object Identifier Type) is, according to
+// https://www.postgresql.org/docs/current/static/datatype-OIDValue.html, used
+// internally by PostgreSQL as a primary key for various system tables. It is
+// currently implemented as an unsigned four-byte integer. Its definition can be
+// found in src/include/postgres_ext.h in the PostgreSQL sources.
+type OIDValue pguint32
+
+// Set converts from src to dst. Note that as OIDValue is not a general
+// number type Set does not do automatic type conversion as other number
+// types do.
+func (dst *OIDValue) Set(src interface{}) error {
+ return (*pguint32)(dst).Set(src)
+}
+
+func (dst OIDValue) Get() interface{} {
+ return (pguint32)(dst).Get()
+}
+
+// AssignTo assigns from src to dst. Note that as OIDValue is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *OIDValue) AssignTo(dst interface{}) error {
+ return (*pguint32)(src).AssignTo(dst)
+}
+
+func (dst *OIDValue) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeText(ci, src)
+}
+
+func (dst *OIDValue) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeBinary(ci, src)
+}
+
+func (src OIDValue) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeText(ci, buf)
+}
+
+func (src OIDValue) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *OIDValue) Scan(src interface{}) error {
+ return (*pguint32)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src OIDValue) Value() (driver.Value, error) {
+ return (pguint32)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/path.go b/vendor/github.com/jackc/pgtype/path.go
new file mode 100644
index 000000000..9f89969e0
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/path.go
@@ -0,0 +1,195 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Path struct {
+ P []Vec2
+ Closed bool
+ Status Status
+}
+
+func (dst *Path) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Path", src)
+}
+
+func (dst Path) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Path) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Path) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Path{Status: Null}
+ return nil
+ }
+
+ if len(src) < 7 {
+ return fmt.Errorf("invalid length for Path: %v", len(src))
+ }
+
+ closed := src[0] == '('
+ points := make([]Vec2, 0)
+
+ str := string(src[2:])
+
+ for {
+ end := strings.IndexByte(str, ',')
+ x, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1:]
+ end = strings.IndexByte(str, ')')
+
+ y, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ points = append(points, Vec2{x, y})
+
+ if end+3 < len(str) {
+ str = str[end+3:]
+ } else {
+ break
+ }
+ }
+
+ *dst = Path{P: points, Closed: closed, Status: Present}
+ return nil
+}
+
+func (dst *Path) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Path{Status: Null}
+ return nil
+ }
+
+ if len(src) < 5 {
+ return fmt.Errorf("invalid length for Path: %v", len(src))
+ }
+
+ closed := src[0] == 1
+ pointCount := int(binary.BigEndian.Uint32(src[1:]))
+
+ rp := 5
+
+ if 5+pointCount*16 != len(src) {
+ return fmt.Errorf("invalid length for Path with %d points: %v", pointCount, len(src))
+ }
+
+ points := make([]Vec2, pointCount)
+ for i := 0; i < len(points); i++ {
+ x := binary.BigEndian.Uint64(src[rp:])
+ rp += 8
+ y := binary.BigEndian.Uint64(src[rp:])
+ rp += 8
+ points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
+ }
+
+ *dst = Path{
+ P: points,
+ Closed: closed,
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Path) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var startByte, endByte byte
+ if src.Closed {
+ startByte = '('
+ endByte = ')'
+ } else {
+ startByte = '['
+ endByte = ']'
+ }
+ buf = append(buf, startByte)
+
+ for i, p := range src.P {
+ if i > 0 {
+ buf = append(buf, ',')
+ }
+ buf = append(buf, fmt.Sprintf(`(%s,%s)`,
+ strconv.FormatFloat(p.X, 'f', -1, 64),
+ strconv.FormatFloat(p.Y, 'f', -1, 64),
+ )...)
+ }
+
+ return append(buf, endByte), nil
+}
+
+func (src Path) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var closeByte byte
+ if src.Closed {
+ closeByte = 1
+ }
+ buf = append(buf, closeByte)
+
+ buf = pgio.AppendInt32(buf, int32(len(src.P)))
+
+ for _, p := range src.P {
+ buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Path) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Path{Status: Null}
+ return 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 Path) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/pgtype.go b/vendor/github.com/jackc/pgtype/pgtype.go
new file mode 100644
index 000000000..4a6808449
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/pgtype.go
@@ -0,0 +1,940 @@
+package pgtype
+
+import (
+ "database/sql"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math"
+ "net"
+ "reflect"
+ "time"
+)
+
+// PostgreSQL oids for common types
+const (
+ BoolOID = 16
+ ByteaOID = 17
+ QCharOID = 18
+ NameOID = 19
+ Int8OID = 20
+ Int2OID = 21
+ Int4OID = 23
+ TextOID = 25
+ OIDOID = 26
+ TIDOID = 27
+ XIDOID = 28
+ CIDOID = 29
+ JSONOID = 114
+ PointOID = 600
+ LsegOID = 601
+ PathOID = 602
+ BoxOID = 603
+ PolygonOID = 604
+ LineOID = 628
+ CIDROID = 650
+ CIDRArrayOID = 651
+ Float4OID = 700
+ Float8OID = 701
+ CircleOID = 718
+ UnknownOID = 705
+ MacaddrOID = 829
+ InetOID = 869
+ BoolArrayOID = 1000
+ Int2ArrayOID = 1005
+ Int4ArrayOID = 1007
+ TextArrayOID = 1009
+ ByteaArrayOID = 1001
+ BPCharArrayOID = 1014
+ VarcharArrayOID = 1015
+ Int8ArrayOID = 1016
+ Float4ArrayOID = 1021
+ Float8ArrayOID = 1022
+ ACLItemOID = 1033
+ ACLItemArrayOID = 1034
+ InetArrayOID = 1041
+ BPCharOID = 1042
+ VarcharOID = 1043
+ DateOID = 1082
+ TimeOID = 1083
+ TimestampOID = 1114
+ TimestampArrayOID = 1115
+ DateArrayOID = 1182
+ TimestamptzOID = 1184
+ TimestamptzArrayOID = 1185
+ IntervalOID = 1186
+ NumericArrayOID = 1231
+ BitOID = 1560
+ VarbitOID = 1562
+ NumericOID = 1700
+ RecordOID = 2249
+ UUIDOID = 2950
+ UUIDArrayOID = 2951
+ JSONBOID = 3802
+ JSONBArrayOID = 3807
+ DaterangeOID = 3912
+ Int4rangeOID = 3904
+ NumrangeOID = 3906
+ TsrangeOID = 3908
+ TsrangeArrayOID = 3909
+ TstzrangeOID = 3910
+ TstzrangeArrayOID = 3911
+ Int8rangeOID = 3926
+)
+
+type Status byte
+
+const (
+ Undefined Status = iota
+ Null
+ Present
+)
+
+type InfinityModifier int8
+
+const (
+ Infinity InfinityModifier = 1
+ None InfinityModifier = 0
+ NegativeInfinity InfinityModifier = -Infinity
+)
+
+func (im InfinityModifier) String() string {
+ switch im {
+ case None:
+ return "none"
+ case Infinity:
+ return "infinity"
+ case NegativeInfinity:
+ return "-infinity"
+ default:
+ return "invalid"
+ }
+}
+
+// PostgreSQL format codes
+const (
+ TextFormatCode = 0
+ BinaryFormatCode = 1
+)
+
+// Value translates values to and from an internal canonical representation for the type. To actually be usable a type
+// that implements Value should also implement some combination of BinaryDecoder, BinaryEncoder, TextDecoder,
+// and TextEncoder.
+//
+// Operations that update a Value (e.g. Set, DecodeText, DecodeBinary) should entirely replace the value. e.g. Internal
+// slices should be replaced not resized and reused. This allows Get and AssignTo to return a slice directly rather
+// than incur a usually unnecessary copy.
+type Value interface {
+ // Set converts and assigns src to itself. Value takes ownership of src.
+ Set(src interface{}) error
+
+ // Get returns the simplest representation of Value. Get may return a pointer to an internal value but it must never
+ // mutate that value. e.g. If Get returns a []byte Value must never change the contents of the []byte.
+ Get() interface{}
+
+ // AssignTo converts and assigns the Value to dst. AssignTo may a pointer to an internal value but it must never
+ // mutate that value. e.g. If Get returns a []byte Value must never change the contents of the []byte.
+ AssignTo(dst interface{}) error
+}
+
+// TypeValue is a Value where instances can represent different PostgreSQL types. This can be useful for
+// representing types such as enums, composites, and arrays.
+//
+// In general, instances of TypeValue should not be used to directly represent a value. It should only be used as an
+// encoder and decoder internal to ConnInfo.
+type TypeValue interface {
+ Value
+
+ // NewTypeValue creates a TypeValue including references to internal type information. e.g. the list of members
+ // in an EnumType.
+ NewTypeValue() Value
+
+ // TypeName returns the PostgreSQL name of this type.
+ TypeName() string
+}
+
+// ValueTranscoder is a value that implements the text and binary encoding and decoding interfaces.
+type ValueTranscoder interface {
+ Value
+ TextEncoder
+ BinaryEncoder
+ TextDecoder
+ BinaryDecoder
+}
+
+// ResultFormatPreferrer allows a type to specify its preferred result format instead of it being inferred from
+// whether it is also a BinaryDecoder.
+type ResultFormatPreferrer interface {
+ PreferredResultFormat() int16
+}
+
+// ParamFormatPreferrer allows a type to specify its preferred param format instead of it being inferred from
+// whether it is also a BinaryEncoder.
+type ParamFormatPreferrer interface {
+ PreferredParamFormat() int16
+}
+
+type BinaryDecoder interface {
+ // DecodeBinary decodes src into BinaryDecoder. If src is nil then the
+ // original SQL value is NULL. BinaryDecoder takes ownership of src. The
+ // caller MUST not use it again.
+ DecodeBinary(ci *ConnInfo, src []byte) error
+}
+
+type TextDecoder interface {
+ // DecodeText decodes src into TextDecoder. If src is nil then the original
+ // SQL value is NULL. TextDecoder takes ownership of src. The caller MUST not
+ // use it again.
+ DecodeText(ci *ConnInfo, src []byte) error
+}
+
+// BinaryEncoder is implemented by types that can encode themselves into the
+// PostgreSQL binary wire format.
+type BinaryEncoder interface {
+ // EncodeBinary should append the binary format of self to buf. If self is the
+ // SQL value NULL then append nothing and return (nil, nil). The caller of
+ // EncodeBinary is responsible for writing the correct NULL value or the
+ // length of the data written.
+ EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
+}
+
+// TextEncoder is implemented by types that can encode themselves into the
+// PostgreSQL text wire format.
+type TextEncoder interface {
+ // EncodeText should append the text format of self to buf. If self is the
+ // SQL value NULL then append nothing and return (nil, nil). The caller of
+ // EncodeText is responsible for writing the correct NULL value or the
+ // length of the data written.
+ EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
+}
+
+var errUndefined = errors.New("cannot encode status undefined")
+var errBadStatus = errors.New("invalid status")
+
+type nullAssignmentError struct {
+ dst interface{}
+}
+
+func (e *nullAssignmentError) Error() string {
+ return fmt.Sprintf("cannot assign NULL to %T", e.dst)
+}
+
+type DataType struct {
+ Value Value
+
+ textDecoder TextDecoder
+ binaryDecoder BinaryDecoder
+
+ Name string
+ OID uint32
+}
+
+type ConnInfo struct {
+ oidToDataType map[uint32]*DataType
+ nameToDataType map[string]*DataType
+ reflectTypeToName map[reflect.Type]string
+ oidToParamFormatCode map[uint32]int16
+ oidToResultFormatCode map[uint32]int16
+
+ reflectTypeToDataType map[reflect.Type]*DataType
+}
+
+func newConnInfo() *ConnInfo {
+ return &ConnInfo{
+ oidToDataType: make(map[uint32]*DataType),
+ nameToDataType: make(map[string]*DataType),
+ reflectTypeToName: make(map[reflect.Type]string),
+ oidToParamFormatCode: make(map[uint32]int16),
+ oidToResultFormatCode: make(map[uint32]int16),
+ }
+}
+
+func NewConnInfo() *ConnInfo {
+ ci := newConnInfo()
+
+ ci.RegisterDataType(DataType{Value: &ACLItemArray{}, Name: "_aclitem", OID: ACLItemArrayOID})
+ ci.RegisterDataType(DataType{Value: &BoolArray{}, Name: "_bool", OID: BoolArrayOID})
+ ci.RegisterDataType(DataType{Value: &BPCharArray{}, Name: "_bpchar", OID: BPCharArrayOID})
+ ci.RegisterDataType(DataType{Value: &ByteaArray{}, Name: "_bytea", OID: ByteaArrayOID})
+ ci.RegisterDataType(DataType{Value: &CIDRArray{}, Name: "_cidr", OID: CIDRArrayOID})
+ ci.RegisterDataType(DataType{Value: &DateArray{}, Name: "_date", OID: DateArrayOID})
+ ci.RegisterDataType(DataType{Value: &Float4Array{}, Name: "_float4", OID: Float4ArrayOID})
+ ci.RegisterDataType(DataType{Value: &Float8Array{}, Name: "_float8", OID: Float8ArrayOID})
+ ci.RegisterDataType(DataType{Value: &InetArray{}, Name: "_inet", OID: InetArrayOID})
+ ci.RegisterDataType(DataType{Value: &Int2Array{}, Name: "_int2", OID: Int2ArrayOID})
+ ci.RegisterDataType(DataType{Value: &Int4Array{}, Name: "_int4", OID: Int4ArrayOID})
+ ci.RegisterDataType(DataType{Value: &Int8Array{}, Name: "_int8", OID: Int8ArrayOID})
+ ci.RegisterDataType(DataType{Value: &NumericArray{}, Name: "_numeric", OID: NumericArrayOID})
+ ci.RegisterDataType(DataType{Value: &TextArray{}, Name: "_text", OID: TextArrayOID})
+ ci.RegisterDataType(DataType{Value: &TimestampArray{}, Name: "_timestamp", OID: TimestampArrayOID})
+ ci.RegisterDataType(DataType{Value: &TimestamptzArray{}, Name: "_timestamptz", OID: TimestamptzArrayOID})
+ ci.RegisterDataType(DataType{Value: &UUIDArray{}, Name: "_uuid", OID: UUIDArrayOID})
+ ci.RegisterDataType(DataType{Value: &VarcharArray{}, Name: "_varchar", OID: VarcharArrayOID})
+ ci.RegisterDataType(DataType{Value: &ACLItem{}, Name: "aclitem", OID: ACLItemOID})
+ ci.RegisterDataType(DataType{Value: &Bit{}, Name: "bit", OID: BitOID})
+ ci.RegisterDataType(DataType{Value: &Bool{}, Name: "bool", OID: BoolOID})
+ ci.RegisterDataType(DataType{Value: &Box{}, Name: "box", OID: BoxOID})
+ ci.RegisterDataType(DataType{Value: &BPChar{}, Name: "bpchar", OID: BPCharOID})
+ ci.RegisterDataType(DataType{Value: &Bytea{}, Name: "bytea", OID: ByteaOID})
+ ci.RegisterDataType(DataType{Value: &QChar{}, Name: "char", OID: QCharOID})
+ ci.RegisterDataType(DataType{Value: &CID{}, Name: "cid", OID: CIDOID})
+ ci.RegisterDataType(DataType{Value: &CIDR{}, Name: "cidr", OID: CIDROID})
+ ci.RegisterDataType(DataType{Value: &Circle{}, Name: "circle", OID: CircleOID})
+ ci.RegisterDataType(DataType{Value: &Date{}, Name: "date", OID: DateOID})
+ ci.RegisterDataType(DataType{Value: &Daterange{}, Name: "daterange", OID: DaterangeOID})
+ ci.RegisterDataType(DataType{Value: &Float4{}, Name: "float4", OID: Float4OID})
+ ci.RegisterDataType(DataType{Value: &Float8{}, Name: "float8", OID: Float8OID})
+ ci.RegisterDataType(DataType{Value: &Inet{}, Name: "inet", OID: InetOID})
+ ci.RegisterDataType(DataType{Value: &Int2{}, Name: "int2", OID: Int2OID})
+ ci.RegisterDataType(DataType{Value: &Int4{}, Name: "int4", OID: Int4OID})
+ ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID})
+ ci.RegisterDataType(DataType{Value: &Int8{}, Name: "int8", OID: Int8OID})
+ ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID})
+ ci.RegisterDataType(DataType{Value: &Interval{}, Name: "interval", OID: IntervalOID})
+ ci.RegisterDataType(DataType{Value: &JSON{}, Name: "json", OID: JSONOID})
+ ci.RegisterDataType(DataType{Value: &JSONB{}, Name: "jsonb", OID: JSONBOID})
+ ci.RegisterDataType(DataType{Value: &JSONBArray{}, Name: "_jsonb", OID: JSONBArrayOID})
+ ci.RegisterDataType(DataType{Value: &Line{}, Name: "line", OID: LineOID})
+ ci.RegisterDataType(DataType{Value: &Lseg{}, Name: "lseg", OID: LsegOID})
+ ci.RegisterDataType(DataType{Value: &Macaddr{}, Name: "macaddr", OID: MacaddrOID})
+ ci.RegisterDataType(DataType{Value: &Name{}, Name: "name", OID: NameOID})
+ ci.RegisterDataType(DataType{Value: &Numeric{}, Name: "numeric", OID: NumericOID})
+ ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID})
+ ci.RegisterDataType(DataType{Value: &OIDValue{}, Name: "oid", OID: OIDOID})
+ ci.RegisterDataType(DataType{Value: &Path{}, Name: "path", OID: PathOID})
+ ci.RegisterDataType(DataType{Value: &Point{}, Name: "point", OID: PointOID})
+ ci.RegisterDataType(DataType{Value: &Polygon{}, Name: "polygon", OID: PolygonOID})
+ ci.RegisterDataType(DataType{Value: &Record{}, Name: "record", OID: RecordOID})
+ ci.RegisterDataType(DataType{Value: &Text{}, Name: "text", OID: TextOID})
+ ci.RegisterDataType(DataType{Value: &TID{}, Name: "tid", OID: TIDOID})
+ ci.RegisterDataType(DataType{Value: &Time{}, Name: "time", OID: TimeOID})
+ ci.RegisterDataType(DataType{Value: &Timestamp{}, Name: "timestamp", OID: TimestampOID})
+ ci.RegisterDataType(DataType{Value: &Timestamptz{}, Name: "timestamptz", OID: TimestamptzOID})
+ ci.RegisterDataType(DataType{Value: &Tsrange{}, Name: "tsrange", OID: TsrangeOID})
+ ci.RegisterDataType(DataType{Value: &TsrangeArray{}, Name: "_tsrange", OID: TsrangeArrayOID})
+ ci.RegisterDataType(DataType{Value: &Tstzrange{}, Name: "tstzrange", OID: TstzrangeOID})
+ ci.RegisterDataType(DataType{Value: &TstzrangeArray{}, Name: "_tstzrange", OID: TstzrangeArrayOID})
+ ci.RegisterDataType(DataType{Value: &Unknown{}, Name: "unknown", OID: UnknownOID})
+ ci.RegisterDataType(DataType{Value: &UUID{}, Name: "uuid", OID: UUIDOID})
+ ci.RegisterDataType(DataType{Value: &Varbit{}, Name: "varbit", OID: VarbitOID})
+ ci.RegisterDataType(DataType{Value: &Varchar{}, Name: "varchar", OID: VarcharOID})
+ ci.RegisterDataType(DataType{Value: &XID{}, Name: "xid", OID: XIDOID})
+
+ registerDefaultPgTypeVariants := func(name, arrayName string, value interface{}) {
+ ci.RegisterDefaultPgType(value, name)
+ valueType := reflect.TypeOf(value)
+
+ ci.RegisterDefaultPgType(reflect.New(valueType).Interface(), name)
+
+ sliceType := reflect.SliceOf(valueType)
+ ci.RegisterDefaultPgType(reflect.MakeSlice(sliceType, 0, 0).Interface(), arrayName)
+
+ ci.RegisterDefaultPgType(reflect.New(sliceType).Interface(), arrayName)
+ }
+
+ // Integer types that directly map to a PostgreSQL type
+ registerDefaultPgTypeVariants("int2", "_int2", int16(0))
+ registerDefaultPgTypeVariants("int4", "_int4", int32(0))
+ registerDefaultPgTypeVariants("int8", "_int8", int64(0))
+
+ // Integer types that do not have a direct match to a PostgreSQL type
+ registerDefaultPgTypeVariants("int8", "_int8", uint16(0))
+ registerDefaultPgTypeVariants("int8", "_int8", uint32(0))
+ registerDefaultPgTypeVariants("int8", "_int8", uint64(0))
+ registerDefaultPgTypeVariants("int8", "_int8", int(0))
+ registerDefaultPgTypeVariants("int8", "_int8", uint(0))
+
+ registerDefaultPgTypeVariants("float4", "_float4", float32(0))
+ registerDefaultPgTypeVariants("float8", "_float8", float64(0))
+
+ registerDefaultPgTypeVariants("bool", "_bool", false)
+ registerDefaultPgTypeVariants("timestamptz", "_timestamptz", time.Time{})
+ registerDefaultPgTypeVariants("text", "_text", "")
+ registerDefaultPgTypeVariants("bytea", "_bytea", []byte(nil))
+
+ registerDefaultPgTypeVariants("inet", "_inet", net.IP{})
+ ci.RegisterDefaultPgType((*net.IPNet)(nil), "cidr")
+ ci.RegisterDefaultPgType([]*net.IPNet(nil), "_cidr")
+
+ return ci
+}
+
+func (ci *ConnInfo) InitializeDataTypes(nameOIDs map[string]uint32) {
+ for name, oid := range nameOIDs {
+ var value Value
+ if t, ok := nameValues[name]; ok {
+ value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value)
+ } else {
+ value = &GenericText{}
+ }
+ ci.RegisterDataType(DataType{Value: value, Name: name, OID: oid})
+ }
+}
+
+func (ci *ConnInfo) RegisterDataType(t DataType) {
+ t.Value = NewValue(t.Value)
+
+ ci.oidToDataType[t.OID] = &t
+ ci.nameToDataType[t.Name] = &t
+
+ {
+ var formatCode int16
+ if pfp, ok := t.Value.(ParamFormatPreferrer); ok {
+ formatCode = pfp.PreferredParamFormat()
+ } else if _, ok := t.Value.(BinaryEncoder); ok {
+ formatCode = BinaryFormatCode
+ }
+ ci.oidToParamFormatCode[t.OID] = formatCode
+ }
+
+ {
+ var formatCode int16
+ if rfp, ok := t.Value.(ResultFormatPreferrer); ok {
+ formatCode = rfp.PreferredResultFormat()
+ } else if _, ok := t.Value.(BinaryDecoder); ok {
+ formatCode = BinaryFormatCode
+ }
+ ci.oidToResultFormatCode[t.OID] = formatCode
+ }
+
+ if d, ok := t.Value.(TextDecoder); ok {
+ t.textDecoder = d
+ }
+
+ if d, ok := t.Value.(BinaryDecoder); ok {
+ t.binaryDecoder = d
+ }
+
+ ci.reflectTypeToDataType = nil // Invalidated by type registration
+}
+
+// RegisterDefaultPgType registers a mapping of a Go type to a PostgreSQL type name. Typically the data type to be
+// encoded or decoded is determined by the PostgreSQL OID. But if the OID of a value to be encoded or decoded is
+// unknown, this additional mapping will be used by DataTypeForValue to determine a suitable data type.
+func (ci *ConnInfo) RegisterDefaultPgType(value interface{}, name string) {
+ ci.reflectTypeToName[reflect.TypeOf(value)] = name
+ ci.reflectTypeToDataType = nil // Invalidated by registering a default type
+}
+
+func (ci *ConnInfo) DataTypeForOID(oid uint32) (*DataType, bool) {
+ dt, ok := ci.oidToDataType[oid]
+ return dt, ok
+}
+
+func (ci *ConnInfo) DataTypeForName(name string) (*DataType, bool) {
+ dt, ok := ci.nameToDataType[name]
+ return dt, ok
+}
+
+func (ci *ConnInfo) buildReflectTypeToDataType() {
+ ci.reflectTypeToDataType = make(map[reflect.Type]*DataType)
+
+ for _, dt := range ci.oidToDataType {
+ if _, is := dt.Value.(TypeValue); !is {
+ ci.reflectTypeToDataType[reflect.ValueOf(dt.Value).Type()] = dt
+ }
+ }
+
+ for reflectType, name := range ci.reflectTypeToName {
+ if dt, ok := ci.nameToDataType[name]; ok {
+ ci.reflectTypeToDataType[reflectType] = dt
+ }
+ }
+}
+
+// DataTypeForValue finds a data type suitable for v. Use RegisterDataType to register types that can encode and decode
+// themselves. Use RegisterDefaultPgType to register that can be handled by a registered data type.
+func (ci *ConnInfo) DataTypeForValue(v interface{}) (*DataType, bool) {
+ if ci.reflectTypeToDataType == nil {
+ ci.buildReflectTypeToDataType()
+ }
+
+ if tv, ok := v.(TypeValue); ok {
+ dt, ok := ci.nameToDataType[tv.TypeName()]
+ return dt, ok
+ }
+
+ dt, ok := ci.reflectTypeToDataType[reflect.TypeOf(v)]
+ return dt, ok
+}
+
+func (ci *ConnInfo) ParamFormatCodeForOID(oid uint32) int16 {
+ fc, ok := ci.oidToParamFormatCode[oid]
+ if ok {
+ return fc
+ }
+ return TextFormatCode
+}
+
+func (ci *ConnInfo) ResultFormatCodeForOID(oid uint32) int16 {
+ fc, ok := ci.oidToResultFormatCode[oid]
+ if ok {
+ return fc
+ }
+ return TextFormatCode
+}
+
+// DeepCopy makes a deep copy of the ConnInfo.
+func (ci *ConnInfo) DeepCopy() *ConnInfo {
+ ci2 := newConnInfo()
+
+ for _, dt := range ci.oidToDataType {
+ ci2.RegisterDataType(DataType{
+ Value: NewValue(dt.Value),
+ Name: dt.Name,
+ OID: dt.OID,
+ })
+ }
+
+ for t, n := range ci.reflectTypeToName {
+ ci2.reflectTypeToName[t] = n
+ }
+
+ return ci2
+}
+
+// ScanPlan is a precompiled plan to scan into a type of destination.
+type ScanPlan interface {
+ // Scan scans src into dst. If the dst type has changed in an incompatible way a ScanPlan should automatically
+ // replan and scan.
+ Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error
+}
+
+type scanPlanDstBinaryDecoder struct{}
+
+func (scanPlanDstBinaryDecoder) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if d, ok := (dst).(BinaryDecoder); ok {
+ return d.DecodeBinary(ci, src)
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanDstTextDecoder struct{}
+
+func (plan scanPlanDstTextDecoder) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if d, ok := (dst).(TextDecoder); ok {
+ return d.DecodeText(ci, src)
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanDataTypeSQLScanner DataType
+
+func (plan *scanPlanDataTypeSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ scanner, ok := dst.(sql.Scanner)
+ if !ok {
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+ }
+
+ dt := (*DataType)(plan)
+ var err error
+ switch formatCode {
+ case BinaryFormatCode:
+ err = dt.binaryDecoder.DecodeBinary(ci, src)
+ case TextFormatCode:
+ err = dt.textDecoder.DecodeText(ci, src)
+ }
+ if err != nil {
+ return err
+ }
+
+ sqlSrc, err := DatabaseSQLValue(ci, dt.Value)
+ if err != nil {
+ return err
+ }
+ return scanner.Scan(sqlSrc)
+}
+
+type scanPlanDataTypeAssignTo DataType
+
+func (plan *scanPlanDataTypeAssignTo) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ dt := (*DataType)(plan)
+ var err error
+ switch formatCode {
+ case BinaryFormatCode:
+ err = dt.binaryDecoder.DecodeBinary(ci, src)
+ case TextFormatCode:
+ err = dt.textDecoder.DecodeText(ci, src)
+ }
+ if err != nil {
+ return err
+ }
+
+ assignToErr := dt.Value.AssignTo(dst)
+ if assignToErr == nil {
+ return nil
+ }
+
+ if dstPtr, ok := dst.(*interface{}); ok {
+ *dstPtr = dt.Value.Get()
+ return nil
+ }
+
+ // assignToErr might have failed because the type of destination has changed
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ if newPlan, sameType := newPlan.(*scanPlanDataTypeAssignTo); !sameType {
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+ }
+
+ return assignToErr
+}
+
+type scanPlanSQLScanner struct{}
+
+func (scanPlanSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ scanner := dst.(sql.Scanner)
+ if formatCode == BinaryFormatCode {
+ return scanner.Scan(src)
+ } else {
+ return scanner.Scan(string(src))
+ }
+}
+
+type scanPlanReflection struct{}
+
+func (scanPlanReflection) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ // We might be given a pointer to something that implements the decoder interface(s),
+ // even though the pointer itself doesn't.
+ refVal := reflect.ValueOf(dst)
+ if refVal.Kind() == reflect.Ptr && refVal.Type().Elem().Kind() == reflect.Ptr {
+ // If the database returned NULL, then we set dest as nil to indicate that.
+ if src == nil {
+ nilPtr := reflect.Zero(refVal.Type().Elem())
+ refVal.Elem().Set(nilPtr)
+ return nil
+ }
+
+ // We need to allocate an element, and set the destination to it
+ // Then we can retry as that element.
+ elemPtr := reflect.New(refVal.Type().Elem().Elem())
+ refVal.Elem().Set(elemPtr)
+
+ plan := ci.PlanScan(oid, formatCode, elemPtr.Interface())
+ return plan.Scan(ci, oid, formatCode, src, elemPtr.Interface())
+ }
+
+ return scanUnknownType(oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryInt16 struct{}
+
+func (scanPlanBinaryInt16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if len(src) != 2 {
+ return fmt.Errorf("invalid length for int2: %v", len(src))
+ }
+
+ if p, ok := (dst).(*int16); ok {
+ *p = int16(binary.BigEndian.Uint16(src))
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryInt32 struct{}
+
+func (scanPlanBinaryInt32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length for int4: %v", len(src))
+ }
+
+ if p, ok := (dst).(*int32); ok {
+ *p = int32(binary.BigEndian.Uint32(src))
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryInt64 struct{}
+
+func (scanPlanBinaryInt64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for int8: %v", len(src))
+ }
+
+ if p, ok := (dst).(*int64); ok {
+ *p = int64(binary.BigEndian.Uint64(src))
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryFloat32 struct{}
+
+func (scanPlanBinaryFloat32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length for int4: %v", len(src))
+ }
+
+ if p, ok := (dst).(*float32); ok {
+ n := int32(binary.BigEndian.Uint32(src))
+ *p = float32(math.Float32frombits(uint32(n)))
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryFloat64 struct{}
+
+func (scanPlanBinaryFloat64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for int8: %v", len(src))
+ }
+
+ if p, ok := (dst).(*float64); ok {
+ n := int64(binary.BigEndian.Uint64(src))
+ *p = float64(math.Float64frombits(uint64(n)))
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanBinaryBytes struct{}
+
+func (scanPlanBinaryBytes) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if p, ok := (dst).(*[]byte); ok {
+ *p = src
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+type scanPlanString struct{}
+
+func (scanPlanString) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if src == nil {
+ return fmt.Errorf("cannot scan null into %T", dst)
+ }
+
+ if p, ok := (dst).(*string); ok {
+ *p = string(src)
+ return nil
+ }
+
+ newPlan := ci.PlanScan(oid, formatCode, dst)
+ return newPlan.Scan(ci, oid, formatCode, src, dst)
+}
+
+// PlanScan prepares a plan to scan a value into dst.
+func (ci *ConnInfo) PlanScan(oid uint32, formatCode int16, dst interface{}) ScanPlan {
+ switch formatCode {
+ case BinaryFormatCode:
+ switch dst.(type) {
+ case *string:
+ switch oid {
+ case TextOID, VarcharOID:
+ return scanPlanString{}
+ }
+ case *int16:
+ if oid == Int2OID {
+ return scanPlanBinaryInt16{}
+ }
+ case *int32:
+ if oid == Int4OID {
+ return scanPlanBinaryInt32{}
+ }
+ case *int64:
+ if oid == Int8OID {
+ return scanPlanBinaryInt64{}
+ }
+ case *float32:
+ if oid == Float4OID {
+ return scanPlanBinaryFloat32{}
+ }
+ case *float64:
+ if oid == Float8OID {
+ return scanPlanBinaryFloat64{}
+ }
+ case *[]byte:
+ switch oid {
+ case ByteaOID, TextOID, VarcharOID, JSONOID:
+ return scanPlanBinaryBytes{}
+ }
+ case BinaryDecoder:
+ return scanPlanDstBinaryDecoder{}
+ }
+ case TextFormatCode:
+ switch dst.(type) {
+ case *string:
+ return scanPlanString{}
+ case *[]byte:
+ if oid != ByteaOID {
+ return scanPlanBinaryBytes{}
+ }
+ case TextDecoder:
+ return scanPlanDstTextDecoder{}
+ }
+ }
+
+ var dt *DataType
+
+ if oid == 0 {
+ if dataType, ok := ci.DataTypeForValue(dst); ok {
+ dt = dataType
+ }
+ } else {
+ if dataType, ok := ci.DataTypeForOID(oid); ok {
+ dt = dataType
+ }
+ }
+
+ if dt != nil {
+ if _, ok := dst.(sql.Scanner); ok {
+ return (*scanPlanDataTypeSQLScanner)(dt)
+ }
+ return (*scanPlanDataTypeAssignTo)(dt)
+ }
+
+ if _, ok := dst.(sql.Scanner); ok {
+ return scanPlanSQLScanner{}
+ }
+
+ return scanPlanReflection{}
+}
+
+func (ci *ConnInfo) Scan(oid uint32, formatCode int16, src []byte, dst interface{}) error {
+ if dst == nil {
+ return nil
+ }
+
+ plan := ci.PlanScan(oid, formatCode, dst)
+ return plan.Scan(ci, oid, formatCode, src, dst)
+}
+
+func scanUnknownType(oid uint32, formatCode int16, buf []byte, dest interface{}) error {
+ switch dest := dest.(type) {
+ case *string:
+ if formatCode == BinaryFormatCode {
+ return fmt.Errorf("unknown oid %d in binary format cannot be scanned into %T", oid, dest)
+ }
+ *dest = string(buf)
+ return nil
+ case *[]byte:
+ *dest = buf
+ return nil
+ default:
+ if nextDst, retry := GetAssignToDstType(dest); retry {
+ return scanUnknownType(oid, formatCode, buf, nextDst)
+ }
+ return fmt.Errorf("unknown oid %d cannot be scanned into %T", oid, dest)
+ }
+}
+
+// NewValue returns a new instance of the same type as v.
+func NewValue(v Value) Value {
+ if tv, ok := v.(TypeValue); ok {
+ return tv.NewTypeValue()
+ } else {
+ return reflect.New(reflect.ValueOf(v).Elem().Type()).Interface().(Value)
+ }
+}
+
+var nameValues map[string]Value
+
+func init() {
+ nameValues = map[string]Value{
+ "_aclitem": &ACLItemArray{},
+ "_bool": &BoolArray{},
+ "_bpchar": &BPCharArray{},
+ "_bytea": &ByteaArray{},
+ "_cidr": &CIDRArray{},
+ "_date": &DateArray{},
+ "_float4": &Float4Array{},
+ "_float8": &Float8Array{},
+ "_inet": &InetArray{},
+ "_int2": &Int2Array{},
+ "_int4": &Int4Array{},
+ "_int8": &Int8Array{},
+ "_numeric": &NumericArray{},
+ "_text": &TextArray{},
+ "_timestamp": &TimestampArray{},
+ "_timestamptz": &TimestamptzArray{},
+ "_uuid": &UUIDArray{},
+ "_varchar": &VarcharArray{},
+ "_jsonb": &JSONBArray{},
+ "aclitem": &ACLItem{},
+ "bit": &Bit{},
+ "bool": &Bool{},
+ "box": &Box{},
+ "bpchar": &BPChar{},
+ "bytea": &Bytea{},
+ "char": &QChar{},
+ "cid": &CID{},
+ "cidr": &CIDR{},
+ "circle": &Circle{},
+ "date": &Date{},
+ "daterange": &Daterange{},
+ "float4": &Float4{},
+ "float8": &Float8{},
+ "hstore": &Hstore{},
+ "inet": &Inet{},
+ "int2": &Int2{},
+ "int4": &Int4{},
+ "int4range": &Int4range{},
+ "int8": &Int8{},
+ "int8range": &Int8range{},
+ "interval": &Interval{},
+ "json": &JSON{},
+ "jsonb": &JSONB{},
+ "line": &Line{},
+ "lseg": &Lseg{},
+ "macaddr": &Macaddr{},
+ "name": &Name{},
+ "numeric": &Numeric{},
+ "numrange": &Numrange{},
+ "oid": &OIDValue{},
+ "path": &Path{},
+ "point": &Point{},
+ "polygon": &Polygon{},
+ "record": &Record{},
+ "text": &Text{},
+ "tid": &TID{},
+ "timestamp": &Timestamp{},
+ "timestamptz": &Timestamptz{},
+ "tsrange": &Tsrange{},
+ "_tsrange": &TsrangeArray{},
+ "tstzrange": &Tstzrange{},
+ "_tstzrange": &TstzrangeArray{},
+ "unknown": &Unknown{},
+ "uuid": &UUID{},
+ "varbit": &Varbit{},
+ "varchar": &Varchar{},
+ "xid": &XID{},
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/pguint32.go b/vendor/github.com/jackc/pgtype/pguint32.go
new file mode 100644
index 000000000..a0e88ca2a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/pguint32.go
@@ -0,0 +1,162 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+
+ "github.com/jackc/pgio"
+)
+
+// pguint32 is the core type that is used to implement PostgreSQL types such as
+// CID and XID.
+type pguint32 struct {
+ Uint uint32
+ Status Status
+}
+
+// Set converts from src to dst. Note that as pguint32 is not a general
+// number type Set does not do automatic type conversion as other number
+// types do.
+func (dst *pguint32) Set(src interface{}) error {
+ switch value := src.(type) {
+ case int64:
+ if value < 0 {
+ return fmt.Errorf("%d is less than minimum value for pguint32", value)
+ }
+ if value > math.MaxUint32 {
+ return fmt.Errorf("%d is greater than maximum value for pguint32", value)
+ }
+ *dst = pguint32{Uint: uint32(value), Status: Present}
+ case uint32:
+ *dst = pguint32{Uint: value, Status: Present}
+ default:
+ return fmt.Errorf("cannot convert %v to pguint32", value)
+ }
+
+ return nil
+}
+
+func (dst pguint32) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Uint
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+// AssignTo assigns from src to dst. Note that as pguint32 is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *pguint32) AssignTo(dst interface{}) error {
+ switch v := dst.(type) {
+ case *uint32:
+ if src.Status == Present {
+ *v = src.Uint
+ } else {
+ return fmt.Errorf("cannot assign %v into %T", src, dst)
+ }
+ case **uint32:
+ if src.Status == Present {
+ n := src.Uint
+ *v = &n
+ } else {
+ *v = nil
+ }
+ }
+
+ return nil
+}
+
+func (dst *pguint32) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = pguint32{Status: Null}
+ return nil
+ }
+
+ n, err := strconv.ParseUint(string(src), 10, 32)
+ if err != nil {
+ return err
+ }
+
+ *dst = pguint32{Uint: uint32(n), Status: Present}
+ return nil
+}
+
+func (dst *pguint32) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = pguint32{Status: Null}
+ return nil
+ }
+
+ if len(src) != 4 {
+ return fmt.Errorf("invalid length: %v", len(src))
+ }
+
+ n := binary.BigEndian.Uint32(src)
+ *dst = pguint32{Uint: n, Status: Present}
+ return nil
+}
+
+func (src pguint32) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, strconv.FormatUint(uint64(src.Uint), 10)...), nil
+}
+
+func (src pguint32) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return pgio.AppendUint32(buf, src.Uint), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *pguint32) Scan(src interface{}) error {
+ if src == nil {
+ *dst = pguint32{Status: Null}
+ return nil
+ }
+
+ switch src := src.(type) {
+ case uint32:
+ *dst = pguint32{Uint: src, Status: Present}
+ return nil
+ case int64:
+ *dst = pguint32{Uint: uint32(src), Status: Present}
+ return nil
+ 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 pguint32) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return int64(src.Uint), nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/point.go b/vendor/github.com/jackc/pgtype/point.go
new file mode 100644
index 000000000..0c799106c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/point.go
@@ -0,0 +1,214 @@
+package pgtype
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Vec2 struct {
+ X float64
+ Y float64
+}
+
+type Point struct {
+ P Vec2
+ Status Status
+}
+
+func (dst *Point) Set(src interface{}) error {
+ if src == nil {
+ dst.Status = Null
+ return nil
+ }
+ err := fmt.Errorf("cannot convert %v to Point", src)
+ var p *Point
+ switch value := src.(type) {
+ case string:
+ p, err = parsePoint([]byte(value))
+ case []byte:
+ p, err = parsePoint(value)
+ default:
+ return err
+ }
+ if err != nil {
+ return err
+ }
+ *dst = *p
+ return nil
+}
+
+func parsePoint(src []byte) (*Point, error) {
+ if src == nil || bytes.Compare(src, []byte("null")) == 0 {
+ return &Point{Status: Null}, nil
+ }
+
+ if len(src) < 5 {
+ return nil, fmt.Errorf("invalid length for point: %v", len(src))
+ }
+ if src[0] == '"' && src[len(src)-1] == '"' {
+ src = src[1 : len(src)-1]
+ }
+ parts := strings.SplitN(string(src[1:len(src)-1]), ",", 2)
+ if len(parts) < 2 {
+ return nil, fmt.Errorf("invalid format for point")
+ }
+
+ x, err := strconv.ParseFloat(parts[0], 64)
+ if err != nil {
+ return nil, err
+ }
+
+ y, err := strconv.ParseFloat(parts[1], 64)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Point{P: Vec2{x, y}, Status: Present}, nil
+}
+
+func (dst Point) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Point) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Point) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Point{Status: Null}
+ return nil
+ }
+
+ if len(src) < 5 {
+ return fmt.Errorf("invalid length for point: %v", len(src))
+ }
+
+ parts := strings.SplitN(string(src[1:len(src)-1]), ",", 2)
+ if len(parts) < 2 {
+ return fmt.Errorf("invalid format for point")
+ }
+
+ x, err := strconv.ParseFloat(parts[0], 64)
+ if err != nil {
+ return err
+ }
+
+ y, err := strconv.ParseFloat(parts[1], 64)
+ if err != nil {
+ return err
+ }
+
+ *dst = Point{P: Vec2{x, y}, Status: Present}
+ return nil
+}
+
+func (dst *Point) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Point{Status: Null}
+ return nil
+ }
+
+ if len(src) != 16 {
+ return fmt.Errorf("invalid length for point: %v", len(src))
+ }
+
+ x := binary.BigEndian.Uint64(src)
+ y := binary.BigEndian.Uint64(src[8:])
+
+ *dst = Point{
+ P: Vec2{math.Float64frombits(x), math.Float64frombits(y)},
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Point) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, fmt.Sprintf(`(%s,%s)`,
+ strconv.FormatFloat(src.P.X, 'f', -1, 64),
+ strconv.FormatFloat(src.P.Y, 'f', -1, 64),
+ )...), nil
+}
+
+func (src Point) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P.X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(src.P.Y))
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Point) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Point{Status: Null}
+ return 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 Point) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
+
+func (src Point) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ var buff bytes.Buffer
+ buff.WriteByte('"')
+ buff.WriteString(fmt.Sprintf("(%g,%g)", src.P.X, src.P.Y))
+ buff.WriteByte('"')
+ return buff.Bytes(), nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+ return nil, errBadStatus
+}
+
+func (dst *Point) UnmarshalJSON(point []byte) error {
+ p, err := parsePoint(point)
+ if err != nil {
+ return err
+ }
+ *dst = *p
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/polygon.go b/vendor/github.com/jackc/pgtype/polygon.go
new file mode 100644
index 000000000..207cadc00
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/polygon.go
@@ -0,0 +1,226 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+type Polygon struct {
+ P []Vec2
+ Status Status
+}
+
+// Set converts src to dest.
+//
+// src can be nil, string, []float64, and []pgtype.Vec2.
+//
+// If src is string the format must be ((x1,y1),(x2,y2),...,(xn,yn)).
+// Important that there are no spaces in it.
+func (dst *Polygon) Set(src interface{}) error {
+ if src == nil {
+ dst.Status = Null
+ return nil
+ }
+ err := fmt.Errorf("cannot convert %v to Polygon", src)
+ var p *Polygon
+ switch value := src.(type) {
+ case string:
+ p, err = stringToPolygon(value)
+ case []Vec2:
+ p = &Polygon{Status: Present, P: value}
+ err = nil
+ case []float64:
+ p, err = float64ToPolygon(value)
+ default:
+ return err
+ }
+ if err != nil {
+ return err
+ }
+ *dst = *p
+ return nil
+}
+
+func stringToPolygon(src string) (*Polygon, error) {
+ p := &Polygon{}
+ err := p.DecodeText(nil, []byte(src))
+ return p, err
+}
+
+func float64ToPolygon(src []float64) (*Polygon, error) {
+ p := &Polygon{Status: Null}
+ if len(src) == 0 {
+ return p, nil
+ }
+ if len(src)%2 != 0 {
+ p.Status = Undefined
+ return p, fmt.Errorf("invalid length for polygon: %v", len(src))
+ }
+ p.Status = Present
+ p.P = make([]Vec2, 0)
+ for i := 0; i < len(src); i += 2 {
+ p.P = append(p.P, Vec2{X: src[i], Y: src[i+1]})
+ }
+ return p, nil
+}
+
+func (dst Polygon) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Polygon) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Polygon) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Polygon{Status: Null}
+ return nil
+ }
+
+ if len(src) < 7 {
+ return fmt.Errorf("invalid length for Polygon: %v", len(src))
+ }
+
+ points := make([]Vec2, 0)
+
+ str := string(src[2:])
+
+ for {
+ end := strings.IndexByte(str, ',')
+ x, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ str = str[end+1:]
+ end = strings.IndexByte(str, ')')
+
+ y, err := strconv.ParseFloat(str[:end], 64)
+ if err != nil {
+ return err
+ }
+
+ points = append(points, Vec2{x, y})
+
+ if end+3 < len(str) {
+ str = str[end+3:]
+ } else {
+ break
+ }
+ }
+
+ *dst = Polygon{P: points, Status: Present}
+ return nil
+}
+
+func (dst *Polygon) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Polygon{Status: Null}
+ return nil
+ }
+
+ if len(src) < 5 {
+ return fmt.Errorf("invalid length for Polygon: %v", len(src))
+ }
+
+ pointCount := int(binary.BigEndian.Uint32(src))
+ rp := 4
+
+ if 4+pointCount*16 != len(src) {
+ return fmt.Errorf("invalid length for Polygon with %d points: %v", pointCount, len(src))
+ }
+
+ points := make([]Vec2, pointCount)
+ for i := 0; i < len(points); i++ {
+ x := binary.BigEndian.Uint64(src[rp:])
+ rp += 8
+ y := binary.BigEndian.Uint64(src[rp:])
+ rp += 8
+ points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
+ }
+
+ *dst = Polygon{
+ P: points,
+ Status: Present,
+ }
+ return nil
+}
+
+func (src Polygon) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, '(')
+
+ for i, p := range src.P {
+ if i > 0 {
+ buf = append(buf, ',')
+ }
+ buf = append(buf, fmt.Sprintf(`(%s,%s)`,
+ strconv.FormatFloat(p.X, 'f', -1, 64),
+ strconv.FormatFloat(p.Y, 'f', -1, 64),
+ )...)
+ }
+
+ return append(buf, ')'), nil
+}
+
+func (src Polygon) 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.P)))
+
+ for _, p := range src.P {
+ buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
+ buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Polygon) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Polygon{Status: Null}
+ return 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 Polygon) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/qchar.go b/vendor/github.com/jackc/pgtype/qchar.go
new file mode 100644
index 000000000..574f6066c
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/qchar.go
@@ -0,0 +1,152 @@
+package pgtype
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+)
+
+// QChar is for PostgreSQL's special 8-bit-only "char" type more akin to the C
+// language's char type, or Go's byte type. (Note that the name in PostgreSQL
+// itself is "char", in double-quotes, and not char.) It gets used a lot in
+// PostgreSQL's system tables to hold a single ASCII character value (eg
+// pg_class.relkind). It is named Qchar for quoted char to disambiguate from SQL
+// standard type char.
+//
+// Not all possible values of QChar are representable in the text format.
+// Therefore, QChar does not implement TextEncoder and TextDecoder. In
+// addition, database/sql Scanner and database/sql/driver Value are not
+// implemented.
+type QChar struct {
+ Int int8
+ Status Status
+}
+
+func (dst *QChar) Set(src interface{}) error {
+ if src == nil {
+ *dst = QChar{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case int8:
+ *dst = QChar{Int: value, Status: Present}
+ case uint8:
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case int16:
+ if value < math.MinInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case uint16:
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case int32:
+ if value < math.MinInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case uint32:
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case int64:
+ if value < math.MinInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case uint64:
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case int:
+ if value < math.MinInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case uint:
+ if value > math.MaxInt8 {
+ return fmt.Errorf("%d is greater than maximum value for QChar", value)
+ }
+ *dst = QChar{Int: int8(value), Status: Present}
+ case string:
+ num, err := strconv.ParseInt(value, 10, 8)
+ if err != nil {
+ return err
+ }
+ *dst = QChar{Int: int8(num), Status: Present}
+ default:
+ if originalSrc, ok := underlyingNumberType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to QChar", value)
+ }
+
+ return nil
+}
+
+func (dst QChar) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Int
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *QChar) AssignTo(dst interface{}) error {
+ return int64AssignTo(int64(src.Int), src.Status, dst)
+}
+
+func (dst *QChar) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = QChar{Status: Null}
+ return nil
+ }
+
+ if len(src) != 1 {
+ return fmt.Errorf(`invalid length for "char": %v`, len(src))
+ }
+
+ *dst = QChar{Int: int8(src[0]), Status: Present}
+ return nil
+}
+
+func (src QChar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, byte(src.Int)), nil
+}
diff --git a/vendor/github.com/jackc/pgtype/range.go b/vendor/github.com/jackc/pgtype/range.go
new file mode 100644
index 000000000..e999f6a91
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/range.go
@@ -0,0 +1,277 @@
+package pgtype
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+)
+
+type BoundType byte
+
+const (
+ Inclusive = BoundType('i')
+ Exclusive = BoundType('e')
+ Unbounded = BoundType('U')
+ Empty = BoundType('E')
+)
+
+func (bt BoundType) String() string {
+ return string(bt)
+}
+
+type UntypedTextRange struct {
+ Lower string
+ Upper string
+ LowerType BoundType
+ UpperType BoundType
+}
+
+func ParseUntypedTextRange(src string) (*UntypedTextRange, error) {
+ utr := &UntypedTextRange{}
+ if src == "empty" {
+ utr.LowerType = Empty
+ utr.UpperType = Empty
+ return utr, nil
+ }
+
+ buf := bytes.NewBufferString(src)
+
+ skipWhitespace(buf)
+
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid lower bound: %v", err)
+ }
+ switch r {
+ case '(':
+ utr.LowerType = Exclusive
+ case '[':
+ utr.LowerType = Inclusive
+ default:
+ return nil, fmt.Errorf("missing lower bound, instead got: %v", string(r))
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid lower value: %v", err)
+ }
+ buf.UnreadRune()
+
+ if r == ',' {
+ utr.LowerType = Unbounded
+ } else {
+ utr.Lower, err = rangeParseValue(buf)
+ if err != nil {
+ return nil, fmt.Errorf("invalid lower value: %v", err)
+ }
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("missing range separator: %v", err)
+ }
+ if r != ',' {
+ return nil, fmt.Errorf("missing range separator: %v", r)
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("invalid upper value: %v", err)
+ }
+
+ if r == ')' || r == ']' {
+ utr.UpperType = Unbounded
+ } else {
+ buf.UnreadRune()
+ utr.Upper, err = rangeParseValue(buf)
+ if err != nil {
+ return nil, fmt.Errorf("invalid upper value: %v", err)
+ }
+
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return nil, fmt.Errorf("missing upper bound: %v", err)
+ }
+ switch r {
+ case ')':
+ utr.UpperType = Exclusive
+ case ']':
+ utr.UpperType = Inclusive
+ default:
+ return nil, fmt.Errorf("missing upper bound, instead got: %v", string(r))
+ }
+ }
+
+ skipWhitespace(buf)
+
+ if buf.Len() > 0 {
+ return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
+ }
+
+ return utr, nil
+}
+
+func rangeParseValue(buf *bytes.Buffer) (string, error) {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+ if r == '"' {
+ return rangeParseQuotedValue(buf)
+ }
+ buf.UnreadRune()
+
+ s := &bytes.Buffer{}
+
+ for {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+
+ switch r {
+ case '\\':
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+ case ',', '[', ']', '(', ')':
+ buf.UnreadRune()
+ return s.String(), nil
+ }
+
+ s.WriteRune(r)
+ }
+}
+
+func rangeParseQuotedValue(buf *bytes.Buffer) (string, error) {
+ s := &bytes.Buffer{}
+
+ for {
+ r, _, err := buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+
+ switch r {
+ case '\\':
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+ case '"':
+ r, _, err = buf.ReadRune()
+ if err != nil {
+ return "", err
+ }
+ if r != '"' {
+ buf.UnreadRune()
+ return s.String(), nil
+ }
+ }
+ s.WriteRune(r)
+ }
+}
+
+type UntypedBinaryRange struct {
+ Lower []byte
+ Upper []byte
+ LowerType BoundType
+ UpperType BoundType
+}
+
+// 0 = () = 00000
+// 1 = empty = 00001
+// 2 = [) = 00010
+// 4 = (] = 00100
+// 6 = [] = 00110
+// 8 = ) = 01000
+// 12 = ] = 01100
+// 16 = ( = 10000
+// 18 = [ = 10010
+// 24 = = 11000
+
+const emptyMask = 1
+const lowerInclusiveMask = 2
+const upperInclusiveMask = 4
+const lowerUnboundedMask = 8
+const upperUnboundedMask = 16
+
+func ParseUntypedBinaryRange(src []byte) (*UntypedBinaryRange, error) {
+ ubr := &UntypedBinaryRange{}
+
+ if len(src) == 0 {
+ return nil, fmt.Errorf("range too short: %v", len(src))
+ }
+
+ rangeType := src[0]
+ rp := 1
+
+ if rangeType&emptyMask > 0 {
+ if len(src[rp:]) > 0 {
+ return nil, fmt.Errorf("unexpected trailing bytes parsing empty range: %v", len(src[rp:]))
+ }
+ ubr.LowerType = Empty
+ ubr.UpperType = Empty
+ return ubr, nil
+ }
+
+ if rangeType&lowerInclusiveMask > 0 {
+ ubr.LowerType = Inclusive
+ } else if rangeType&lowerUnboundedMask > 0 {
+ ubr.LowerType = Unbounded
+ } else {
+ ubr.LowerType = Exclusive
+ }
+
+ if rangeType&upperInclusiveMask > 0 {
+ ubr.UpperType = Inclusive
+ } else if rangeType&upperUnboundedMask > 0 {
+ ubr.UpperType = Unbounded
+ } else {
+ ubr.UpperType = Exclusive
+ }
+
+ if ubr.LowerType == Unbounded && ubr.UpperType == Unbounded {
+ if len(src[rp:]) > 0 {
+ return nil, fmt.Errorf("unexpected trailing bytes parsing unbounded range: %v", len(src[rp:]))
+ }
+ return ubr, nil
+ }
+
+ if len(src[rp:]) < 4 {
+ return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
+ }
+ valueLen := int(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+
+ val := src[rp : rp+valueLen]
+ rp += valueLen
+
+ if ubr.LowerType != Unbounded {
+ ubr.Lower = val
+ } else {
+ ubr.Upper = val
+ if len(src[rp:]) > 0 {
+ return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
+ }
+ return ubr, nil
+ }
+
+ if ubr.UpperType != Unbounded {
+ if len(src[rp:]) < 4 {
+ return nil, fmt.Errorf("too few bytes for size: %v", src[rp:])
+ }
+ valueLen := int(binary.BigEndian.Uint32(src[rp:]))
+ rp += 4
+ ubr.Upper = src[rp : rp+valueLen]
+ rp += valueLen
+ }
+
+ if len(src[rp:]) > 0 {
+ return nil, fmt.Errorf("unexpected trailing bytes parsing range: %v", len(src[rp:]))
+ }
+
+ return ubr, nil
+
+}
diff --git a/vendor/github.com/jackc/pgtype/record.go b/vendor/github.com/jackc/pgtype/record.go
new file mode 100644
index 000000000..718c35702
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/record.go
@@ -0,0 +1,126 @@
+package pgtype
+
+import (
+ "fmt"
+ "reflect"
+)
+
+// Record is the generic PostgreSQL record type such as is created with the
+// "row" function. Record only implements BinaryEncoder and Value. The text
+// format output format from PostgreSQL does not include type information and is
+// therefore impossible to decode. No encoders are implemented because
+// PostgreSQL does not support input of generic records.
+type Record struct {
+ Fields []Value
+ Status Status
+}
+
+func (dst *Record) Set(src interface{}) error {
+ if src == nil {
+ *dst = Record{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case []Value:
+ *dst = Record{Fields: value, Status: Present}
+ default:
+ return fmt.Errorf("cannot convert %v to Record", src)
+ }
+
+ return nil
+}
+
+func (dst Record) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Fields
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Record) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *[]Value:
+ *v = make([]Value, len(src.Fields))
+ copy(*v, src.Fields)
+ return nil
+ case *[]interface{}:
+ *v = make([]interface{}, len(src.Fields))
+ for i := range *v {
+ (*v)[i] = src.Fields[i].Get()
+ }
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func prepareNewBinaryDecoder(ci *ConnInfo, fieldOID uint32, v *Value) (BinaryDecoder, error) {
+ var binaryDecoder BinaryDecoder
+
+ if dt, ok := ci.DataTypeForOID(fieldOID); ok {
+ binaryDecoder, _ = dt.Value.(BinaryDecoder)
+ } else {
+ return nil, fmt.Errorf("unknown oid while decoding record: %v", fieldOID)
+ }
+
+ if binaryDecoder == nil {
+ return nil, fmt.Errorf("no binary decoder registered for: %v", fieldOID)
+ }
+
+ // Duplicate struct to scan into
+ binaryDecoder = reflect.New(reflect.ValueOf(binaryDecoder).Elem().Type()).Interface().(BinaryDecoder)
+ *v = binaryDecoder.(Value)
+ return binaryDecoder, nil
+}
+
+func (dst *Record) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Record{Status: Null}
+ return nil
+ }
+
+ scanner := NewCompositeBinaryScanner(ci, src)
+
+ fields := make([]Value, scanner.FieldCount())
+
+ for i := 0; scanner.Next(); i++ {
+ binaryDecoder, err := prepareNewBinaryDecoder(ci, scanner.OID(), &fields[i])
+ if err != nil {
+ return err
+ }
+
+ if err = binaryDecoder.DecodeBinary(ci, scanner.Bytes()); err != nil {
+ return err
+ }
+ }
+
+ if scanner.Err() != nil {
+ return scanner.Err()
+ }
+
+ *dst = Record{Fields: fields, Status: Present}
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/text.go b/vendor/github.com/jackc/pgtype/text.go
new file mode 100644
index 000000000..6b01d1b49
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/text.go
@@ -0,0 +1,182 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+)
+
+type Text struct {
+ String string
+ Status Status
+}
+
+func (dst *Text) Set(src interface{}) error {
+ if src == nil {
+ *dst = Text{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case string:
+ *dst = Text{String: value, Status: Present}
+ case *string:
+ if value == nil {
+ *dst = Text{Status: Null}
+ } else {
+ *dst = Text{String: *value, Status: Present}
+ }
+ case []byte:
+ if value == nil {
+ *dst = Text{Status: Null}
+ } else {
+ *dst = Text{String: string(value), Status: Present}
+ }
+ default:
+ if originalSrc, ok := underlyingStringType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Text", value)
+ }
+
+ return nil
+}
+
+func (dst Text) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.String
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Text) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (Text) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *Text) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Text{Status: Null}
+ return nil
+ }
+
+ *dst = Text{String: string(src), Status: Present}
+ return nil
+}
+
+func (dst *Text) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return dst.DecodeText(ci, src)
+}
+
+func (Text) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src Text) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.String...), nil
+}
+
+func (src Text) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return src.EncodeText(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Text) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Text{Status: Null}
+ return 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 Text) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ return src.String, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Text) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ return json.Marshal(src.String)
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return nil, errBadStatus
+}
+
+func (dst *Text) UnmarshalJSON(b []byte) error {
+ var s *string
+ err := json.Unmarshal(b, &s)
+ if err != nil {
+ return err
+ }
+
+ if s == nil {
+ *dst = Text{Status: Null}
+ } else {
+ *dst = Text{String: *s, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/text_array.go b/vendor/github.com/jackc/pgtype/text_array.go
new file mode 100644
index 000000000..2461966b3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/text_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type TextArray struct {
+ Elements []Text
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *TextArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = TextArray{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 = TextArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TextArray{Status: Present}
+ } else {
+ elements := make([]Text, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TextArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = TextArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TextArray{Status: Present}
+ } else {
+ elements := make([]Text, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TextArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Text:
+ if value == nil {
+ *dst = TextArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TextArray{Status: Present}
+ } else {
+ *dst = TextArray{
+ 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 = TextArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for TextArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = TextArray{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 TextArray", src)
+ }
+
+ *dst = TextArray{
+ Elements: make([]Text, 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([]Text, 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 TextArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *TextArray) 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 TextArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in TextArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst TextArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TextArray) 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 *[]*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
+
+ }
+ }
+
+ // 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 *TextArray) 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 TextArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from TextArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *TextArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TextArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Text
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Text, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Text
+ 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 = TextArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *TextArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TextArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = TextArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Text, 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 = TextArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src TextArray) 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 TextArray) 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("text"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "text")
+ }
+
+ 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 *TextArray) 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 TextArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/tid.go b/vendor/github.com/jackc/pgtype/tid.go
new file mode 100644
index 000000000..4bb57f643
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/tid.go
@@ -0,0 +1,156 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/jackc/pgio"
+)
+
+// TID is PostgreSQL's Tuple Identifier type.
+//
+// When one does
+//
+// select ctid, * from some_table;
+//
+// it is the data type of the ctid hidden system column.
+//
+// It is currently implemented as a pair unsigned two byte integers.
+// Its conversion functions can be found in src/backend/utils/adt/tid.c
+// in the PostgreSQL sources.
+type TID struct {
+ BlockNumber uint32
+ OffsetNumber uint16
+ Status Status
+}
+
+func (dst *TID) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to TID", src)
+}
+
+func (dst TID) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TID) AssignTo(dst interface{}) error {
+ if src.Status == Present {
+ switch v := dst.(type) {
+ case *string:
+ *v = fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber)
+ return nil
+ default:
+ if nextDst, retry := GetAssignToDstType(dst); retry {
+ return src.AssignTo(nextDst)
+ }
+ return fmt.Errorf("unable to assign to %T", dst)
+ }
+ }
+
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *TID) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TID{Status: Null}
+ return nil
+ }
+
+ if len(src) < 5 {
+ return fmt.Errorf("invalid length for tid: %v", len(src))
+ }
+
+ parts := strings.SplitN(string(src[1:len(src)-1]), ",", 2)
+ if len(parts) < 2 {
+ return fmt.Errorf("invalid format for tid")
+ }
+
+ blockNumber, err := strconv.ParseUint(parts[0], 10, 32)
+ if err != nil {
+ return err
+ }
+
+ offsetNumber, err := strconv.ParseUint(parts[1], 10, 16)
+ if err != nil {
+ return err
+ }
+
+ *dst = TID{BlockNumber: uint32(blockNumber), OffsetNumber: uint16(offsetNumber), Status: Present}
+ return nil
+}
+
+func (dst *TID) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TID{Status: Null}
+ return nil
+ }
+
+ if len(src) != 6 {
+ return fmt.Errorf("invalid length for tid: %v", len(src))
+ }
+
+ *dst = TID{
+ BlockNumber: binary.BigEndian.Uint32(src),
+ OffsetNumber: binary.BigEndian.Uint16(src[4:]),
+ Status: Present,
+ }
+ return nil
+}
+
+func (src TID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = append(buf, fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber)...)
+ return buf, nil
+}
+
+func (src TID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendUint32(buf, src.BlockNumber)
+ buf = pgio.AppendUint16(buf, src.OffsetNumber)
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *TID) Scan(src interface{}) error {
+ if src == nil {
+ *dst = TID{Status: Null}
+ return 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 TID) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/time.go b/vendor/github.com/jackc/pgtype/time.go
new file mode 100644
index 000000000..f7a28870a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/time.go
@@ -0,0 +1,231 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "strconv"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+// Time represents the PostgreSQL time type. The PostgreSQL time is a time of day without time zone.
+//
+// Time is represented as the number of microseconds since midnight in the same way that PostgreSQL does. Other time
+// and date types in pgtype can use time.Time as the underlying representation. However, pgtype.Time type cannot due
+// to needing to handle 24:00:00. time.Time converts that to 00:00:00 on the following day.
+type Time struct {
+ Microseconds int64 // Number of microseconds since midnight
+ Status Status
+}
+
+// Set converts src into a Time and stores in dst.
+func (dst *Time) Set(src interface{}) error {
+ if src == nil {
+ *dst = Time{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case time.Time:
+ usec := int64(value.Hour())*microsecondsPerHour +
+ int64(value.Minute())*microsecondsPerMinute +
+ int64(value.Second())*microsecondsPerSecond +
+ int64(value.Nanosecond())/1000
+ *dst = Time{Microseconds: usec, Status: Present}
+ case *time.Time:
+ if value == nil {
+ *dst = Time{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingTimeType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Time", value)
+ }
+
+ return nil
+}
+
+func (dst Time) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Microseconds
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Time) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *time.Time:
+ // 24:00:00 is max allowed time in PostgreSQL, but time.Time will normalize that to 00:00:00 the next day.
+ var maxRepresentableByTime int64 = 24*60*60*1000000 - 1
+ if src.Microseconds > maxRepresentableByTime {
+ return fmt.Errorf("%d microseconds cannot be represented as time.Time", src.Microseconds)
+ }
+
+ usec := src.Microseconds
+ hours := usec / microsecondsPerHour
+ usec -= hours * microsecondsPerHour
+ minutes := usec / microsecondsPerMinute
+ usec -= minutes * microsecondsPerMinute
+ seconds := usec / microsecondsPerSecond
+ usec -= seconds * microsecondsPerSecond
+ ns := usec * 1000
+ *v = time.Date(2000, 1, 1, int(hours), int(minutes), int(seconds), int(ns), time.UTC)
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+// DecodeText decodes from src into dst.
+func (dst *Time) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Time{Status: Null}
+ return nil
+ }
+
+ s := string(src)
+
+ if len(s) < 8 {
+ return fmt.Errorf("cannot decode %v into Time", s)
+ }
+
+ hours, err := strconv.ParseInt(s[0:2], 10, 64)
+ if err != nil {
+ return fmt.Errorf("cannot decode %v into Time", s)
+ }
+ usec := hours * microsecondsPerHour
+
+ minutes, err := strconv.ParseInt(s[3:5], 10, 64)
+ if err != nil {
+ return fmt.Errorf("cannot decode %v into Time", s)
+ }
+ usec += minutes * microsecondsPerMinute
+
+ seconds, err := strconv.ParseInt(s[6:8], 10, 64)
+ if err != nil {
+ return fmt.Errorf("cannot decode %v into Time", s)
+ }
+ usec += seconds * microsecondsPerSecond
+
+ if len(s) > 9 {
+ fraction := s[9:]
+ n, err := strconv.ParseInt(fraction, 10, 64)
+ if err != nil {
+ return fmt.Errorf("cannot decode %v into Time", s)
+ }
+
+ for i := len(fraction); i < 6; i++ {
+ n *= 10
+ }
+
+ usec += n
+ }
+
+ *dst = Time{Microseconds: usec, Status: Present}
+
+ return nil
+}
+
+// DecodeBinary decodes from src into dst.
+func (dst *Time) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Time{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for time: %v", len(src))
+ }
+
+ usec := int64(binary.BigEndian.Uint64(src))
+ *dst = Time{Microseconds: usec, Status: Present}
+
+ return nil
+}
+
+// EncodeText writes the text encoding of src into w.
+func (src Time) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ usec := src.Microseconds
+ hours := usec / microsecondsPerHour
+ usec -= hours * microsecondsPerHour
+ minutes := usec / microsecondsPerMinute
+ usec -= minutes * microsecondsPerMinute
+ seconds := usec / microsecondsPerSecond
+ usec -= seconds * microsecondsPerSecond
+
+ s := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, usec)
+
+ return append(buf, s...), nil
+}
+
+// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
+// the UTC time zone it returns an error.
+func (src Time) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return pgio.AppendInt64(buf, src.Microseconds), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Time) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Time{Status: Null}
+ return 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)
+ case time.Time:
+ return dst.Set(src)
+ }
+
+ return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Time) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/timestamp.go b/vendor/github.com/jackc/pgtype/timestamp.go
new file mode 100644
index 000000000..466441158
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/timestamp.go
@@ -0,0 +1,241 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+const pgTimestampFormat = "2006-01-02 15:04:05.999999999"
+
+// Timestamp represents the PostgreSQL timestamp type. The PostgreSQL
+// timestamp does not have a time zone. This presents a problem when
+// translating to and from time.Time which requires a time zone. It is highly
+// recommended to use timestamptz whenever possible. Timestamp methods either
+// convert to UTC or return an error on non-UTC times.
+type Timestamp struct {
+ Time time.Time // Time must always be in UTC.
+ Status Status
+ InfinityModifier InfinityModifier
+}
+
+// Set converts src into a Timestamp and stores in dst. If src is a
+// time.Time in a non-UTC time zone, the time zone is discarded.
+func (dst *Timestamp) Set(src interface{}) error {
+ if src == nil {
+ *dst = Timestamp{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case time.Time:
+ *dst = Timestamp{Time: time.Date(value.Year(), value.Month(), value.Day(), value.Hour(), value.Minute(), value.Second(), value.Nanosecond(), time.UTC), Status: Present}
+ case *time.Time:
+ if value == nil {
+ *dst = Timestamp{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case InfinityModifier:
+ *dst = Timestamp{InfinityModifier: value, Status: Present}
+ default:
+ if originalSrc, ok := underlyingTimeType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Timestamp", value)
+ }
+
+ return nil
+}
+
+func (dst Timestamp) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ if dst.InfinityModifier != None {
+ return dst.InfinityModifier
+ }
+ return dst.Time
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Timestamp) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *time.Time:
+ if src.InfinityModifier != None {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+ }
+ *v = src.Time
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+// DecodeText decodes from src into dst. The decoded time is considered to
+// be in UTC.
+func (dst *Timestamp) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Timestamp{Status: Null}
+ return nil
+ }
+
+ sbuf := string(src)
+ switch sbuf {
+ case "infinity":
+ *dst = Timestamp{Status: Present, InfinityModifier: Infinity}
+ case "-infinity":
+ *dst = Timestamp{Status: Present, InfinityModifier: -Infinity}
+ default:
+ tim, err := time.Parse(pgTimestampFormat, sbuf)
+ if err != nil {
+ return err
+ }
+
+ *dst = Timestamp{Time: tim, Status: Present}
+ }
+
+ return nil
+}
+
+// DecodeBinary decodes from src into dst. The decoded time is considered to
+// be in UTC.
+func (dst *Timestamp) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Timestamp{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for timestamp: %v", len(src))
+ }
+
+ microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
+
+ switch microsecSinceY2K {
+ case infinityMicrosecondOffset:
+ *dst = Timestamp{Status: Present, InfinityModifier: Infinity}
+ case negativeInfinityMicrosecondOffset:
+ *dst = Timestamp{Status: Present, InfinityModifier: -Infinity}
+ default:
+ microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K
+ tim := time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000).UTC()
+ *dst = Timestamp{Time: tim, Status: Present}
+ }
+
+ return nil
+}
+
+// EncodeText writes the text encoding of src into w. If src.Time is not in
+// the UTC time zone it returns an error.
+func (src Timestamp) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+ if src.Time.Location() != time.UTC {
+ return nil, fmt.Errorf("cannot encode non-UTC time into timestamp")
+ }
+
+ var s string
+
+ switch src.InfinityModifier {
+ case None:
+ s = src.Time.Truncate(time.Microsecond).Format(pgTimestampFormat)
+ case Infinity:
+ s = "infinity"
+ case NegativeInfinity:
+ s = "-infinity"
+ }
+
+ return append(buf, s...), nil
+}
+
+// EncodeBinary writes the binary encoding of src into w. If src.Time is not in
+// the UTC time zone it returns an error.
+func (src Timestamp) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+ if src.Time.Location() != time.UTC {
+ return nil, fmt.Errorf("cannot encode non-UTC time into timestamp")
+ }
+
+ var microsecSinceY2K int64
+ switch src.InfinityModifier {
+ case None:
+ microsecSinceUnixEpoch := src.Time.Unix()*1000000 + int64(src.Time.Nanosecond())/1000
+ microsecSinceY2K = microsecSinceUnixEpoch - microsecFromUnixEpochToY2K
+ case Infinity:
+ microsecSinceY2K = infinityMicrosecondOffset
+ case NegativeInfinity:
+ microsecSinceY2K = negativeInfinityMicrosecondOffset
+ }
+
+ return pgio.AppendInt64(buf, microsecSinceY2K), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Timestamp) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Timestamp{Status: Null}
+ return 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)
+ case time.Time:
+ *dst = Timestamp{Time: src, Status: Present}
+ return nil
+ }
+
+ return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Timestamp) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ if src.InfinityModifier != None {
+ return src.InfinityModifier.String(), nil
+ }
+ return src.Time, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
diff --git a/vendor/github.com/jackc/pgtype/timestamp_array.go b/vendor/github.com/jackc/pgtype/timestamp_array.go
new file mode 100644
index 000000000..e12481e3d
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/timestamp_array.go
@@ -0,0 +1,518 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+type TimestampArray struct {
+ Elements []Timestamp
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *TimestampArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = TimestampArray{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 []time.Time:
+ if value == nil {
+ *dst = TimestampArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestampArray{Status: Present}
+ } else {
+ elements := make([]Timestamp, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TimestampArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*time.Time:
+ if value == nil {
+ *dst = TimestampArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestampArray{Status: Present}
+ } else {
+ elements := make([]Timestamp, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TimestampArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Timestamp:
+ if value == nil {
+ *dst = TimestampArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestampArray{Status: Present}
+ } else {
+ *dst = TimestampArray{
+ 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 = TimestampArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for TimestampArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = TimestampArray{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 TimestampArray", src)
+ }
+
+ *dst = TimestampArray{
+ Elements: make([]Timestamp, 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([]Timestamp, 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 TimestampArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *TimestampArray) 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 TimestampArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in TimestampArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst TimestampArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TimestampArray) 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 *[]time.Time:
+ *v = make([]time.Time, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*time.Time:
+ *v = make([]*time.Time, 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 *TimestampArray) 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 TimestampArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from TimestampArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *TimestampArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TimestampArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Timestamp
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Timestamp, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Timestamp
+ 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 = TimestampArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *TimestampArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TimestampArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = TimestampArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Timestamp, 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 = TimestampArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src TimestampArray) 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 TimestampArray) 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("timestamp"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "timestamp")
+ }
+
+ 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 *TimestampArray) 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 TimestampArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/timestamptz.go b/vendor/github.com/jackc/pgtype/timestamptz.go
new file mode 100644
index 000000000..e0743060b
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/timestamptz.go
@@ -0,0 +1,294 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+const pgTimestamptzHourFormat = "2006-01-02 15:04:05.999999999Z07"
+const pgTimestamptzMinuteFormat = "2006-01-02 15:04:05.999999999Z07:00"
+const pgTimestamptzSecondFormat = "2006-01-02 15:04:05.999999999Z07:00:00"
+const microsecFromUnixEpochToY2K = 946684800 * 1000000
+
+const (
+ negativeInfinityMicrosecondOffset = -9223372036854775808
+ infinityMicrosecondOffset = 9223372036854775807
+)
+
+type Timestamptz struct {
+ Time time.Time
+ Status Status
+ InfinityModifier InfinityModifier
+}
+
+func (dst *Timestamptz) Set(src interface{}) error {
+ if src == nil {
+ *dst = Timestamptz{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case time.Time:
+ *dst = Timestamptz{Time: value, Status: Present}
+ case *time.Time:
+ if value == nil {
+ *dst = Timestamptz{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ case InfinityModifier:
+ *dst = Timestamptz{InfinityModifier: value, Status: Present}
+ default:
+ if originalSrc, ok := underlyingTimeType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to Timestamptz", value)
+ }
+
+ return nil
+}
+
+func (dst Timestamptz) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ if dst.InfinityModifier != None {
+ return dst.InfinityModifier
+ }
+ return dst.Time
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Timestamptz) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *time.Time:
+ if src.InfinityModifier != None {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+ }
+ *v = src.Time
+ 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 fmt.Errorf("cannot decode %#v into %T", src, dst)
+}
+
+func (dst *Timestamptz) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Timestamptz{Status: Null}
+ return nil
+ }
+
+ sbuf := string(src)
+ switch sbuf {
+ case "infinity":
+ *dst = Timestamptz{Status: Present, InfinityModifier: Infinity}
+ case "-infinity":
+ *dst = Timestamptz{Status: Present, InfinityModifier: -Infinity}
+ default:
+ var format string
+ if len(sbuf) >= 9 && (sbuf[len(sbuf)-9] == '-' || sbuf[len(sbuf)-9] == '+') {
+ format = pgTimestamptzSecondFormat
+ } else if len(sbuf) >= 6 && (sbuf[len(sbuf)-6] == '-' || sbuf[len(sbuf)-6] == '+') {
+ format = pgTimestamptzMinuteFormat
+ } else {
+ format = pgTimestamptzHourFormat
+ }
+
+ tim, err := time.Parse(format, sbuf)
+ if err != nil {
+ return err
+ }
+
+ *dst = Timestamptz{Time: tim, Status: Present}
+ }
+
+ return nil
+}
+
+func (dst *Timestamptz) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Timestamptz{Status: Null}
+ return nil
+ }
+
+ if len(src) != 8 {
+ return fmt.Errorf("invalid length for timestamptz: %v", len(src))
+ }
+
+ microsecSinceY2K := int64(binary.BigEndian.Uint64(src))
+
+ switch microsecSinceY2K {
+ case infinityMicrosecondOffset:
+ *dst = Timestamptz{Status: Present, InfinityModifier: Infinity}
+ case negativeInfinityMicrosecondOffset:
+ *dst = Timestamptz{Status: Present, InfinityModifier: -Infinity}
+ default:
+ microsecSinceUnixEpoch := microsecFromUnixEpochToY2K + microsecSinceY2K
+ tim := time.Unix(microsecSinceUnixEpoch/1000000, (microsecSinceUnixEpoch%1000000)*1000)
+ *dst = Timestamptz{Time: tim, Status: Present}
+ }
+
+ return nil
+}
+
+func (src Timestamptz) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var s string
+
+ switch src.InfinityModifier {
+ case None:
+ s = src.Time.UTC().Truncate(time.Microsecond).Format(pgTimestamptzSecondFormat)
+ case Infinity:
+ s = "infinity"
+ case NegativeInfinity:
+ s = "-infinity"
+ }
+
+ return append(buf, s...), nil
+}
+
+func (src Timestamptz) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var microsecSinceY2K int64
+ switch src.InfinityModifier {
+ case None:
+ microsecSinceUnixEpoch := src.Time.Unix()*1000000 + int64(src.Time.Nanosecond())/1000
+ microsecSinceY2K = microsecSinceUnixEpoch - microsecFromUnixEpochToY2K
+ case Infinity:
+ microsecSinceY2K = infinityMicrosecondOffset
+ case NegativeInfinity:
+ microsecSinceY2K = negativeInfinityMicrosecondOffset
+ }
+
+ return pgio.AppendInt64(buf, microsecSinceY2K), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Timestamptz) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Timestamptz{Status: Null}
+ return 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)
+ case time.Time:
+ *dst = Timestamptz{Time: src, Status: Present}
+ return nil
+ }
+
+ return fmt.Errorf("cannot scan %T", src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Timestamptz) Value() (driver.Value, error) {
+ switch src.Status {
+ case Present:
+ if src.InfinityModifier != None {
+ return src.InfinityModifier.String(), nil
+ }
+ return src.Time, nil
+ case Null:
+ return nil, nil
+ default:
+ return nil, errUndefined
+ }
+}
+
+func (src Timestamptz) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ if src.Status != Present {
+ return nil, errBadStatus
+ }
+
+ var s string
+
+ switch src.InfinityModifier {
+ case None:
+ s = src.Time.Format(time.RFC3339Nano)
+ case Infinity:
+ s = "infinity"
+ case NegativeInfinity:
+ s = "-infinity"
+ }
+
+ return json.Marshal(s)
+}
+
+func (dst *Timestamptz) UnmarshalJSON(b []byte) error {
+ var s *string
+ err := json.Unmarshal(b, &s)
+ if err != nil {
+ return err
+ }
+
+ if s == nil {
+ *dst = Timestamptz{Status: Null}
+ return nil
+ }
+
+ switch *s {
+ case "infinity":
+ *dst = Timestamptz{Status: Present, InfinityModifier: Infinity}
+ case "-infinity":
+ *dst = Timestamptz{Status: Present, InfinityModifier: -Infinity}
+ default:
+ // PostgreSQL uses ISO 8601 for to_json function and casting from a string to timestamptz
+ tim, err := time.Parse(time.RFC3339Nano, *s)
+ if err != nil {
+ return err
+ }
+
+ *dst = Timestamptz{Time: tim, Status: Present}
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgtype/timestamptz_array.go b/vendor/github.com/jackc/pgtype/timestamptz_array.go
new file mode 100644
index 000000000..a3b4b263d
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/timestamptz_array.go
@@ -0,0 +1,518 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "time"
+
+ "github.com/jackc/pgio"
+)
+
+type TimestamptzArray struct {
+ Elements []Timestamptz
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *TimestamptzArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = TimestamptzArray{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 []time.Time:
+ if value == nil {
+ *dst = TimestamptzArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestamptzArray{Status: Present}
+ } else {
+ elements := make([]Timestamptz, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TimestamptzArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*time.Time:
+ if value == nil {
+ *dst = TimestamptzArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestamptzArray{Status: Present}
+ } else {
+ elements := make([]Timestamptz, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = TimestamptzArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Timestamptz:
+ if value == nil {
+ *dst = TimestamptzArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TimestamptzArray{Status: Present}
+ } else {
+ *dst = TimestamptzArray{
+ 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 = TimestamptzArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for TimestamptzArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = TimestamptzArray{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 TimestamptzArray", src)
+ }
+
+ *dst = TimestamptzArray{
+ Elements: make([]Timestamptz, 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([]Timestamptz, 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 TimestamptzArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *TimestamptzArray) 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 TimestamptzArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in TimestamptzArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst TimestamptzArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TimestamptzArray) 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 *[]time.Time:
+ *v = make([]time.Time, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+
+ case *[]*time.Time:
+ *v = make([]*time.Time, 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 *TimestamptzArray) 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 TimestamptzArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from TimestamptzArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *TimestamptzArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TimestamptzArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Timestamptz
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Timestamptz, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Timestamptz
+ 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 = TimestamptzArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *TimestamptzArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TimestamptzArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = TimestamptzArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Timestamptz, 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 = TimestamptzArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src TimestamptzArray) 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 TimestamptzArray) 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("timestamptz"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "timestamptz")
+ }
+
+ 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 *TimestamptzArray) 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 TimestamptzArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/tsrange.go b/vendor/github.com/jackc/pgtype/tsrange.go
new file mode 100644
index 000000000..19ecf446a
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/tsrange.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Tsrange struct {
+ Lower Timestamp
+ Upper Timestamp
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Tsrange) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Tsrange{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Tsrange:
+ *dst = value
+ case *Tsrange:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Tsrange", src)
+ }
+
+ return nil
+}
+
+func (dst Tsrange) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Tsrange) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Tsrange) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Tsrange{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Tsrange{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Tsrange) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Tsrange{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Tsrange{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Tsrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Tsrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Tsrange) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Tsrange{Status: Null}
+ return 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 Tsrange) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/tsrange_array.go b/vendor/github.com/jackc/pgtype/tsrange_array.go
new file mode 100644
index 000000000..c64048eb0
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/tsrange_array.go
@@ -0,0 +1,470 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type TsrangeArray struct {
+ Elements []Tsrange
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *TsrangeArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = TsrangeArray{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 []Tsrange:
+ if value == nil {
+ *dst = TsrangeArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TsrangeArray{Status: Present}
+ } else {
+ *dst = TsrangeArray{
+ 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 = TsrangeArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for TsrangeArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = TsrangeArray{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 TsrangeArray", src)
+ }
+
+ *dst = TsrangeArray{
+ Elements: make([]Tsrange, 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([]Tsrange, 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 TsrangeArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *TsrangeArray) 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 TsrangeArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in TsrangeArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst TsrangeArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TsrangeArray) 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 *[]Tsrange:
+ *v = make([]Tsrange, 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 *TsrangeArray) 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 TsrangeArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from TsrangeArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *TsrangeArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TsrangeArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Tsrange
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Tsrange, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Tsrange
+ 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 = TsrangeArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *TsrangeArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TsrangeArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = TsrangeArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Tsrange, 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 = TsrangeArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src TsrangeArray) 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 TsrangeArray) 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("tsrange"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "tsrange")
+ }
+
+ 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 *TsrangeArray) 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 TsrangeArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/tstzrange.go b/vendor/github.com/jackc/pgtype/tstzrange.go
new file mode 100644
index 000000000..255763081
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/tstzrange.go
@@ -0,0 +1,267 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Tstzrange struct {
+ Lower Timestamptz
+ Upper Timestamptz
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *Tstzrange) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = Tstzrange{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case Tstzrange:
+ *dst = value
+ case *Tstzrange:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to Tstzrange", src)
+ }
+
+ return nil
+}
+
+func (dst Tstzrange) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Tstzrange) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Tstzrange) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Tstzrange{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = Tstzrange{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *Tstzrange) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Tstzrange{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = Tstzrange{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src Tstzrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src Tstzrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Tstzrange) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Tstzrange{Status: Null}
+ return 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 Tstzrange) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/tstzrange_array.go b/vendor/github.com/jackc/pgtype/tstzrange_array.go
new file mode 100644
index 000000000..a216820a3
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/tstzrange_array.go
@@ -0,0 +1,470 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type TstzrangeArray struct {
+ Elements []Tstzrange
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *TstzrangeArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = TstzrangeArray{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 []Tstzrange:
+ if value == nil {
+ *dst = TstzrangeArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = TstzrangeArray{Status: Present}
+ } else {
+ *dst = TstzrangeArray{
+ 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 = TstzrangeArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for TstzrangeArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = TstzrangeArray{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 TstzrangeArray", src)
+ }
+
+ *dst = TstzrangeArray{
+ Elements: make([]Tstzrange, 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([]Tstzrange, 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 TstzrangeArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *TstzrangeArray) 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 TstzrangeArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in TstzrangeArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst TstzrangeArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *TstzrangeArray) 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 *[]Tstzrange:
+ *v = make([]Tstzrange, 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 *TstzrangeArray) 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 TstzrangeArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from TstzrangeArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *TstzrangeArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TstzrangeArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Tstzrange
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Tstzrange, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Tstzrange
+ 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 = TstzrangeArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *TstzrangeArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = TstzrangeArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = TstzrangeArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Tstzrange, 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 = TstzrangeArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src TstzrangeArray) 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 TstzrangeArray) 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("tstzrange"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "tstzrange")
+ }
+
+ 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 *TstzrangeArray) 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 TstzrangeArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/typed_array.go.erb b/vendor/github.com/jackc/pgtype/typed_array.go.erb
new file mode 100644
index 000000000..5788626b4
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/typed_array.go.erb
@@ -0,0 +1,494 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+
+ "github.com/jackc/pgio"
+)
+
+type <%= pgtype_array_type %> struct {
+ Elements []<%= pgtype_element_type %>
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *<%= pgtype_array_type %>) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = <%= pgtype_array_type %>{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) {
+ <% go_array_types.split(",").each do |t| %>
+ <% if t != "[]#{pgtype_element_type}" %>
+ case <%= t %>:
+ if value == nil {
+ *dst = <%= pgtype_array_type %>{Status: Null}
+ } else if len(value) == 0 {
+ *dst = <%= pgtype_array_type %>{Status: Present}
+ } else {
+ elements := make([]<%= pgtype_element_type %>, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = <%= pgtype_array_type %>{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+ <% end %>
+ <% end %>
+ case []<%= pgtype_element_type %>:
+ if value == nil {
+ *dst = <%= pgtype_array_type %>{Status: Null}
+ } else if len(value) == 0 {
+ *dst = <%= pgtype_array_type %>{Status: Present}
+ } else {
+ *dst = <%= pgtype_array_type %>{
+ 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 = <%= pgtype_array_type %>{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for <%= pgtype_array_type %>", src)
+ }
+ if elementsLength == 0 {
+ *dst = <%= pgtype_array_type %>{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 <%= pgtype_array_type %>", src)
+ }
+
+ *dst = <%= pgtype_array_type %> {
+ Elements: make([]<%= pgtype_element_type %>, 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([]<%= pgtype_element_type %>, 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 <%= pgtype_array_type %>, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *<%= pgtype_array_type %>) 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 <%= pgtype_array_type %>")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in <%= pgtype_array_type %>", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst <%= pgtype_array_type %>) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *<%= pgtype_array_type %>) 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) {
+ <% go_array_types.split(",").each do |t| %>
+ case *<%= t %>:
+ *v = make(<%= t %>, len(src.Elements))
+ for i := range src.Elements {
+ if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
+ return err
+ }
+ }
+ return nil
+ <% end %>
+ }
+ }
+
+ // 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 *<%= pgtype_array_type %>) 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 <%= pgtype_array_type %>")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from <%= pgtype_array_type %>")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *<%= pgtype_array_type %>) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = <%= pgtype_array_type %>{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []<%= pgtype_element_type %>
+
+ if len(uta.Elements) > 0 {
+ elements = make([]<%= pgtype_element_type %>, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem <%= pgtype_element_type %>
+ 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 = <%= pgtype_array_type %>{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+<% if binary_format == "true" %>
+func (dst *<%= pgtype_array_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = <%= pgtype_array_type %>{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = <%= pgtype_array_type %>{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]<%= pgtype_element_type %>, 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 = <%= pgtype_array_type %>{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+<% end %>
+
+func (src <%= pgtype_array_type %>) 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, `<%= text_null %>`...)
+ } else {
+ buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
+ }
+
+ for _, dec := range dimElemCounts {
+ if (i+1)%dec == 0 {
+ buf = append(buf, '}')
+ }
+ }
+ }
+
+ return buf, nil
+}
+
+<% if binary_format == "true" %>
+ func (src <%= pgtype_array_type %>) 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("<%= element_type_name %>"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "<%= element_type_name %>")
+ }
+
+ 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
+ }
+<% end %>
+
+// Scan implements the database/sql Scanner interface.
+func (dst *<%= pgtype_array_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 <%= pgtype_array_type %>) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/typed_array_gen.sh b/vendor/github.com/jackc/pgtype/typed_array_gen.sh
new file mode 100644
index 000000000..ea28be077
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/typed_array_gen.sh
@@ -0,0 +1,28 @@
+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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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=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
+
+# 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
+
+goimports -w *_array.go
diff --git a/vendor/github.com/jackc/pgtype/typed_range.go.erb b/vendor/github.com/jackc/pgtype/typed_range.go.erb
new file mode 100644
index 000000000..5625587ae
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/typed_range.go.erb
@@ -0,0 +1,269 @@
+package pgtype
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "fmt"
+ "io"
+
+ "github.com/jackc/pgio"
+)
+
+type <%= range_type %> struct {
+ Lower <%= element_type %>
+ Upper <%= element_type %>
+ LowerType BoundType
+ UpperType BoundType
+ Status Status
+}
+
+func (dst *<%= range_type %>) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = <%= range_type %>{Status: Null}
+ return nil
+ }
+
+ switch value := src.(type) {
+ case <%= range_type %>:
+ *dst = value
+ case *<%= range_type %>:
+ *dst = *value
+ case string:
+ return dst.DecodeText(nil, []byte(value))
+ default:
+ return fmt.Errorf("cannot convert %v to <%= range_type %>", src)
+ }
+
+ return nil
+}
+
+func (dst <%= range_type %>) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *<%= range_type %>) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *<%= range_type %>) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = <%= range_type %>{Status: Null}
+ return nil
+ }
+
+ utr, err := ParseUntypedTextRange(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = <%= range_type %>{Status: Present}
+
+ dst.LowerType = utr.LowerType
+ dst.UpperType = utr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (dst *<%= range_type %>) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = <%= range_type %>{Status: Null}
+ return nil
+ }
+
+ ubr, err := ParseUntypedBinaryRange(src)
+ if err != nil {
+ return err
+ }
+
+ *dst = <%= range_type %>{Status: Present}
+
+ dst.LowerType = ubr.LowerType
+ dst.UpperType = ubr.UpperType
+
+ if dst.LowerType == Empty {
+ return nil
+ }
+
+ if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
+ if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
+ return err
+ }
+ }
+
+ if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
+ if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (src <%= range_type %>) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ switch src.LowerType {
+ case Exclusive, Unbounded:
+ buf = append(buf, '(')
+ case Inclusive:
+ buf = append(buf, '[')
+ case Empty:
+ return append(buf, "empty"...), nil
+ default:
+ return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
+ }
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ buf, err = src.Lower.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+ }
+
+ buf = append(buf, ',')
+
+ if src.UpperType != Unbounded {
+ buf, err = src.Upper.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ } else if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+ }
+
+ switch src.UpperType {
+ case Exclusive, Unbounded:
+ buf = append(buf, ')')
+ case Inclusive:
+ buf = append(buf, ']')
+ default:
+ return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
+ }
+
+ return buf, nil
+}
+
+func (src <%= range_type %>) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ var rangeType byte
+ switch src.LowerType {
+ case Inclusive:
+ rangeType |= lowerInclusiveMask
+ case Unbounded:
+ rangeType |= lowerUnboundedMask
+ case Exclusive:
+ case Empty:
+ return append(buf, emptyMask), nil
+ default:
+ return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
+ }
+
+ switch src.UpperType {
+ case Inclusive:
+ rangeType |= upperInclusiveMask
+ case Unbounded:
+ rangeType |= upperUnboundedMask
+ case Exclusive:
+ default:
+ return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
+ }
+
+ buf = append(buf, rangeType)
+
+ var err error
+
+ if src.LowerType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Lower.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ if src.UpperType != Unbounded {
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+
+ buf, err = src.Upper.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
+ }
+
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+
+ return buf, nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *<%= range_type %>) Scan(src interface{}) error {
+ if src == nil {
+ *dst = <%= range_type %>{Status: Null}
+ return 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 <%= range_type %>) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/typed_range_gen.sh b/vendor/github.com/jackc/pgtype/typed_range_gen.sh
new file mode 100644
index 000000000..bedda2925
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/typed_range_gen.sh
@@ -0,0 +1,7 @@
+erb range_type=Int4range element_type=Int4 typed_range.go.erb > int4range.go
+erb range_type=Int8range element_type=Int8 typed_range.go.erb > int8range.go
+erb range_type=Tsrange element_type=Timestamp typed_range.go.erb > tsrange.go
+erb range_type=Tstzrange element_type=Timestamptz typed_range.go.erb > tstzrange.go
+erb range_type=Daterange element_type=Date typed_range.go.erb > daterange.go
+erb range_type=Numrange element_type=Numeric typed_range.go.erb > numrange.go
+goimports -w *range.go
diff --git a/vendor/github.com/jackc/pgtype/unknown.go b/vendor/github.com/jackc/pgtype/unknown.go
new file mode 100644
index 000000000..c591b7083
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/unknown.go
@@ -0,0 +1,44 @@
+package pgtype
+
+import "database/sql/driver"
+
+// Unknown represents the PostgreSQL unknown type. It is either a string literal
+// or NULL. It is used when PostgreSQL does not know the type of a value. In
+// general, this will only be used in pgx when selecting a null value without
+// type information. e.g. SELECT NULL;
+type Unknown struct {
+ String string
+ Status Status
+}
+
+func (dst *Unknown) Set(src interface{}) error {
+ return (*Text)(dst).Set(src)
+}
+
+func (dst Unknown) Get() interface{} {
+ return (Text)(dst).Get()
+}
+
+// AssignTo assigns from src to dst. Note that as Unknown is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *Unknown) AssignTo(dst interface{}) error {
+ return (*Text)(src).AssignTo(dst)
+}
+
+func (dst *Unknown) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeText(ci, src)
+}
+
+func (dst *Unknown) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeBinary(ci, src)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Unknown) Scan(src interface{}) error {
+ return (*Text)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Unknown) Value() (driver.Value, error) {
+ return (Text)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgtype/uuid.go b/vendor/github.com/jackc/pgtype/uuid.go
new file mode 100644
index 000000000..fa0be07fe
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/uuid.go
@@ -0,0 +1,230 @@
+package pgtype
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/hex"
+ "fmt"
+)
+
+type UUID struct {
+ Bytes [16]byte
+ Status Status
+}
+
+func (dst *UUID) Set(src interface{}) error {
+ if src == nil {
+ *dst = UUID{Status: Null}
+ return nil
+ }
+
+ if value, ok := src.(interface{ Get() interface{} }); ok {
+ value2 := value.Get()
+ if value2 != value {
+ return dst.Set(value2)
+ }
+ }
+
+ switch value := src.(type) {
+ case [16]byte:
+ *dst = UUID{Bytes: value, Status: Present}
+ case []byte:
+ if value != nil {
+ if len(value) != 16 {
+ return fmt.Errorf("[]byte must be 16 bytes to convert to UUID: %d", len(value))
+ }
+ *dst = UUID{Status: Present}
+ copy(dst.Bytes[:], value)
+ } else {
+ *dst = UUID{Status: Null}
+ }
+ case string:
+ uuid, err := parseUUID(value)
+ if err != nil {
+ return err
+ }
+ *dst = UUID{Bytes: uuid, Status: Present}
+ case *string:
+ if value == nil {
+ *dst = UUID{Status: Null}
+ } else {
+ return dst.Set(*value)
+ }
+ default:
+ if originalSrc, ok := underlyingUUIDType(src); ok {
+ return dst.Set(originalSrc)
+ }
+ return fmt.Errorf("cannot convert %v to UUID", value)
+ }
+
+ return nil
+}
+
+func (dst UUID) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst.Bytes
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *UUID) AssignTo(dst interface{}) error {
+ switch src.Status {
+ case Present:
+ switch v := dst.(type) {
+ case *[16]byte:
+ *v = src.Bytes
+ return nil
+ case *[]byte:
+ *v = make([]byte, 16)
+ copy(*v, src.Bytes[:])
+ return nil
+ case *string:
+ *v = encodeUUID(src.Bytes)
+ return nil
+ default:
+ if nextDst, retry := GetAssignToDstType(v); retry {
+ return src.AssignTo(nextDst)
+ }
+ }
+ case Null:
+ return NullAssignTo(dst)
+ }
+
+ return fmt.Errorf("cannot assign %v into %T", src, dst)
+}
+
+// parseUUID converts a string UUID in standard form to a byte array.
+func parseUUID(src string) (dst [16]byte, err error) {
+ switch len(src) {
+ case 36:
+ src = src[0:8] + src[9:13] + src[14:18] + src[19:23] + src[24:]
+ case 32:
+ // dashes already stripped, assume valid
+ default:
+ // assume invalid.
+ return dst, fmt.Errorf("cannot parse UUID %v", src)
+ }
+
+ buf, err := hex.DecodeString(src)
+ if err != nil {
+ return dst, err
+ }
+
+ copy(dst[:], buf)
+ return dst, err
+}
+
+// encodeUUID converts a uuid byte array to UUID standard string form.
+func encodeUUID(src [16]byte) string {
+ return fmt.Sprintf("%x-%x-%x-%x-%x", src[0:4], src[4:6], src[6:8], src[8:10], src[10:16])
+}
+
+func (dst *UUID) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = UUID{Status: Null}
+ return nil
+ }
+
+ if len(src) != 36 {
+ return fmt.Errorf("invalid length for UUID: %v", len(src))
+ }
+
+ buf, err := parseUUID(string(src))
+ if err != nil {
+ return err
+ }
+
+ *dst = UUID{Bytes: buf, Status: Present}
+ return nil
+}
+
+func (dst *UUID) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = UUID{Status: Null}
+ return nil
+ }
+
+ if len(src) != 16 {
+ return fmt.Errorf("invalid length for UUID: %v", len(src))
+ }
+
+ *dst = UUID{Status: Present}
+ copy(dst.Bytes[:], src)
+ return nil
+}
+
+func (src UUID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, encodeUUID(src.Bytes)...), nil
+}
+
+func (src UUID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ return append(buf, src.Bytes[:]...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *UUID) Scan(src interface{}) error {
+ if src == nil {
+ *dst = UUID{Status: Null}
+ return 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 UUID) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
+
+func (src UUID) MarshalJSON() ([]byte, error) {
+ switch src.Status {
+ case Present:
+ var buff bytes.Buffer
+ buff.WriteByte('"')
+ buff.WriteString(encodeUUID(src.Bytes))
+ buff.WriteByte('"')
+ return buff.Bytes(), nil
+ case Null:
+ return []byte("null"), nil
+ case Undefined:
+ return nil, errUndefined
+ }
+ return nil, errBadStatus
+}
+
+func (dst *UUID) UnmarshalJSON(src []byte) error {
+ if bytes.Compare(src, []byte("null")) == 0 {
+ return dst.Set(nil)
+ }
+ if len(src) != 38 {
+ return fmt.Errorf("invalid length for UUID: %v", len(src))
+ }
+ return dst.Set(string(src[1 : len(src)-1]))
+}
diff --git a/vendor/github.com/jackc/pgtype/uuid_array.go b/vendor/github.com/jackc/pgtype/uuid_array.go
new file mode 100644
index 000000000..00721ef93
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/uuid_array.go
@@ -0,0 +1,573 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type UUIDArray struct {
+ Elements []UUID
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *UUIDArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = UUIDArray{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 [][16]byte:
+ if value == nil {
+ *dst = UUIDArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = UUIDArray{Status: Present}
+ } else {
+ elements := make([]UUID, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = UUIDArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case [][]byte:
+ if value == nil {
+ *dst = UUIDArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = UUIDArray{Status: Present}
+ } else {
+ elements := make([]UUID, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = UUIDArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []string:
+ if value == nil {
+ *dst = UUIDArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = UUIDArray{Status: Present}
+ } else {
+ elements := make([]UUID, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = UUIDArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = UUIDArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = UUIDArray{Status: Present}
+ } else {
+ elements := make([]UUID, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = UUIDArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []UUID:
+ if value == nil {
+ *dst = UUIDArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = UUIDArray{Status: Present}
+ } else {
+ *dst = UUIDArray{
+ 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 = UUIDArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for UUIDArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = UUIDArray{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 UUIDArray", src)
+ }
+
+ *dst = UUIDArray{
+ Elements: make([]UUID, 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([]UUID, 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 UUIDArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *UUIDArray) 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 UUIDArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in UUIDArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst UUIDArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *UUIDArray) 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 *[][16]byte:
+ *v = make([][16]byte, 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 *[]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 *[]*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
+
+ }
+ }
+
+ // 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 *UUIDArray) 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 UUIDArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from UUIDArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *UUIDArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = UUIDArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []UUID
+
+ if len(uta.Elements) > 0 {
+ elements = make([]UUID, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem UUID
+ 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 = UUIDArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *UUIDArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = UUIDArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = UUIDArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]UUID, 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 = UUIDArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src UUIDArray) 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 UUIDArray) 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("uuid"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "uuid")
+ }
+
+ 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 *UUIDArray) 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 UUIDArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/varbit.go b/vendor/github.com/jackc/pgtype/varbit.go
new file mode 100644
index 000000000..f24dc5bcf
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/varbit.go
@@ -0,0 +1,133 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+
+ "github.com/jackc/pgio"
+)
+
+type Varbit struct {
+ Bytes []byte
+ Len int32 // Number of bits
+ Status Status
+}
+
+func (dst *Varbit) Set(src interface{}) error {
+ return fmt.Errorf("cannot convert %v to Varbit", src)
+}
+
+func (dst Varbit) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *Varbit) AssignTo(dst interface{}) error {
+ return fmt.Errorf("cannot assign %v to %T", src, dst)
+}
+
+func (dst *Varbit) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Varbit{Status: Null}
+ return nil
+ }
+
+ bitLen := len(src)
+ byteLen := bitLen / 8
+ if bitLen%8 > 0 {
+ byteLen++
+ }
+ buf := make([]byte, byteLen)
+
+ for i, b := range src {
+ if b == '1' {
+ byteIdx := i / 8
+ bitIdx := uint(i % 8)
+ buf[byteIdx] = buf[byteIdx] | (128 >> bitIdx)
+ }
+ }
+
+ *dst = Varbit{Bytes: buf, Len: int32(bitLen), Status: Present}
+ return nil
+}
+
+func (dst *Varbit) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = Varbit{Status: Null}
+ return nil
+ }
+
+ if len(src) < 4 {
+ return fmt.Errorf("invalid length for varbit: %v", len(src))
+ }
+
+ bitLen := int32(binary.BigEndian.Uint32(src))
+ rp := 4
+
+ *dst = Varbit{Bytes: src[rp:], Len: bitLen, Status: Present}
+ return nil
+}
+
+func (src Varbit) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ for i := int32(0); i < src.Len; i++ {
+ byteIdx := i / 8
+ bitMask := byte(128 >> byte(i%8))
+ char := byte('0')
+ if src.Bytes[byteIdx]&bitMask > 0 {
+ char = '1'
+ }
+ buf = append(buf, char)
+ }
+
+ return buf, nil
+}
+
+func (src Varbit) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ switch src.Status {
+ case Null:
+ return nil, nil
+ case Undefined:
+ return nil, errUndefined
+ }
+
+ buf = pgio.AppendInt32(buf, src.Len)
+ return append(buf, src.Bytes...), nil
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Varbit) Scan(src interface{}) error {
+ if src == nil {
+ *dst = Varbit{Status: Null}
+ return 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 Varbit) Value() (driver.Value, error) {
+ return EncodeValueText(src)
+}
diff --git a/vendor/github.com/jackc/pgtype/varchar.go b/vendor/github.com/jackc/pgtype/varchar.go
new file mode 100644
index 000000000..fea31d181
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/varchar.go
@@ -0,0 +1,66 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+type Varchar Text
+
+// Set converts from src to dst. Note that as Varchar is not a general
+// number type Set does not do automatic type conversion as other number
+// types do.
+func (dst *Varchar) Set(src interface{}) error {
+ return (*Text)(dst).Set(src)
+}
+
+func (dst Varchar) Get() interface{} {
+ return (Text)(dst).Get()
+}
+
+// AssignTo assigns from src to dst. Note that as Varchar is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *Varchar) AssignTo(dst interface{}) error {
+ return (*Text)(src).AssignTo(dst)
+}
+
+func (Varchar) PreferredResultFormat() int16 {
+ return TextFormatCode
+}
+
+func (dst *Varchar) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeText(ci, src)
+}
+
+func (dst *Varchar) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*Text)(dst).DecodeBinary(ci, src)
+}
+
+func (Varchar) PreferredParamFormat() int16 {
+ return TextFormatCode
+}
+
+func (src Varchar) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeText(ci, buf)
+}
+
+func (src Varchar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (Text)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *Varchar) Scan(src interface{}) error {
+ return (*Text)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src Varchar) Value() (driver.Value, error) {
+ return (Text)(src).Value()
+}
+
+func (src Varchar) MarshalJSON() ([]byte, error) {
+ return (Text)(src).MarshalJSON()
+}
+
+func (dst *Varchar) UnmarshalJSON(b []byte) error {
+ return (*Text)(dst).UnmarshalJSON(b)
+}
diff --git a/vendor/github.com/jackc/pgtype/varchar_array.go b/vendor/github.com/jackc/pgtype/varchar_array.go
new file mode 100644
index 000000000..8a309a3f8
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/varchar_array.go
@@ -0,0 +1,517 @@
+// Code generated by erb. DO NOT EDIT.
+
+package pgtype
+
+import (
+ "database/sql/driver"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgio"
+)
+
+type VarcharArray struct {
+ Elements []Varchar
+ Dimensions []ArrayDimension
+ Status Status
+}
+
+func (dst *VarcharArray) Set(src interface{}) error {
+ // untyped nil and typed nil interfaces are different
+ if src == nil {
+ *dst = VarcharArray{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 = VarcharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = VarcharArray{Status: Present}
+ } else {
+ elements := make([]Varchar, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = VarcharArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []*string:
+ if value == nil {
+ *dst = VarcharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = VarcharArray{Status: Present}
+ } else {
+ elements := make([]Varchar, len(value))
+ for i := range value {
+ if err := elements[i].Set(value[i]); err != nil {
+ return err
+ }
+ }
+ *dst = VarcharArray{
+ Elements: elements,
+ Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
+ Status: Present,
+ }
+ }
+
+ case []Varchar:
+ if value == nil {
+ *dst = VarcharArray{Status: Null}
+ } else if len(value) == 0 {
+ *dst = VarcharArray{Status: Present}
+ } else {
+ *dst = VarcharArray{
+ 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 = VarcharArray{Status: Null}
+ return nil
+ }
+
+ dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
+ if !ok {
+ return fmt.Errorf("cannot find dimensions of %v for VarcharArray", src)
+ }
+ if elementsLength == 0 {
+ *dst = VarcharArray{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 VarcharArray", src)
+ }
+
+ *dst = VarcharArray{
+ Elements: make([]Varchar, 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([]Varchar, 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 VarcharArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
+ }
+ }
+
+ return nil
+}
+
+func (dst *VarcharArray) 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 VarcharArray")
+ }
+ if err := dst.Elements[index].Set(value.Interface()); err != nil {
+ return 0, fmt.Errorf("%v in VarcharArray", err)
+ }
+ index++
+
+ return index, nil
+}
+
+func (dst VarcharArray) Get() interface{} {
+ switch dst.Status {
+ case Present:
+ return dst
+ case Null:
+ return nil
+ default:
+ return dst.Status
+ }
+}
+
+func (src *VarcharArray) 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 *[]*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
+
+ }
+ }
+
+ // 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 *VarcharArray) 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 VarcharArray")
+ }
+ addr := value.Addr()
+ if !addr.CanInterface() {
+ return 0, fmt.Errorf("cannot assign all values from VarcharArray")
+ }
+ if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
+ return 0, err
+ }
+ index++
+ return index, nil
+}
+
+func (dst *VarcharArray) DecodeText(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = VarcharArray{Status: Null}
+ return nil
+ }
+
+ uta, err := ParseUntypedTextArray(string(src))
+ if err != nil {
+ return err
+ }
+
+ var elements []Varchar
+
+ if len(uta.Elements) > 0 {
+ elements = make([]Varchar, len(uta.Elements))
+
+ for i, s := range uta.Elements {
+ var elem Varchar
+ 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 = VarcharArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
+
+ return nil
+}
+
+func (dst *VarcharArray) DecodeBinary(ci *ConnInfo, src []byte) error {
+ if src == nil {
+ *dst = VarcharArray{Status: Null}
+ return nil
+ }
+
+ var arrayHeader ArrayHeader
+ rp, err := arrayHeader.DecodeBinary(ci, src)
+ if err != nil {
+ return err
+ }
+
+ if len(arrayHeader.Dimensions) == 0 {
+ *dst = VarcharArray{Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+ }
+
+ elementCount := arrayHeader.Dimensions[0].Length
+ for _, d := range arrayHeader.Dimensions[1:] {
+ elementCount *= d.Length
+ }
+
+ elements := make([]Varchar, 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 = VarcharArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
+ return nil
+}
+
+func (src VarcharArray) 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 VarcharArray) 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("varchar"); ok {
+ arrayHeader.ElementOID = int32(dt.OID)
+ } else {
+ return nil, fmt.Errorf("unable to find oid for type name %v", "varchar")
+ }
+
+ 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 *VarcharArray) 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 VarcharArray) 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
+}
diff --git a/vendor/github.com/jackc/pgtype/xid.go b/vendor/github.com/jackc/pgtype/xid.go
new file mode 100644
index 000000000..f6d6b22d5
--- /dev/null
+++ b/vendor/github.com/jackc/pgtype/xid.go
@@ -0,0 +1,64 @@
+package pgtype
+
+import (
+ "database/sql/driver"
+)
+
+// XID is PostgreSQL's Transaction ID type.
+//
+// In later versions of PostgreSQL, it is the type used for the backend_xid
+// and backend_xmin columns of the pg_stat_activity system view.
+//
+// Also, when one does
+//
+// select xmin, xmax, * from some_table;
+//
+// it is the data type of the xmin and xmax hidden system columns.
+//
+// It is currently implemented as an unsigned four byte integer.
+// Its definition can be found in src/include/postgres_ext.h as TransactionId
+// in the PostgreSQL sources.
+type XID pguint32
+
+// Set converts from src to dst. Note that as XID is not a general
+// number type Set does not do automatic type conversion as other number
+// types do.
+func (dst *XID) Set(src interface{}) error {
+ return (*pguint32)(dst).Set(src)
+}
+
+func (dst XID) Get() interface{} {
+ return (pguint32)(dst).Get()
+}
+
+// AssignTo assigns from src to dst. Note that as XID is not a general number
+// type AssignTo does not do automatic type conversion as other number types do.
+func (src *XID) AssignTo(dst interface{}) error {
+ return (*pguint32)(src).AssignTo(dst)
+}
+
+func (dst *XID) DecodeText(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeText(ci, src)
+}
+
+func (dst *XID) DecodeBinary(ci *ConnInfo, src []byte) error {
+ return (*pguint32)(dst).DecodeBinary(ci, src)
+}
+
+func (src XID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeText(ci, buf)
+}
+
+func (src XID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
+ return (pguint32)(src).EncodeBinary(ci, buf)
+}
+
+// Scan implements the database/sql Scanner interface.
+func (dst *XID) Scan(src interface{}) error {
+ return (*pguint32)(dst).Scan(src)
+}
+
+// Value implements the database/sql/driver Valuer interface.
+func (src XID) Value() (driver.Value, error) {
+ return (pguint32)(src).Value()
+}
diff --git a/vendor/github.com/jackc/pgx/v4/.gitignore b/vendor/github.com/jackc/pgx/v4/.gitignore
new file mode 100644
index 000000000..39175a965
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+.envrc
diff --git a/vendor/github.com/jackc/pgx/v4/CHANGELOG.md b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md
new file mode 100644
index 000000000..ef4a2029a
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md
@@ -0,0 +1,209 @@
+# 4.13.0 (July 24, 2021)
+
+* Trimmed pseudo-dependencies in Go modules from other packages tests
+* Upgrade pgconn -- context cancellation no longer will return a net.Error
+* Support time durations for simple protocol (Michael Darr)
+
+# 4.12.0 (July 10, 2021)
+
+* ResetSession hook is called before a connection is reused from pool for another query (Dmytro Haranzha)
+* stdlib: Add RandomizeHostOrderFunc (dkinder)
+* stdlib: add OptionBeforeConnect (dkinder)
+* stdlib: Do not reuse ConnConfig strings (Andrew Kimball)
+* stdlib: implement Conn.ResetSession (Jonathan Amsterdam)
+* Upgrade pgconn to v1.9.0
+* Upgrade pgtype to v1.8.0
+
+# 4.11.0 (March 25, 2021)
+
+* Add BeforeConnect callback to pgxpool.Config (Robert Froehlich)
+* Add Ping method to pgxpool.Conn (davidsbond)
+* Added a kitlog level log adapter (Fabrice Aneche)
+* Make ScanArgError public to allow identification of offending column (Pau Sanchez)
+* Add *pgxpool.AcquireFunc
+* Add BeginFunc and BeginTxFunc
+* Add prefer_simple_protocol to connection string
+* Add logging on CopyFrom (Patrick Hemmer)
+* Add comment support when sanitizing SQL queries (Rusakow Andrew)
+* Do not panic on double close of pgxpool.Pool (Matt Schultz)
+* Avoid panic on SendBatch on closed Tx (Matt Schultz)
+* Update pgconn to v1.8.1
+* Update pgtype to v1.7.0
+
+# 4.10.1 (December 19, 2020)
+
+* Fix panic on Query error with nil stmtcache.
+
+# 4.10.0 (December 3, 2020)
+
+* Add CopyFromSlice to simplify CopyFrom usage (Egon Elbre)
+* Remove broken prepared statements from stmtcache (Ethan Pailes)
+* stdlib: consider any Ping error as fatal
+* Update puddle to v1.1.3 - this fixes an issue where concurrent Acquires can hang when a connection cannot be established
+* Update pgtype to v1.6.2
+
+# 4.9.2 (November 3, 2020)
+
+The underlying library updates fix an issue where appending to a scanned slice could corrupt other data.
+
+* Update pgconn to v1.7.2
+* Update pgproto3 to v2.0.6
+
+# 4.9.1 (October 31, 2020)
+
+* Update pgconn to v1.7.1
+* Update pgtype to v1.6.1
+* Fix SendBatch of all prepared statements with statement cache disabled
+
+# 4.9.0 (September 26, 2020)
+
+* pgxpool now waits for connection cleanup to finish before making room in pool for another connection. This prevents temporarily exceeding max pool size.
+* Fix when scanning a column to nil to skip it on the first row but scanning it to a real value on a subsequent row.
+* Fix prefer simple protocol with prepared statements. (Jinzhu)
+* Fix FieldDescriptions not being available on Rows before calling Next the first time.
+* Various minor fixes in updated versions of pgconn, pgtype, and puddle.
+
+# 4.8.1 (July 29, 2020)
+
+* Update pgconn to v1.6.4
+ * Fix deadlock on error after CommandComplete but before ReadyForQuery
+ * Fix panic on parsing DSN with trailing '='
+
+# 4.8.0 (July 22, 2020)
+
+* All argument types supported by native pgx should now also work through database/sql
+* Update pgconn to v1.6.3
+* Update pgtype to v1.4.2
+
+# 4.7.2 (July 14, 2020)
+
+* Improve performance of Columns() (zikaeroh)
+* Fix fatal Commit() failure not being considered fatal
+* Update pgconn to v1.6.2
+* Update pgtype to v1.4.1
+
+# 4.7.1 (June 29, 2020)
+
+* Fix stdlib decoding error with certain order and combination of fields
+
+# 4.7.0 (June 27, 2020)
+
+* Update pgtype to v1.4.0
+* Update pgconn to v1.6.1
+* Update puddle to v1.1.1
+* Fix context propagation with Tx commit and Rollback (georgysavva)
+* Add lazy connect option to pgxpool (georgysavva)
+* Fix connection leak if pgxpool.BeginTx() fail (Jean-Baptiste Bronisz)
+* Add native Go slice support for strings and numbers to simple protocol
+* stdlib add default timeouts for Conn.Close() and Stmt.Close() (georgysavva)
+* Assorted performance improvements especially with large result sets
+* Fix close pool on not lazy connect failure (Yegor Myskin)
+* Add Config copy (georgysavva)
+* Support SendBatch with Simple Protocol (Jordan Lewis)
+* Better error logging on rows close (Igor V. Kozinov)
+* Expose stdlib.Conn.Conn() to enable database/sql.Conn.Raw()
+* Improve unknown type support for database/sql
+* Fix transaction commit failure closing connection
+
+# 4.6.0 (March 30, 2020)
+
+* stdlib: Bail early if preloading rows.Next() results in rows.Err() (Bas van Beek)
+* Sanitize time to microsecond accuracy (Andrew Nicoll)
+* Update pgtype to v1.3.0
+* Update pgconn to v1.5.0
+ * Update golang.org/x/crypto for security fix
+ * Implement "verify-ca" SSL mode
+
+# 4.5.0 (March 7, 2020)
+
+* Update to pgconn v1.4.0
+ * Fixes QueryRow with empty SQL
+ * Adds PostgreSQL service file support
+* Add Len() to *pgx.Batch (WGH)
+* Better logging for individual batch items (Ben Bader)
+
+# 4.4.1 (February 14, 2020)
+
+* Update pgconn to v1.3.2 - better default read buffer size
+* Fix race in CopyFrom
+
+# 4.4.0 (February 5, 2020)
+
+* Update puddle to v1.1.0 - fixes possible deadlock when acquire is cancelled
+* Update pgconn to v1.3.1 - fixes CopyFrom deadlock when multiple NoticeResponse received during copy
+* Update pgtype to v1.2.0
+* Add MaxConnIdleTime to pgxpool (Patrick Ellul)
+* Add MinConns to pgxpool (Patrick Ellul)
+* Fix: stdlib.ReleaseConn closes connections left in invalid state
+
+# 4.3.0 (January 23, 2020)
+
+* Fix Rows.Values panic when unable to decode
+* Add Rows.Values support for unknown types
+* Add DriverContext support for stdlib (Alex Gaynor)
+* Update pgproto3 to v2.0.1 to never return an io.EOF as it would be misinterpreted by database/sql. Instead return io.UnexpectedEOF.
+
+# 4.2.1 (January 13, 2020)
+
+* Update pgconn to v1.2.1 (fixes context cancellation data race introduced in v1.2.0))
+
+# 4.2.0 (January 11, 2020)
+
+* Update pgconn to v1.2.0.
+* Update pgtype to v1.1.0.
+* Return error instead of panic when wrong number of arguments passed to Exec. (malstoun)
+* Fix large objects functionality when PreferSimpleProtocol = true.
+* Restore GetDefaultDriver which existed in v3. (Johan Brandhorst)
+* Add RegisterConnConfig to stdlib which replaces the removed RegisterDriverConfig from v3.
+
+# 4.1.2 (October 22, 2019)
+
+* Fix dbSavepoint.Begin recursive self call
+* Upgrade pgtype to v1.0.2 - fix scan pointer to pointer
+
+# 4.1.1 (October 21, 2019)
+
+* Fix pgxpool Rows.CommandTag() infinite loop / typo
+
+# 4.1.0 (October 12, 2019)
+
+## Potentially Breaking Changes
+
+Technically, two changes are breaking changes, but in practice these are extremely unlikely to break existing code.
+
+* Conn.Begin and Conn.BeginTx return a Tx interface instead of the internal dbTx struct. This is necessary for the Conn.Begin method to signature as other methods that begin a transaction.
+* Add Conn() to Tx interface. This is necessary to allow code using a Tx to access the *Conn (and pgconn.PgConn) on which the Tx is executing.
+
+## Fixes
+
+* Releasing a busy connection closes the connection instead of returning an unusable connection to the pool
+* Do not mutate config.Config.OnNotification in connect
+
+# 4.0.1 (September 19, 2019)
+
+* Fix statement cache cleanup.
+* Corrected daterange OID.
+* Fix Tx when committing or rolling back multiple times in certain cases.
+* Improve documentation.
+
+# 4.0.0 (September 14, 2019)
+
+v4 is a major release with many significant changes some of which are breaking changes. The most significant are
+included below.
+
+* Simplified establishing a connection with a connection string.
+* All potentially blocking operations now require a context.Context. The non-context aware functions have been removed.
+* OIDs are hard-coded for known types. This saves the query on connection.
+* Context cancellations while network activity is in progress is now always fatal. Previously, it was sometimes recoverable. This led to increased complexity in pgx itself and in application code.
+* Go modules are required.
+* Errors are now implemented in the Go 1.13 style.
+* `Rows` and `Tx` are now interfaces.
+* The connection pool as been decoupled from pgx and is now a separate, included package (github.com/jackc/pgx/v4/pgxpool).
+* pgtype has been spun off to a separate package (github.com/jackc/pgtype).
+* pgproto3 has been spun off to a separate package (github.com/jackc/pgproto3/v2).
+* Logical replication support has been spun off to a separate package (github.com/jackc/pglogrepl).
+* Lower level PostgreSQL functionality is now implemented in a separate package (github.com/jackc/pgconn).
+* Tests are now configured with environment variables.
+* Conn has an automatic statement cache by default.
+* Batch interface has been simplified.
+* QueryArgs has been removed.
diff --git a/vendor/github.com/jackc/pgx/v4/LICENSE b/vendor/github.com/jackc/pgx/v4/LICENSE
new file mode 100644
index 000000000..5c486c39a
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2021 Jack Christensen
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/jackc/pgx/v4/README.md b/vendor/github.com/jackc/pgx/v4/README.md
new file mode 100644
index 000000000..732320447
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/README.md
@@ -0,0 +1,203 @@
+[![](https://godoc.org/github.com/jackc/pgx?status.svg)](https://pkg.go.dev/github.com/jackc/pgx/v4)
+[![Build Status](https://travis-ci.org/jackc/pgx.svg)](https://travis-ci.org/jackc/pgx)
+
+# pgx - PostgreSQL Driver and Toolkit
+
+pgx is a pure Go driver and toolkit for PostgreSQL.
+
+pgx aims to be low-level, fast, and performant, while also enabling PostgreSQL-specific features that the standard `database/sql` package does not allow for.
+
+The driver component of pgx can be used alongside the standard `database/sql` package.
+
+The toolkit component is a related set of packages that implement PostgreSQL functionality such as parsing the wire protocol
+and type mapping between PostgreSQL and Go. These underlying packages can be used to implement alternative drivers,
+proxies, load balancers, logical replication clients, etc.
+
+The current release of `pgx v4` requires Go modules. To use the previous version, checkout and vendor the `v3` branch.
+
+## Example Usage
+
+```go
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+
+ "github.com/jackc/pgx/v4"
+)
+
+func main() {
+ // urlExample := "postgres://username:password@localhost:5432/database_name"
+ conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Unable to connect to database: %v\n", err)
+ os.Exit(1)
+ }
+ defer conn.Close(context.Background())
+
+ var name string
+ var weight int64
+ err = conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "QueryRow failed: %v\n", err)
+ os.Exit(1)
+ }
+
+ fmt.Println(name, weight)
+}
+```
+
+See the [getting started guide](https://github.com/jackc/pgx/wiki/Getting-started-with-pgx) for more information.
+
+## Choosing Between the pgx and database/sql Interfaces
+
+It is recommended to use the pgx interface if:
+1. The application only targets PostgreSQL.
+2. No other libraries that require `database/sql` are in use.
+
+The pgx interface is faster and exposes more features.
+
+The `database/sql` interface only allows the underlying driver to return or receive the following types: `int64`,
+`float64`, `bool`, `[]byte`, `string`, `time.Time`, or `nil`. Handling other types requires implementing the
+`database/sql.Scanner` and the `database/sql/driver/driver.Valuer` interfaces which require transmission of values in text format. The binary format can be substantially faster, which is what the pgx interface uses.
+
+## Features
+
+pgx supports many features beyond what is available through `database/sql`:
+
+* Support for approximately 70 different PostgreSQL types
+* Automatic statement preparation and caching
+* Batch queries
+* Single-round trip query mode
+* Full TLS connection control
+* Binary format support for custom types (allows for much quicker encoding/decoding)
+* Copy protocol support for faster bulk data loads
+* Extendable logging support including built-in support for `log15adapter`, [`logrus`](https://github.com/sirupsen/logrus), [`zap`](https://github.com/uber-go/zap), and [`zerolog`](https://github.com/rs/zerolog)
+* Connection pool with after-connect hook for arbitrary connection setup
+* Listen / notify
+* Conversion of PostgreSQL arrays to Go slice mappings for integers, floats, and strings
+* Hstore support
+* JSON and JSONB support
+* Maps `inet` and `cidr` PostgreSQL types to `net.IPNet` and `net.IP`
+* Large object support
+* NULL mapping to Null* struct or pointer to pointer
+* Supports `database/sql.Scanner` and `database/sql/driver.Valuer` interfaces for custom types
+* Notice response handling
+* Simulated nested transactions with savepoints
+
+## Performance
+
+There are three areas in particular where pgx can provide a significant performance advantage over the standard
+`database/sql` interface and other drivers:
+
+1. PostgreSQL specific types - Types such as arrays can be parsed much quicker because pgx uses the binary format.
+2. Automatic statement preparation and caching - pgx will prepare and cache statements by default. This can provide an
+ significant free improvement to code that does not explicitly use prepared statements. Under certain workloads, it can
+ perform nearly 3x the number of queries per second.
+3. Batched queries - Multiple queries can be batched together to minimize network round trips.
+
+## Comparison with Alternatives
+
+* [pq](http://godoc.org/github.com/lib/pq)
+* [go-pg](https://github.com/go-pg/pg)
+
+For prepared queries with small sets of simple data types, all drivers will have have similar performance. However, if prepared statements aren't being explicitly used, pgx can have a significant performance advantage due to automatic statement preparation.
+pgx also can perform better when using PostgreSQL-specific data types or query batching. See
+[go_db_bench](https://github.com/jackc/go_db_bench) for some database driver benchmarks.
+
+### Compatibility with `database/sql`
+
+pq is exclusively used with `database/sql`. go-pg does not use `database/sql` at all. pgx supports `database/sql` as well as
+its own interface.
+
+### Level of access, ORM
+
+go-pg is a PostgreSQL client and ORM. It includes many features that traditionally sit above the database driver, such as ORM, struct mapping, soft deletes, schema migrations, and sharding support.
+
+pgx is "closer to the metal" and such abstractions are beyond the scope of the pgx project, which first and foremost, aims to be a performant driver and toolkit.
+
+## Testing
+
+pgx tests naturally require a PostgreSQL database. It will connect to the database specified in the `PGX_TEST_DATABASE` environment
+variable. The `PGX_TEST_DATABASE` environment variable can either be a URL or DSN. In addition, the standard `PG*` environment
+variables will be respected. Consider using [direnv](https://github.com/direnv/direnv) to simplify environment variable
+handling.
+
+### Example Test Environment
+
+Connect to your PostgreSQL server and run:
+
+```
+create database pgx_test;
+```
+
+Connect to the newly-created database and run:
+
+```
+create domain uint64 as numeric(20,0);
+```
+
+Now, you can run the tests:
+
+```
+PGX_TEST_DATABASE="host=/var/run/postgresql database=pgx_test" go test ./...
+```
+
+In addition, there are tests specific for PgBouncer that will be executed if `PGX_TEST_PGBOUNCER_CONN_STRING` is set.
+
+## Supported Go and PostgreSQL Versions
+
+pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.15 and higher and PostgreSQL 9.6 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/).
+
+## Version Policy
+
+pgx follows semantic versioning for the documented public API on stable releases. `v4` is the latest stable major version.
+
+## PGX Family Libraries
+
+pgx is the head of a family of PostgreSQL libraries. Many of these can be used independently. Many can also be accessed
+from pgx for lower-level control.
+
+### [github.com/jackc/pgconn](https://github.com/jackc/pgconn)
+
+`pgconn` is a lower-level PostgreSQL database driver that operates at nearly the same level as the C library `libpq`.
+
+### [github.com/jackc/pgx/v4/pgxpool](https://github.com/jackc/pgx/tree/master/pgxpool)
+
+`pgxpool` is a connection pool for pgx. pgx is entirely decoupled from its default pool implementation. This means that pgx can be used with a different pool or without any pool at all.
+
+### [github.com/jackc/pgx/v4/stdlib](https://github.com/jackc/pgx/tree/master/stdlib)
+
+This is a `database/sql` compatibility layer for pgx. pgx can be used as a normal `database/sql` driver, but at any time, the native interface can be acquired for more performance or PostgreSQL specific functionality.
+
+### [github.com/jackc/pgtype](https://github.com/jackc/pgtype)
+
+Over 70 PostgreSQL types are supported including `uuid`, `hstore`, `json`, `bytea`, `numeric`, `interval`, `inet`, and arrays. These types support `database/sql` interfaces and are usable outside of pgx. They are fully tested in pgx and pq. They also support a higher performance interface when used with the pgx driver.
+
+### [github.com/jackc/pgproto3](https://github.com/jackc/pgproto3)
+
+pgproto3 provides standalone encoding and decoding of the PostgreSQL v3 wire protocol. This is useful for implementing very low level PostgreSQL tooling.
+
+### [github.com/jackc/pglogrepl](https://github.com/jackc/pglogrepl)
+
+pglogrepl provides functionality to act as a client for PostgreSQL logical replication.
+
+### [github.com/jackc/pgmock](https://github.com/jackc/pgmock)
+
+pgmock offers the ability to create a server that mocks the PostgreSQL wire protocol. This is used internally to test pgx by purposely inducing unusual errors. pgproto3 and pgmock together provide most of the foundational tooling required to implement a PostgreSQL proxy or MitM (such as for a custom connection pooler).
+
+### [github.com/jackc/tern](https://github.com/jackc/tern)
+
+tern is a stand-alone SQL migration system.
+
+### [github.com/jackc/pgerrcode](https://github.com/jackc/pgerrcode)
+
+pgerrcode contains constants for the PostgreSQL error codes.
+
+## 3rd Party Libraries with PGX Support
+
+### [github.com/georgysavva/scany](https://github.com/georgysavva/scany)
+
+Library for scanning data from a database into Go structs and more.
diff --git a/vendor/github.com/jackc/pgx/v4/batch.go b/vendor/github.com/jackc/pgx/v4/batch.go
new file mode 100644
index 000000000..4b96ca194
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/batch.go
@@ -0,0 +1,179 @@
+package pgx
+
+import (
+ "context"
+ "errors"
+
+ "github.com/jackc/pgconn"
+)
+
+type batchItem struct {
+ query string
+ arguments []interface{}
+}
+
+// Batch queries are a way of bundling multiple queries together to avoid
+// unnecessary network round trips.
+type Batch struct {
+ items []*batchItem
+}
+
+// Queue queues a query to batch b. query can be an SQL query or the name of a prepared statement.
+func (b *Batch) Queue(query string, arguments ...interface{}) {
+ b.items = append(b.items, &batchItem{
+ query: query,
+ arguments: arguments,
+ })
+}
+
+// Len returns number of queries that have been queued so far.
+func (b *Batch) Len() int {
+ return len(b.items)
+}
+
+type BatchResults interface {
+ // Exec reads the results from the next query in the batch as if the query has been sent with Conn.Exec.
+ Exec() (pgconn.CommandTag, error)
+
+ // Query reads the results from the next query in the batch as if the query has been sent with Conn.Query.
+ Query() (Rows, error)
+
+ // QueryRow reads the results from the next query in the batch as if the query has been sent with Conn.QueryRow.
+ QueryRow() Row
+
+ // Close closes the batch operation. This must be called before the underlying connection can be used again. Any error
+ // that occurred during a batch operation may have made it impossible to resyncronize the connection with the server.
+ // In this case the underlying connection will have been closed.
+ Close() error
+}
+
+type batchResults struct {
+ ctx context.Context
+ conn *Conn
+ mrr *pgconn.MultiResultReader
+ err error
+ b *Batch
+ ix int
+}
+
+// Exec reads the results from the next query in the batch as if the query has been sent with Exec.
+func (br *batchResults) Exec() (pgconn.CommandTag, error) {
+ if br.err != nil {
+ return nil, br.err
+ }
+
+ query, arguments, _ := br.nextQueryAndArgs()
+
+ if !br.mrr.NextResult() {
+ err := br.mrr.Close()
+ if err == nil {
+ err = errors.New("no result")
+ }
+ if br.conn.shouldLog(LogLevelError) {
+ br.conn.log(br.ctx, LogLevelError, "BatchResult.Exec", map[string]interface{}{
+ "sql": query,
+ "args": logQueryArgs(arguments),
+ "err": err,
+ })
+ }
+ return nil, err
+ }
+
+ commandTag, err := br.mrr.ResultReader().Close()
+
+ if err != nil {
+ if br.conn.shouldLog(LogLevelError) {
+ br.conn.log(br.ctx, LogLevelError, "BatchResult.Exec", map[string]interface{}{
+ "sql": query,
+ "args": logQueryArgs(arguments),
+ "err": err,
+ })
+ }
+ } else if br.conn.shouldLog(LogLevelInfo) {
+ br.conn.log(br.ctx, LogLevelInfo, "BatchResult.Exec", map[string]interface{}{
+ "sql": query,
+ "args": logQueryArgs(arguments),
+ "commandTag": commandTag,
+ })
+ }
+
+ return commandTag, err
+}
+
+// Query reads the results from the next query in the batch as if the query has been sent with Query.
+func (br *batchResults) Query() (Rows, error) {
+ query, arguments, ok := br.nextQueryAndArgs()
+ if !ok {
+ query = "batch query"
+ }
+
+ if br.err != nil {
+ return &connRows{err: br.err, closed: true}, br.err
+ }
+
+ rows := br.conn.getRows(br.ctx, query, arguments)
+
+ if !br.mrr.NextResult() {
+ rows.err = br.mrr.Close()
+ if rows.err == nil {
+ rows.err = errors.New("no result")
+ }
+ rows.closed = true
+
+ if br.conn.shouldLog(LogLevelError) {
+ br.conn.log(br.ctx, LogLevelError, "BatchResult.Query", map[string]interface{}{
+ "sql": query,
+ "args": logQueryArgs(arguments),
+ "err": rows.err,
+ })
+ }
+
+ return rows, rows.err
+ }
+
+ rows.resultReader = br.mrr.ResultReader()
+ return rows, nil
+}
+
+// QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow.
+func (br *batchResults) QueryRow() Row {
+ rows, _ := br.Query()
+ return (*connRow)(rows.(*connRows))
+
+}
+
+// Close closes the batch operation. Any error that occurred during a batch operation may have made it impossible to
+// resyncronize the connection with the server. In this case the underlying connection will have been closed.
+func (br *batchResults) Close() error {
+ if br.err != nil {
+ return br.err
+ }
+
+ // log any queries that haven't yet been logged by Exec or Query
+ for {
+ query, args, ok := br.nextQueryAndArgs()
+ if !ok {
+ break
+ }
+
+ if br.conn.shouldLog(LogLevelInfo) {
+ br.conn.log(br.ctx, LogLevelInfo, "BatchResult.Close", map[string]interface{}{
+ "sql": query,
+ "args": logQueryArgs(args),
+ })
+ }
+ }
+
+ return br.mrr.Close()
+}
+
+func (br *batchResults) nextQueryAndArgs() (query string, args []interface{}, ok bool) {
+ if br.b != nil && br.ix < len(br.b.items) {
+ bi := br.b.items[br.ix]
+ query = bi.query
+ args = bi.arguments
+ ok = true
+ br.ix++
+ }
+ return
+}
diff --git a/vendor/github.com/jackc/pgx/v4/conn.go b/vendor/github.com/jackc/pgx/v4/conn.go
new file mode 100644
index 000000000..9636f2fd6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/conn.go
@@ -0,0 +1,850 @@
+package pgx
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/jackc/pgconn"
+ "github.com/jackc/pgconn/stmtcache"
+ "github.com/jackc/pgproto3/v2"
+ "github.com/jackc/pgtype"
+ "github.com/jackc/pgx/v4/internal/sanitize"
+)
+
+// ConnConfig contains all the options used to establish a connection. It must be created by ParseConfig and
+// then it can be modified. A manually initialized ConnConfig will cause ConnectConfig to panic.
+type ConnConfig struct {
+ pgconn.Config
+ Logger Logger
+ LogLevel LogLevel
+
+ // Original connection string that was parsed into config.
+ connString string
+
+ // BuildStatementCache creates the stmtcache.Cache implementation for connections created with this config. Set
+ // to nil to disable automatic prepared statements.
+ BuildStatementCache BuildStatementCacheFunc
+
+ // PreferSimpleProtocol disables implicit prepared statement usage. By default pgx automatically uses the extended
+ // protocol. This can improve performance due to being able to use the binary format. It also does not rely on client
+ // side parameter sanitization. However, it does incur two round-trips per query (unless using a prepared statement)
+ // and may be incompatible proxies such as PGBouncer. Setting PreferSimpleProtocol causes the simple protocol to be
+ // used by default. The same functionality can be controlled on a per query basis by setting
+ // QueryExOptions.SimpleProtocol.
+ PreferSimpleProtocol bool
+
+ createdByParseConfig bool // Used to enforce created by ParseConfig rule.
+}
+
+// Copy returns a deep copy of the config that is safe to use and modify.
+// The only exception is the tls.Config:
+// according to the tls.Config docs it must not be modified after creation.
+func (cc *ConnConfig) Copy() *ConnConfig {
+ newConfig := new(ConnConfig)
+ *newConfig = *cc
+ newConfig.Config = *newConfig.Config.Copy()
+ return newConfig
+}
+
+func (cc *ConnConfig) ConnString() string { return cc.connString }
+
+// BuildStatementCacheFunc is a function that can be used to create a stmtcache.Cache implementation for connection.
+type BuildStatementCacheFunc func(conn *pgconn.PgConn) stmtcache.Cache
+
+// Conn is a PostgreSQL connection handle. It is not safe for concurrent usage. Use a connection pool to manage access
+// to multiple database connections from multiple goroutines.
+type Conn struct {
+ pgConn *pgconn.PgConn
+ config *ConnConfig // config used when establishing this connection
+ preparedStatements map[string]*pgconn.StatementDescription
+ stmtcache stmtcache.Cache
+ logger Logger
+ logLevel LogLevel
+
+ notifications []*pgconn.Notification
+
+ doneChan chan struct{}
+ closedChan chan error
+
+ connInfo *pgtype.ConnInfo
+
+ wbuf []byte
+ preallocatedRows []connRows
+ eqb extendedQueryBuilder
+}
+
+// Identifier a PostgreSQL identifier or name. Identifiers can be composed of
+// multiple parts such as ["schema", "table"] or ["table", "column"].
+type Identifier []string
+
+// Sanitize returns a sanitized string safe for SQL interpolation.
+func (ident Identifier) Sanitize() string {
+ parts := make([]string, len(ident))
+ for i := range ident {
+ s := strings.ReplaceAll(ident[i], string([]byte{0}), "")
+ parts[i] = `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
+ }
+ return strings.Join(parts, ".")
+}
+
+// ErrNoRows occurs when rows are expected but none are returned.
+var ErrNoRows = errors.New("no rows in result set")
+
+// ErrInvalidLogLevel occurs on attempt to set an invalid log level.
+var ErrInvalidLogLevel = errors.New("invalid log level")
+
+// Connect establishes a connection with a PostgreSQL server with a connection string. See
+// pgconn.Connect for details.
+func Connect(ctx context.Context, connString string) (*Conn, error) {
+ connConfig, err := ParseConfig(connString)
+ if err != nil {
+ return nil, err
+ }
+ return connect(ctx, connConfig)
+}
+
+// Connect establishes a connection with a PostgreSQL server with a configuration struct. connConfig must have been
+// created by ParseConfig.
+func ConnectConfig(ctx context.Context, connConfig *ConnConfig) (*Conn, error) {
+ return connect(ctx, connConfig)
+}
+
+// ParseConfig creates a ConnConfig from a connection string. ParseConfig handles all options that pgconn.ParseConfig
+// does. In addition, it accepts the following options:
+//
+// statement_cache_capacity
+// The maximum size of the automatic statement cache. Set to 0 to disable automatic statement caching. Default: 512.
+//
+// statement_cache_mode
+// Possible values: "prepare" and "describe". "prepare" will create prepared statements on the PostgreSQL server.
+// "describe" will use the anonymous prepared statement to describe a statement without creating a statement on the
+// server. "describe" is primarily useful when the environment does not allow prepared statements such as when
+// running a connection pooler like PgBouncer. Default: "prepare"
+//
+// prefer_simple_protocol
+// Possible values: "true" and "false". Use the simple protocol instead of extended protocol. Default: false
+func ParseConfig(connString string) (*ConnConfig, error) {
+ config, err := pgconn.ParseConfig(connString)
+ if err != nil {
+ return nil, err
+ }
+
+ var buildStatementCache BuildStatementCacheFunc
+ statementCacheCapacity := 512
+ statementCacheMode := stmtcache.ModePrepare
+ if s, ok := config.RuntimeParams["statement_cache_capacity"]; ok {
+ delete(config.RuntimeParams, "statement_cache_capacity")
+ n, err := strconv.ParseInt(s, 10, 32)
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse statement_cache_capacity: %w", err)
+ }
+ statementCacheCapacity = int(n)
+ }
+
+ if s, ok := config.RuntimeParams["statement_cache_mode"]; ok {
+ delete(config.RuntimeParams, "statement_cache_mode")
+ switch s {
+ case "prepare":
+ statementCacheMode = stmtcache.ModePrepare
+ case "describe":
+ statementCacheMode = stmtcache.ModeDescribe
+ default:
+ return nil, fmt.Errorf("invalid statement_cache_mod: %s", s)
+ }
+ }
+
+ if statementCacheCapacity > 0 {
+ buildStatementCache = func(conn *pgconn.PgConn) stmtcache.Cache {
+ return stmtcache.New(conn, statementCacheMode, statementCacheCapacity)
+ }
+ }
+
+ preferSimpleProtocol := false
+ if s, ok := config.RuntimeParams["prefer_simple_protocol"]; ok {
+ delete(config.RuntimeParams, "prefer_simple_protocol")
+ if b, err := strconv.ParseBool(s); err == nil {
+ preferSimpleProtocol = b
+ } else {
+ return nil, fmt.Errorf("invalid prefer_simple_protocol: %v", err)
+ }
+ }
+
+ connConfig := &ConnConfig{
+ Config: *config,
+ createdByParseConfig: true,
+ LogLevel: LogLevelInfo,
+ BuildStatementCache: buildStatementCache,
+ PreferSimpleProtocol: preferSimpleProtocol,
+ connString: connString,
+ }
+
+ return connConfig, nil
+}
+
+func connect(ctx context.Context, config *ConnConfig) (c *Conn, err error) {
+ // Default values are set in ParseConfig. Enforce initial creation by ParseConfig rather than setting defaults from
+ // zero values.
+ if !config.createdByParseConfig {
+ panic("config must be created by ParseConfig")
+ }
+ originalConfig := config
+
+ // This isn't really a deep copy. But it is enough to avoid the config.Config.OnNotification mutation from affecting
+ // other connections with the same config. See https://github.com/jackc/pgx/issues/618.
+ {
+ configCopy := *config
+ config = &configCopy
+ }
+
+ c = &Conn{
+ config: originalConfig,
+ connInfo: pgtype.NewConnInfo(),
+ logLevel: config.LogLevel,
+ logger: config.Logger,
+ }
+
+ // Only install pgx notification system if no other callback handler is present.
+ if config.Config.OnNotification == nil {
+ config.Config.OnNotification = c.bufferNotifications
+ } else {
+ if c.shouldLog(LogLevelDebug) {
+ c.log(ctx, LogLevelDebug, "pgx notification handler disabled by application supplied OnNotification", map[string]interface{}{"host": config.Config.Host})
+ }
+ }
+
+ if c.shouldLog(LogLevelInfo) {
+ c.log(ctx, LogLevelInfo, "Dialing PostgreSQL server", map[string]interface{}{"host": config.Config.Host})
+ }
+ c.pgConn, err = pgconn.ConnectConfig(ctx, &config.Config)
+ if err != nil {
+ if c.shouldLog(LogLevelError) {
+ c.log(ctx, LogLevelError, "connect failed", map[string]interface{}{"err": err})
+ }
+ return nil, err
+ }
+
+ c.preparedStatements = make(map[string]*pgconn.StatementDescription)
+ c.doneChan = make(chan struct{})
+ c.closedChan = make(chan error)
+ c.wbuf = make([]byte, 0, 1024)
+
+ if c.config.BuildStatementCache != nil {
+ c.stmtcache = c.config.BuildStatementCache(c.pgConn)
+ }
+
+ // Replication connections can't execute the queries to
+ // populate the c.PgTypes and c.pgsqlAfInet
+ if _, ok := config.Config.RuntimeParams["replication"]; ok {
+ return c, nil
+ }
+
+ return c, nil
+}
+
+// Close closes a connection. It is safe to call Close on a already closed
+// connection.
+func (c *Conn) Close(ctx context.Context) error {
+ if c.IsClosed() {
+ return nil
+ }
+
+ err := c.pgConn.Close(ctx)
+ if c.shouldLog(LogLevelInfo) {
+ c.log(ctx, LogLevelInfo, "closed connection", nil)
+ }
+ return err
+}
+
+// Prepare creates a prepared statement with name and sql. sql can contain placeholders
+// for bound parameters. These placeholders are referenced positional as $1, $2, etc.
+//
+// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same
+// name and sql arguments. This allows a code path to Prepare and Query/Exec without
+// concern for if the statement has already been prepared.
+func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.StatementDescription, err error) {
+ if name != "" {
+ var ok bool
+ if sd, ok = c.preparedStatements[name]; ok && sd.SQL == sql {
+ return sd, nil
+ }
+ }
+
+ if c.shouldLog(LogLevelError) {
+ defer func() {
+ if err != nil {
+ c.log(ctx, LogLevelError, "Prepare failed", map[string]interface{}{"err": err, "name": name, "sql": sql})
+ }
+ }()
+ }
+
+ sd, err = c.pgConn.Prepare(ctx, name, sql, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if name != "" {
+ c.preparedStatements[name] = sd
+ }
+
+ return sd, nil
+}
+
+// Deallocate released a prepared statement
+func (c *Conn) Deallocate(ctx context.Context, name string) error {
+ delete(c.preparedStatements, name)
+ _, err := c.pgConn.Exec(ctx, "deallocate "+quoteIdentifier(name)).ReadAll()
+ return err
+}
+
+func (c *Conn) bufferNotifications(_ *pgconn.PgConn, n *pgconn.Notification) {
+ c.notifications = append(c.notifications, n)
+}
+
+// WaitForNotification waits for a PostgreSQL notification. It wraps the underlying pgconn notification system in a
+// slightly more convenient form.
+func (c *Conn) WaitForNotification(ctx context.Context) (*pgconn.Notification, error) {
+ var n *pgconn.Notification
+
+ // Return already received notification immediately
+ if len(c.notifications) > 0 {
+ n = c.notifications[0]
+ c.notifications = c.notifications[1:]
+ return n, nil
+ }
+
+ err := c.pgConn.WaitForNotification(ctx)
+ if len(c.notifications) > 0 {
+ n = c.notifications[0]
+ c.notifications = c.notifications[1:]
+ }
+ return n, err
+}
+
+func (c *Conn) IsClosed() bool {
+ return c.pgConn.IsClosed()
+}
+
+func (c *Conn) die(err error) {
+ if c.IsClosed() {
+ return
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ cancel() // force immediate hard cancel
+ c.pgConn.Close(ctx)
+}
+
+func (c *Conn) shouldLog(lvl LogLevel) bool {
+ return c.logger != nil && c.logLevel >= lvl
+}
+
+func (c *Conn) log(ctx context.Context, lvl LogLevel, msg string, data map[string]interface{}) {
+ if data == nil {
+ data = map[string]interface{}{}
+ }
+ if c.pgConn != nil && c.pgConn.PID() != 0 {
+ data["pid"] = c.pgConn.PID()
+ }
+
+ c.logger.Log(ctx, lvl, msg, data)
+}
+
+func quoteIdentifier(s string) string {
+ return `"` + strings.ReplaceAll(s, `"`, `""`) + `"`
+}
+
+func (c *Conn) Ping(ctx context.Context) error {
+ _, err := c.Exec(ctx, ";")
+ return err
+}
+
+func connInfoFromRows(rows Rows, err error) (map[string]uint32, error) {
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ nameOIDs := make(map[string]uint32, 256)
+ for rows.Next() {
+ var oid uint32
+ var name pgtype.Text
+ if err = rows.Scan(&oid, &name); err != nil {
+ return nil, err
+ }
+
+ nameOIDs[name.String] = oid
+ }
+
+ if err = rows.Err(); err != nil {
+ return nil, err
+ }
+
+ return nameOIDs, err
+}
+
+// PgConn returns the underlying *pgconn.PgConn. This is an escape hatch method that allows lower level access to the
+// PostgreSQL connection than pgx exposes.
+//
+// It is strongly recommended that the connection be idle (no in-progress queries) before the underlying *pgconn.PgConn
+// is used and the connection must be returned to the same state before any *pgx.Conn methods are again used.
+func (c *Conn) PgConn() *pgconn.PgConn { return c.pgConn }
+
+// StatementCache returns the statement cache used for this connection.
+func (c *Conn) StatementCache() stmtcache.Cache { return c.stmtcache }
+
+// ConnInfo returns the connection info used for this connection.
+func (c *Conn) ConnInfo() *pgtype.ConnInfo { return c.connInfo }
+
+// Config returns a copy of config that was used to establish this connection.
+func (c *Conn) Config() *ConnConfig { return c.config.Copy() }
+
+// Exec executes sql. sql can be either a prepared statement name or an SQL string. arguments should be referenced
+// positionally from the sql string as $1, $2, etc.
+func (c *Conn) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) {
+ startTime := time.Now()
+
+ commandTag, err := c.exec(ctx, sql, arguments...)
+ if err != nil {
+ if c.shouldLog(LogLevelError) {
+ c.log(ctx, LogLevelError, "Exec", map[string]interface{}{"sql": sql, "args": logQueryArgs(arguments), "err": err})
+ }
+ return commandTag, err
+ }
+
+ if c.shouldLog(LogLevelInfo) {
+ endTime := time.Now()
+ c.log(ctx, LogLevelInfo, "Exec", map[string]interface{}{"sql": sql, "args": logQueryArgs(arguments), "time": endTime.Sub(startTime), "commandTag": commandTag})
+ }
+
+ return commandTag, err
+}
+
+func (c *Conn) exec(ctx context.Context, sql string, arguments ...interface{}) (commandTag pgconn.CommandTag, err error) {
+ simpleProtocol := c.config.PreferSimpleProtocol
+
+optionLoop:
+ for len(arguments) > 0 {
+ switch arg := arguments[0].(type) {
+ case QuerySimpleProtocol:
+ simpleProtocol = bool(arg)
+ arguments = arguments[1:]
+ default:
+ break optionLoop
+ }
+ }
+
+ if sd, ok := c.preparedStatements[sql]; ok {
+ return c.execPrepared(ctx, sd, arguments)
+ }
+
+ if simpleProtocol {
+ return c.execSimpleProtocol(ctx, sql, arguments)
+ }
+
+ if len(arguments) == 0 {
+ return c.execSimpleProtocol(ctx, sql, arguments)
+ }
+
+ if c.stmtcache != nil {
+ sd, err := c.stmtcache.Get(ctx, sql)
+ if err != nil {
+ return nil, err
+ }
+
+ if c.stmtcache.Mode() == stmtcache.ModeDescribe {
+ return c.execParams(ctx, sd, arguments)
+ }
+ return c.execPrepared(ctx, sd, arguments)
+ }
+
+ sd, err := c.Prepare(ctx, "", sql)
+ if err != nil {
+ return nil, err
+ }
+ return c.execPrepared(ctx, sd, arguments)
+}
+
+func (c *Conn) execSimpleProtocol(ctx context.Context, sql string, arguments []interface{}) (commandTag pgconn.CommandTag, err error) {
+ if len(arguments) > 0 {
+ sql, err = c.sanitizeForSimpleQuery(sql, arguments...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ mrr := c.pgConn.Exec(ctx, sql)
+ for mrr.NextResult() {
+ commandTag, err = mrr.ResultReader().Close()
+ }
+ err = mrr.Close()
+ return commandTag, err
+}
+
+func (c *Conn) execParamsAndPreparedPrefix(sd *pgconn.StatementDescription, arguments []interface{}) error {
+ if len(sd.ParamOIDs) != len(arguments) {
+ return fmt.Errorf("expected %d arguments, got %d", len(sd.ParamOIDs), len(arguments))
+ }
+
+ c.eqb.Reset()
+
+ args, err := convertDriverValuers(arguments)
+ if err != nil {
+ return err
+ }
+
+ for i := range args {
+ err = c.eqb.AppendParam(c.connInfo, sd.ParamOIDs[i], args[i])
+ if err != nil {
+ return err
+ }
+ }
+
+ for i := range sd.Fields {
+ c.eqb.AppendResultFormat(c.ConnInfo().ResultFormatCodeForOID(sd.Fields[i].DataTypeOID))
+ }
+
+ return nil
+}
+
+func (c *Conn) execParams(ctx context.Context, sd *pgconn.StatementDescription, arguments []interface{}) (pgconn.CommandTag, error) {
+ err := c.execParamsAndPreparedPrefix(sd, arguments)
+ if err != nil {
+ return nil, err
+ }
+
+ result := c.pgConn.ExecParams(ctx, sd.SQL, c.eqb.paramValues, sd.ParamOIDs, c.eqb.paramFormats, c.eqb.resultFormats).Read()
+ return result.CommandTag, result.Err
+}
+
+func (c *Conn) execPrepared(ctx context.Context, sd *pgconn.StatementDescription, arguments []interface{}) (pgconn.CommandTag, error) {
+ err := c.execParamsAndPreparedPrefix(sd, arguments)
+ if err != nil {
+ return nil, err
+ }
+
+ result := c.pgConn.ExecPrepared(ctx, sd.Name, c.eqb.paramValues, c.eqb.paramFormats, c.eqb.resultFormats).Read()
+ return result.CommandTag, result.Err
+}
+
+func (c *Conn) getRows(ctx context.Context, sql string, args []interface{}) *connRows {
+ if len(c.preallocatedRows) == 0 {
+ c.preallocatedRows = make([]connRows, 64)
+ }
+
+ r := &c.preallocatedRows[len(c.preallocatedRows)-1]
+ c.preallocatedRows = c.preallocatedRows[0 : len(c.preallocatedRows)-1]
+
+ r.ctx = ctx
+ r.logger = c
+ r.connInfo = c.connInfo
+ r.startTime = time.Now()
+ r.sql = sql
+ r.args = args
+ r.conn = c
+
+ return r
+}
+
+// QuerySimpleProtocol controls whether the simple or extended protocol is used to send the query.
+type QuerySimpleProtocol bool
+
+// QueryResultFormats controls the result format (text=0, binary=1) of a query by result column position.
+type QueryResultFormats []int16
+
+// QueryResultFormatsByOID controls the result format (text=0, binary=1) of a query by the result column OID.
+type QueryResultFormatsByOID map[uint32]int16
+
+// Query executes sql with args. If there is an error the returned Rows will be returned in an error state. So it is
+// allowed to ignore the error returned from Query and handle it in Rows.
+//
+// For extra control over how the query is executed, the types QuerySimpleProtocol, QueryResultFormats, and
+// QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely
+// needed. See the documentation for those types for details.
+func (c *Conn) Query(ctx context.Context, sql string, args ...interface{}) (Rows, error) {
+ var resultFormats QueryResultFormats
+ var resultFormatsByOID QueryResultFormatsByOID
+ simpleProtocol := c.config.PreferSimpleProtocol
+
+optionLoop:
+ for len(args) > 0 {
+ switch arg := args[0].(type) {
+ case QueryResultFormats:
+ resultFormats = arg
+ args = args[1:]
+ case QueryResultFormatsByOID:
+ resultFormatsByOID = arg
+ args = args[1:]
+ case QuerySimpleProtocol:
+ simpleProtocol = bool(arg)
+ args = args[1:]
+ default:
+ break optionLoop
+ }
+ }
+
+ rows := c.getRows(ctx, sql, args)
+
+ var err error
+ sd, ok := c.preparedStatements[sql]
+
+ if simpleProtocol && !ok {
+ sql, err = c.sanitizeForSimpleQuery(sql, args...)
+ if err != nil {
+ rows.fatal(err)
+ return rows, err
+ }
+
+ mrr := c.pgConn.Exec(ctx, sql)
+ if mrr.NextResult() {
+ rows.resultReader = mrr.ResultReader()
+ rows.multiResultReader = mrr
+ } else {
+ err = mrr.Close()
+ rows.fatal(err)
+ return rows, err
+ }
+
+ return rows, nil
+ }
+
+ c.eqb.Reset()
+
+ if !ok {
+ if c.stmtcache != nil {
+ sd, err = c.stmtcache.Get(ctx, sql)
+ if err != nil {
+ rows.fatal(err)
+ return rows, rows.err
+ }
+ } else {
+ sd, err = c.pgConn.Prepare(ctx, "", sql, nil)
+ if err != nil {
+ rows.fatal(err)
+ return rows, rows.err
+ }
+ }
+ }
+ if len(sd.ParamOIDs) != len(args) {
+ rows.fatal(fmt.Errorf("expected %d arguments, got %d", len(sd.ParamOIDs), len(args)))
+ return rows, rows.err
+ }
+
+ rows.sql = sd.SQL
+
+ args, err = convertDriverValuers(args)
+ if err != nil {
+ rows.fatal(err)
+ return rows, rows.err
+ }
+
+ for i := range args {
+ err = c.eqb.AppendParam(c.connInfo, sd.ParamOIDs[i], args[i])
+ if err != nil {
+ rows.fatal(err)
+ return rows, rows.err
+ }
+ }
+
+ if resultFormatsByOID != nil {
+ resultFormats = make([]int16, len(sd.Fields))
+ for i := range resultFormats {
+ resultFormats[i] = resultFormatsByOID[uint32(sd.Fields[i].DataTypeOID)]
+ }
+ }
+
+ if resultFormats == nil {
+ for i := range sd.Fields {
+ c.eqb.AppendResultFormat(c.ConnInfo().ResultFormatCodeForOID(sd.Fields[i].DataTypeOID))
+ }
+
+ resultFormats = c.eqb.resultFormats
+ }
+
+ if c.stmtcache != nil && c.stmtcache.Mode() == stmtcache.ModeDescribe {
+ rows.resultReader = c.pgConn.ExecParams(ctx, sql, c.eqb.paramValues, sd.ParamOIDs, c.eqb.paramFormats, resultFormats)
+ } else {
+ rows.resultReader = c.pgConn.ExecPrepared(ctx, sd.Name, c.eqb.paramValues, c.eqb.paramFormats, resultFormats)
+ }
+
+ return rows, rows.err
+}
+
+// QueryRow is a convenience wrapper over Query. Any error that occurs while
+// querying is deferred until calling Scan on the returned Row. That Row will
+// error with ErrNoRows if no rows are returned.
+func (c *Conn) QueryRow(ctx context.Context, sql string, args ...interface{}) Row {
+ rows, _ := c.Query(ctx, sql, args...)
+ return (*connRow)(rows.(*connRows))
+}
+
+// QueryFuncRow is the argument to the QueryFunc callback function.
+//
+// QueryFuncRow is an interface instead of a struct to allow tests to mock QueryFunc. However, adding a method to an
+// interface is technically a breaking change. Because of this the QueryFuncRow interface is partially excluded from
+// semantic version requirements. Methods will not be removed or changed, but new methods may be added.
+type QueryFuncRow interface {
+ FieldDescriptions() []pgproto3.FieldDescription
+
+ // RawValues returns the unparsed bytes of the row values. The returned [][]byte is only valid during the current
+ // function call. However, the underlying byte data is safe to retain a reference to and mutate.
+ RawValues() [][]byte
+}
+
+// QueryFunc executes sql with args. For each row returned by the query the values will scanned into the elements of
+// scans and f will be called. If any row fails to scan or f returns an error the query will be aborted and the error
+// will be returned.
+func (c *Conn) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error) {
+ rows, err := c.Query(ctx, sql, args...)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ err = rows.Scan(scans...)
+ if err != nil {
+ return nil, err
+ }
+
+ err = f(rows)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+
+ return rows.CommandTag(), nil
+}
+
+// SendBatch sends all queued queries to the server at once. All queries are run in an implicit transaction unless
+// explicit transaction control statements are executed. The returned BatchResults must be closed before the connection
+// is used again.
+func (c *Conn) SendBatch(ctx context.Context, b *Batch) BatchResults {
+ simpleProtocol := c.config.PreferSimpleProtocol
+ var sb strings.Builder
+ if simpleProtocol {
+ for i, bi := range b.items {
+ if i > 0 {
+ sb.WriteByte(';')
+ }
+ sql, err := c.sanitizeForSimpleQuery(bi.query, bi.arguments...)
+ if err != nil {
+ return &batchResults{ctx: ctx, conn: c, err: err}
+ }
+ sb.WriteString(sql)
+ }
+ mrr := c.pgConn.Exec(ctx, sb.String())
+ return &batchResults{
+ ctx: ctx,
+ conn: c,
+ mrr: mrr,
+ b: b,
+ ix: 0,
+ }
+ }
+
+ distinctUnpreparedQueries := map[string]struct{}{}
+
+ for _, bi := range b.items {
+ if _, ok := c.preparedStatements[bi.query]; ok {
+ continue
+ }
+ distinctUnpreparedQueries[bi.query] = struct{}{}
+ }
+
+ var stmtCache stmtcache.Cache
+ if len(distinctUnpreparedQueries) > 0 {
+ if c.stmtcache != nil && c.stmtcache.Cap() >= len(distinctUnpreparedQueries) {
+ stmtCache = c.stmtcache
+ } else {
+ stmtCache = stmtcache.New(c.pgConn, stmtcache.ModeDescribe, len(distinctUnpreparedQueries))
+ }
+
+ for sql, _ := range distinctUnpreparedQueries {
+ _, err := stmtCache.Get(ctx, sql)
+ if err != nil {
+ return &batchResults{ctx: ctx, conn: c, err: err}
+ }
+ }
+ }
+
+ batch := &pgconn.Batch{}
+
+ for _, bi := range b.items {
+ c.eqb.Reset()
+
+ sd := c.preparedStatements[bi.query]
+ if sd == nil {
+ var err error
+ sd, err = stmtCache.Get(ctx, bi.query)
+ if err != nil {
+ // the stmtCache was prefilled from distinctUnpreparedQueries above so we are guaranteed no errors
+ panic("BUG: unexpected error from stmtCache")
+ }
+ }
+
+ if len(sd.ParamOIDs) != len(bi.arguments) {
+ return &batchResults{ctx: ctx, conn: c, err: fmt.Errorf("mismatched param and argument count")}
+ }
+
+ args, err := convertDriverValuers(bi.arguments)
+ if err != nil {
+ return &batchResults{ctx: ctx, conn: c, err: err}
+ }
+
+ for i := range args {
+ err = c.eqb.AppendParam(c.connInfo, sd.ParamOIDs[i], args[i])
+ if err != nil {
+ return &batchResults{ctx: ctx, conn: c, err: err}
+ }
+ }
+
+ for i := range sd.Fields {
+ c.eqb.AppendResultFormat(c.ConnInfo().ResultFormatCodeForOID(sd.Fields[i].DataTypeOID))
+ }
+
+ if sd.Name == "" {
+ batch.ExecParams(bi.query, c.eqb.paramValues, sd.ParamOIDs, c.eqb.paramFormats, c.eqb.resultFormats)
+ } else {
+ batch.ExecPrepared(sd.Name, c.eqb.paramValues, c.eqb.paramFormats, c.eqb.resultFormats)
+ }
+ }
+
+ mrr := c.pgConn.ExecBatch(ctx, batch)
+
+ return &batchResults{
+ ctx: ctx,
+ conn: c,
+ mrr: mrr,
+ b: b,
+ ix: 0,
+ }
+}
+
+func (c *Conn) sanitizeForSimpleQuery(sql string, args ...interface{}) (string, error) {
+ if c.pgConn.ParameterStatus("standard_conforming_strings") != "on" {
+ return "", errors.New("simple protocol queries must be run with standard_conforming_strings=on")
+ }
+
+ if c.pgConn.ParameterStatus("client_encoding") != "UTF8" {
+ return "", errors.New("simple protocol queries must be run with client_encoding=UTF8")
+ }
+
+ var err error
+ valueArgs := make([]interface{}, len(args))
+ for i, a := range args {
+ valueArgs[i], err = convertSimpleArgument(c.connInfo, a)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ return sanitize.SanitizeSQL(sql, valueArgs...)
+}
diff --git a/vendor/github.com/jackc/pgx/v4/copy_from.go b/vendor/github.com/jackc/pgx/v4/copy_from.go
new file mode 100644
index 000000000..3494e28f9
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/copy_from.go
@@ -0,0 +1,211 @@
+package pgx
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/jackc/pgconn"
+ "github.com/jackc/pgio"
+)
+
+// CopyFromRows returns a CopyFromSource interface over the provided rows slice
+// making it usable by *Conn.CopyFrom.
+func CopyFromRows(rows [][]interface{}) CopyFromSource {
+ return &copyFromRows{rows: rows, idx: -1}
+}
+
+type copyFromRows struct {
+ rows [][]interface{}
+ idx int
+}
+
+func (ctr *copyFromRows) Next() bool {
+ ctr.idx++
+ return ctr.idx < len(ctr.rows)
+}
+
+func (ctr *copyFromRows) Values() ([]interface{}, error) {
+ return ctr.rows[ctr.idx], nil
+}
+
+func (ctr *copyFromRows) Err() error {
+ return nil
+}
+
+// CopyFromSlice returns a CopyFromSource interface over a dynamic func
+// making it usable by *Conn.CopyFrom.
+func CopyFromSlice(length int, next func(int) ([]interface{}, error)) CopyFromSource {
+ return &copyFromSlice{next: next, idx: -1, len: length}
+}
+
+type copyFromSlice struct {
+ next func(int) ([]interface{}, error)
+ idx int
+ len int
+ err error
+}
+
+func (cts *copyFromSlice) Next() bool {
+ cts.idx++
+ return cts.idx < cts.len
+}
+
+func (cts *copyFromSlice) Values() ([]interface{}, error) {
+ values, err := cts.next(cts.idx)
+ if err != nil {
+ cts.err = err
+ }
+ return values, err
+}
+
+func (cts *copyFromSlice) Err() error {
+ return cts.err
+}
+
+// CopyFromSource is the interface used by *Conn.CopyFrom as the source for copy data.
+type CopyFromSource interface {
+ // Next returns true if there is another row and makes the next row data
+ // available to Values(). When there are no more rows available or an error
+ // has occurred it returns false.
+ Next() bool
+
+ // Values returns the values for the current row.
+ Values() ([]interface{}, error)
+
+ // Err returns any error that has been encountered by the CopyFromSource. If
+ // this is not nil *Conn.CopyFrom will abort the copy.
+ Err() error
+}
+
+type copyFrom struct {
+ conn *Conn
+ tableName Identifier
+ columnNames []string
+ rowSrc CopyFromSource
+ readerErrChan chan error
+}
+
+func (ct *copyFrom) run(ctx context.Context) (int64, error) {
+ quotedTableName := ct.tableName.Sanitize()
+ cbuf := &bytes.Buffer{}
+ for i, cn := range ct.columnNames {
+ if i != 0 {
+ cbuf.WriteString(", ")
+ }
+ cbuf.WriteString(quoteIdentifier(cn))
+ }
+ quotedColumnNames := cbuf.String()
+
+ sd, err := ct.conn.Prepare(ctx, "", fmt.Sprintf("select %s from %s", quotedColumnNames, quotedTableName))
+ if err != nil {
+ return 0, err
+ }
+
+ r, w := io.Pipe()
+ doneChan := make(chan struct{})
+
+ go func() {
+ defer close(doneChan)
+
+ // Purposely NOT using defer w.Close(). See https://github.com/golang/go/issues/24283.
+ buf := ct.conn.wbuf
+
+ buf = append(buf, "PGCOPY\n\377\r\n\000"...)
+ buf = pgio.AppendInt32(buf, 0)
+ buf = pgio.AppendInt32(buf, 0)
+
+ moreRows := true
+ for moreRows {
+ var err error
+ moreRows, buf, err = ct.buildCopyBuf(buf, sd)
+ if err != nil {
+ w.CloseWithError(err)
+ return
+ }
+
+ if ct.rowSrc.Err() != nil {
+ w.CloseWithError(ct.rowSrc.Err())
+ return
+ }
+
+ if len(buf) > 0 {
+ _, err = w.Write(buf)
+ if err != nil {
+ w.Close()
+ return
+ }
+ }
+
+ buf = buf[:0]
+ }
+
+ w.Close()
+ }()
+
+ startTime := time.Now()
+
+ commandTag, err := ct.conn.pgConn.CopyFrom(ctx, r, fmt.Sprintf("copy %s ( %s ) from stdin binary;", quotedTableName, quotedColumnNames))
+
+ r.Close()
+ <-doneChan
+
+ rowsAffected := commandTag.RowsAffected()
+ if err == nil {
+ if ct.conn.shouldLog(LogLevelInfo) {
+ endTime := time.Now()
+ ct.conn.log(ctx, LogLevelInfo, "CopyFrom", map[string]interface{}{"tableName": ct.tableName, "columnNames": ct.columnNames, "time": endTime.Sub(startTime), "rowCount": rowsAffected})
+ }
+ } else if ct.conn.shouldLog(LogLevelError) {
+ ct.conn.log(ctx, LogLevelError, "CopyFrom", map[string]interface{}{"err": err, "tableName": ct.tableName, "columnNames": ct.columnNames})
+ }
+
+ return rowsAffected, err
+}
+
+func (ct *copyFrom) buildCopyBuf(buf []byte, sd *pgconn.StatementDescription) (bool, []byte, error) {
+
+ for ct.rowSrc.Next() {
+ values, err := ct.rowSrc.Values()
+ if err != nil {
+ return false, nil, err
+ }
+ if len(values) != len(ct.columnNames) {
+ return false, nil, fmt.Errorf("expected %d values, got %d values", len(ct.columnNames), len(values))
+ }
+
+ buf = pgio.AppendInt16(buf, int16(len(ct.columnNames)))
+ for i, val := range values {
+ buf, err = encodePreparedStatementArgument(ct.conn.connInfo, buf, sd.Fields[i].DataTypeOID, val)
+ if err != nil {
+ return false, nil, err
+ }
+ }
+
+ if len(buf) > 65536 {
+ return true, buf, nil
+ }
+ }
+
+ return false, buf, nil
+}
+
+// CopyFrom uses the PostgreSQL copy protocol to perform bulk data insertion.
+// It returns the number of rows copied and an error.
+//
+// CopyFrom requires all values use the binary format. Almost all types
+// implemented by pgx use the binary format by default. Types implementing
+// Encoder can only be used if they encode to the binary format.
+func (c *Conn) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+ ct := &copyFrom{
+ conn: c,
+ tableName: tableName,
+ columnNames: columnNames,
+ rowSrc: rowSrc,
+ readerErrChan: make(chan error),
+ }
+
+ return ct.run(ctx)
+}
diff --git a/vendor/github.com/jackc/pgx/v4/doc.go b/vendor/github.com/jackc/pgx/v4/doc.go
new file mode 100644
index 000000000..51b0d9f44
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/doc.go
@@ -0,0 +1,340 @@
+// Package pgx is a PostgreSQL database driver.
+/*
+pgx provides lower level access to PostgreSQL than the standard database/sql. It remains as similar to the database/sql
+interface as possible while providing better speed and access to PostgreSQL specific features. Import
+github.com/jackc/pgx/v4/stdlib to use pgx as a database/sql compatible driver.
+
+Establishing a Connection
+
+The primary way of establishing a connection is with `pgx.Connect`.
+
+ conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
+
+The database connection string can be in URL or DSN format. Both PostgreSQL settings and pgx settings can be specified
+here. In addition, a config struct can be created by `ParseConfig` and modified before establishing the connection with
+`ConnectConfig`.
+
+ config, err := pgx.ParseConfig(os.Getenv("DATABASE_URL"))
+ if err != nil {
+ // ...
+ }
+ config.Logger = log15adapter.NewLogger(log.New("module", "pgx"))
+
+ conn, err := pgx.ConnectConfig(context.Background(), config)
+
+Connection Pool
+
+`*pgx.Conn` represents a single connection to the database and is not concurrency safe. Use sub-package pgxpool for a
+concurrency safe connection pool.
+
+Query Interface
+
+pgx implements Query and Scan in the familiar database/sql style.
+
+ var sum int32
+
+ // Send the query to the server. The returned rows MUST be closed
+ // before conn can be used again.
+ rows, err := conn.Query(context.Background(), "select generate_series(1,$1)", 10)
+ if err != nil {
+ return err
+ }
+
+ // rows.Close is called by rows.Next when all rows are read
+ // or an error occurs in Next or Scan. So it may optionally be
+ // omitted if nothing in the rows.Next loop can panic. It is
+ // safe to close rows multiple times.
+ defer rows.Close()
+
+ // Iterate through the result set
+ for rows.Next() {
+ var n int32
+ err = rows.Scan(&n)
+ if err != nil {
+ return err
+ }
+ sum += n
+ }
+
+ // Any errors encountered by rows.Next or rows.Scan will be returned here
+ if rows.Err() != nil {
+ return rows.Err()
+ }
+
+ // No errors found - do something with sum
+
+pgx also implements QueryRow in the same style as database/sql.
+
+ var name string
+ var weight int64
+ err := conn.QueryRow(context.Background(), "select name, weight from widgets where id=$1", 42).Scan(&name, &weight)
+ if err != nil {
+ return err
+ }
+
+Use Exec to execute a query that does not return a result set.
+
+ commandTag, err := conn.Exec(context.Background(), "delete from widgets where id=$1", 42)
+ if err != nil {
+ return err
+ }
+ if commandTag.RowsAffected() != 1 {
+ return errors.New("No row found to delete")
+ }
+
+QueryFunc can be used to execute a callback function for every row. This is often easier to use than Query.
+
+ var sum, n int32
+ _, err = conn.QueryFunc(
+ context.Background(),
+ "select generate_series(1,$1)",
+ []interface{}{10},
+ []interface{}{&n},
+ func(pgx.QueryFuncRow) error {
+ sum += n
+ return nil
+ },
+ )
+ if err != nil {
+ return err
+ }
+
+Base Type Mapping
+
+pgx maps between all common base types directly between Go and PostgreSQL. In particular:
+
+ Go PostgreSQL
+ -----------------------
+ string varchar
+ text
+
+ // Integers are automatically be converted to any other integer type if
+ // it can be done without overflow or underflow.
+ int8
+ int16 smallint
+ int32 int
+ int64 bigint
+ int
+ uint8
+ uint16
+ uint32
+ uint64
+ uint
+
+ // Floats are strict and do not automatically convert like integers.
+ float32 float4
+ float64 float8
+
+ time.Time date
+ timestamp
+ timestamptz
+
+ []byte bytea
+
+
+Null Mapping
+
+pgx can map nulls in two ways. The first is package pgtype provides types that have a data field and a status field.
+They work in a similar fashion to database/sql. The second is to use a pointer to a pointer.
+
+ var foo pgtype.Varchar
+ var bar *string
+ err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&foo, &bar)
+ if err != nil {
+ return err
+ }
+
+Array Mapping
+
+pgx maps between int16, int32, int64, float32, float64, and string Go slices and the equivalent PostgreSQL array type.
+Go slices of native types do not support nulls, so if a PostgreSQL array that contains a null is read into a native Go
+slice an error will occur. The pgtype package includes many more array types for PostgreSQL types that do not directly
+map to native Go types.
+
+JSON and JSONB Mapping
+
+pgx includes built-in support to marshal and unmarshal between Go types and the PostgreSQL JSON and JSONB.
+
+Inet and CIDR Mapping
+
+pgx encodes from net.IPNet to and from inet and cidr PostgreSQL types. In addition, as a convenience pgx will encode
+from a net.IP; it will assume a /32 netmask for IPv4 and a /128 for IPv6.
+
+Custom Type Support
+
+pgx includes support for the common data types like integers, floats, strings, dates, and times that have direct
+mappings between Go and SQL. In addition, pgx uses the github.com/jackc/pgtype library to support more types. See
+documention for that library for instructions on how to implement custom types.
+
+See example_custom_type_test.go for an example of a custom type for the PostgreSQL point type.
+
+pgx also includes support for custom types implementing the database/sql.Scanner and database/sql/driver.Valuer
+interfaces.
+
+If pgx does cannot natively encode a type and that type is a renamed type (e.g. type MyTime time.Time) pgx will attempt
+to encode the underlying type. While this is usually desired behavior it can produce surprising behavior if one the
+underlying type and the renamed type each implement database/sql interfaces and the other implements pgx interfaces. It
+is recommended that this situation be avoided by implementing pgx interfaces on the renamed type.
+
+Composite types and row values
+
+Row values and composite types are represented as pgtype.Record (https://pkg.go.dev/github.com/jackc/pgtype?tab=doc#Record).
+It is possible to get values of your custom type by implementing DecodeBinary interface. Decoding into
+pgtype.Record first can simplify process by avoiding dealing with raw protocol directly.
+
+For example:
+
+ type MyType struct {
+ a int // NULL will cause decoding error
+ b *string // there can be NULL in this position in SQL
+ }
+
+ func (t *MyType) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error {
+ r := pgtype.Record{
+ Fields: []pgtype.Value{&pgtype.Int4{}, &pgtype.Text{}},
+ }
+
+ if err := r.DecodeBinary(ci, src); err != nil {
+ return err
+ }
+
+ if r.Status != pgtype.Present {
+ return errors.New("BUG: decoding should not be called on NULL value")
+ }
+
+ a := r.Fields[0].(*pgtype.Int4)
+ b := r.Fields[1].(*pgtype.Text)
+
+ // type compatibility is checked by AssignTo
+ // only lossless assignments will succeed
+ if err := a.AssignTo(&t.a); err != nil {
+ return err
+ }
+
+ // AssignTo also deals with null value handling
+ if err := b.AssignTo(&t.b); err != nil {
+ return err
+ }
+ return nil
+ }
+
+ result := MyType{}
+ err := conn.QueryRow(context.Background(), "select row(1, 'foo'::text)", pgx.QueryResultFormats{pgx.BinaryFormatCode}).Scan(&r)
+
+Raw Bytes Mapping
+
+[]byte passed as arguments to Query, QueryRow, and Exec are passed unmodified to PostgreSQL.
+
+Transactions
+
+Transactions are started by calling Begin.
+
+ tx, err := conn.Begin(context.Background())
+ if err != nil {
+ return err
+ }
+ // Rollback is safe to call even if the tx is already closed, so if
+ // the tx commits successfully, this is a no-op
+ defer tx.Rollback(context.Background())
+
+ _, err = tx.Exec(context.Background(), "insert into foo(id) values (1)")
+ if err != nil {
+ return err
+ }
+
+ err = tx.Commit(context.Background())
+ if err != nil {
+ return err
+ }
+
+The Tx returned from Begin also implements the Begin method. This can be used to implement pseudo nested transactions.
+These are internally implemented with savepoints.
+
+Use BeginTx to control the transaction mode.
+
+BeginFunc and BeginTxFunc are variants that begin a transaction, execute a function, and commit or rollback the
+transaction depending on the return value of the function. These can be simpler and less error prone to use.
+
+ err = conn.BeginFunc(context.Background(), func(tx pgx.Tx) error {
+ _, err := tx.Exec(context.Background(), "insert into foo(id) values (1)")
+ return err
+ })
+ if err != nil {
+ return err
+ }
+
+Prepared Statements
+
+Prepared statements can be manually created with the Prepare method. However, this is rarely necessary because pgx
+includes an automatic statement cache by default. Queries run through the normal Query, QueryRow, and Exec functions are
+automatically prepared on first execution and the prepared statement is reused on subsequent executions. See ParseConfig
+for information on how to customize or disable the statement cache.
+
+Copy Protocol
+
+Use CopyFrom to efficiently insert multiple rows at a time using the PostgreSQL copy protocol. CopyFrom accepts a
+CopyFromSource interface. If the data is already in a [][]interface{} use CopyFromRows to wrap it in a CopyFromSource
+interface. Or implement CopyFromSource to avoid buffering the entire data set in memory.
+
+ rows := [][]interface{}{
+ {"John", "Smith", int32(36)},
+ {"Jane", "Doe", int32(29)},
+ }
+
+ copyCount, err := conn.CopyFrom(
+ context.Background(),
+ pgx.Identifier{"people"},
+ []string{"first_name", "last_name", "age"},
+ pgx.CopyFromRows(rows),
+ )
+
+When you already have a typed array using CopyFromSlice can be more convenient.
+
+ rows := []User{
+ {"John", "Smith", 36},
+ {"Jane", "Doe", 29},
+ }
+
+ copyCount, err := conn.CopyFrom(
+ context.Background(),
+ pgx.Identifier{"people"},
+ []string{"first_name", "last_name", "age"},
+ pgx.CopyFromSlice(len(rows), func(i int) ([]interface{}, error) {
+ return []interface{}{rows[i].FirstName, rows[i].LastName, rows[i].Age}, nil
+ }),
+ )
+
+CopyFrom can be faster than an insert with as few as 5 rows.
+
+Listen and Notify
+
+pgx can listen to the PostgreSQL notification system with the `Conn.WaitForNotification` method. It blocks until a
+context is received or the context is canceled.
+
+ _, err := conn.Exec(context.Background(), "listen channelname")
+ if err != nil {
+ return nil
+ }
+
+ if notification, err := conn.WaitForNotification(context.Background()); err != nil {
+ // do something with notification
+ }
+
+
+Logging
+
+pgx defines a simple logger interface. Connections optionally accept a logger that satisfies this interface. Set
+LogLevel to control logging verbosity. Adapters for github.com/inconshreveable/log15, github.com/sirupsen/logrus,
+go.uber.org/zap, github.com/rs/zerolog, and the testing log are provided in the log directory.
+
+Lower Level PostgreSQL Functionality
+
+pgx is implemented on top of github.com/jackc/pgconn a lower level PostgreSQL driver. The Conn.PgConn() method can be
+used to access this lower layer.
+
+PgBouncer
+
+pgx is compatible with PgBouncer in two modes. One is when the connection has a statement cache in "describe" mode. The
+other is when the connection is using the simple protocol. This can be set with the PreferSimpleProtocol config option.
+*/
+package pgx
diff --git a/vendor/github.com/jackc/pgx/v4/extended_query_builder.go b/vendor/github.com/jackc/pgx/v4/extended_query_builder.go
new file mode 100644
index 000000000..09419f0d0
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/extended_query_builder.go
@@ -0,0 +1,168 @@
+package pgx
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "reflect"
+
+ "github.com/jackc/pgtype"
+)
+
+type extendedQueryBuilder struct {
+ paramValues [][]byte
+ paramValueBytes []byte
+ paramFormats []int16
+ resultFormats []int16
+
+ resetCount int
+}
+
+func (eqb *extendedQueryBuilder) AppendParam(ci *pgtype.ConnInfo, oid uint32, arg interface{}) error {
+ f := chooseParameterFormatCode(ci, oid, arg)
+ eqb.paramFormats = append(eqb.paramFormats, f)
+
+ v, err := eqb.encodeExtendedParamValue(ci, oid, f, arg)
+ if err != nil {
+ return err
+ }
+ eqb.paramValues = append(eqb.paramValues, v)
+
+ return nil
+}
+
+func (eqb *extendedQueryBuilder) AppendResultFormat(f int16) {
+ eqb.resultFormats = append(eqb.resultFormats, f)
+}
+
+func (eqb *extendedQueryBuilder) Reset() {
+ eqb.paramValues = eqb.paramValues[0:0]
+ eqb.paramValueBytes = eqb.paramValueBytes[0:0]
+ eqb.paramFormats = eqb.paramFormats[0:0]
+ eqb.resultFormats = eqb.resultFormats[0:0]
+
+ eqb.resetCount++
+
+ // Every so often shrink our reserved memory if it is abnormally high
+ if eqb.resetCount%128 == 0 {
+ if cap(eqb.paramValues) > 64 {
+ eqb.paramValues = make([][]byte, 0, cap(eqb.paramValues)/2)
+ }
+
+ if cap(eqb.paramValueBytes) > 256 {
+ eqb.paramValueBytes = make([]byte, 0, cap(eqb.paramValueBytes)/2)
+ }
+
+ if cap(eqb.paramFormats) > 64 {
+ eqb.paramFormats = make([]int16, 0, cap(eqb.paramFormats)/2)
+ }
+ if cap(eqb.resultFormats) > 64 {
+ eqb.resultFormats = make([]int16, 0, cap(eqb.resultFormats)/2)
+ }
+ }
+
+}
+
+func (eqb *extendedQueryBuilder) encodeExtendedParamValue(ci *pgtype.ConnInfo, oid uint32, formatCode int16, arg interface{}) ([]byte, error) {
+ if arg == nil {
+ return nil, nil
+ }
+
+ refVal := reflect.ValueOf(arg)
+ argIsPtr := refVal.Kind() == reflect.Ptr
+
+ if argIsPtr && refVal.IsNil() {
+ return nil, nil
+ }
+
+ if eqb.paramValueBytes == nil {
+ eqb.paramValueBytes = make([]byte, 0, 128)
+ }
+
+ var err error
+ var buf []byte
+ pos := len(eqb.paramValueBytes)
+
+ if arg, ok := arg.(string); ok {
+ return []byte(arg), nil
+ }
+
+ if formatCode == TextFormatCode {
+ if arg, ok := arg.(pgtype.TextEncoder); ok {
+ buf, err = arg.EncodeText(ci, eqb.paramValueBytes)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ eqb.paramValueBytes = buf
+ return eqb.paramValueBytes[pos:], nil
+ }
+ } else if formatCode == BinaryFormatCode {
+ if arg, ok := arg.(pgtype.BinaryEncoder); ok {
+ buf, err = arg.EncodeBinary(ci, eqb.paramValueBytes)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ eqb.paramValueBytes = buf
+ return eqb.paramValueBytes[pos:], nil
+ }
+ }
+
+ if argIsPtr {
+ // We have already checked that arg is not pointing to nil,
+ // so it is safe to dereference here.
+ arg = refVal.Elem().Interface()
+ return eqb.encodeExtendedParamValue(ci, oid, formatCode, arg)
+ }
+
+ if dt, ok := ci.DataTypeForOID(oid); ok {
+ value := dt.Value
+ err := value.Set(arg)
+ if err != nil {
+ {
+ if arg, ok := arg.(driver.Valuer); ok {
+ v, err := callValuerValue(arg)
+ if err != nil {
+ return nil, err
+ }
+ return eqb.encodeExtendedParamValue(ci, oid, formatCode, v)
+ }
+ }
+
+ return nil, err
+ }
+
+ return eqb.encodeExtendedParamValue(ci, oid, formatCode, value)
+ }
+
+ // There is no data type registered for the destination OID, but maybe there is data type registered for the arg
+ // type. If so use it's text encoder (if available).
+ if dt, ok := ci.DataTypeForValue(arg); ok {
+ value := dt.Value
+ if textEncoder, ok := value.(pgtype.TextEncoder); ok {
+ err := value.Set(arg)
+ if err != nil {
+ return nil, err
+ }
+
+ buf, err = textEncoder.EncodeText(ci, eqb.paramValueBytes)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ eqb.paramValueBytes = buf
+ return eqb.paramValueBytes[pos:], nil
+ }
+ }
+
+ if strippedArg, ok := stripNamedType(&refVal); ok {
+ return eqb.encodeExtendedParamValue(ci, oid, formatCode, strippedArg)
+ }
+ return nil, SerializationError(fmt.Sprintf("Cannot encode %T into oid %v - %T must implement Encoder or be converted to a string", arg, oid, arg))
+}
diff --git a/vendor/github.com/jackc/pgx/v4/go.mod b/vendor/github.com/jackc/pgx/v4/go.mod
new file mode 100644
index 000000000..2d877032b
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/go.mod
@@ -0,0 +1,21 @@
+module github.com/jackc/pgx/v4
+
+go 1.13
+
+require (
+ github.com/Masterminds/semver/v3 v3.1.1
+ github.com/cockroachdb/apd v1.1.0
+ github.com/go-kit/log v0.1.0
+ github.com/gofrs/uuid v4.0.0+incompatible
+ github.com/jackc/pgconn v1.10.0
+ github.com/jackc/pgio v1.0.0
+ github.com/jackc/pgproto3/v2 v2.1.1
+ github.com/jackc/pgtype v1.8.1
+ github.com/jackc/puddle v1.1.3
+ github.com/rs/zerolog v1.15.0
+ github.com/shopspring/decimal v1.2.0
+ github.com/sirupsen/logrus v1.4.2
+ github.com/stretchr/testify v1.7.0
+ go.uber.org/zap v1.13.0
+ gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec
+)
diff --git a/vendor/github.com/jackc/pgx/v4/go.sum b/vendor/github.com/jackc/pgx/v4/go.sum
new file mode 100644
index 000000000..2222449d8
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/go.sum
@@ -0,0 +1,196 @@
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
+github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+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/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ=
+github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
+github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
+github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+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/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
+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.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
+github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
+github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
+github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
+github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
+github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
+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.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU=
+github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
+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/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
+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/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
+github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
+github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
+github.com/jackc/pgproto3/v2 v2.0.6/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/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/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-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
+github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
+github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs=
+github.com/jackc/pgtype v1.8.1/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-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.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
+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 v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94=
+github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
+github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
+github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
+github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
+github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
+github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
+github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU=
+go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
+golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114 h1:DnSr2mCsxyCE6ZgIkmcWUQY2R5cH/6wL7eIxEmQOMSE=
+golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A=
+gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
diff --git a/vendor/github.com/jackc/pgx/v4/go_stdlib.go b/vendor/github.com/jackc/pgx/v4/go_stdlib.go
new file mode 100644
index 000000000..9372f9efa
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/go_stdlib.go
@@ -0,0 +1,61 @@
+package pgx
+
+import (
+ "database/sql/driver"
+ "reflect"
+)
+
+// This file contains code copied from the Go standard library due to the
+// required function not being public.
+
+// Copyright (c) 2009 The Go Authors. All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// From database/sql/convert.go
+
+var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
+
+// callValuerValue returns vr.Value(), with one exception:
+// If vr.Value is an auto-generated method on a pointer type and the
+// pointer is nil, it would panic at runtime in the panicwrap
+// method. Treat it like nil instead.
+// Issue 8415.
+//
+// This is so people can implement driver.Value on value types and
+// still use nil pointers to those types to mean nil/NULL, just like
+// string/*string.
+//
+// This function is mirrored in the database/sql/driver package.
+func callValuerValue(vr driver.Valuer) (v driver.Value, err error) {
+ if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr &&
+ rv.IsNil() &&
+ rv.Type().Elem().Implements(valuerReflectType) {
+ return nil, nil
+ }
+ return vr.Value()
+}
diff --git a/vendor/github.com/jackc/pgx/v4/internal/sanitize/sanitize.go b/vendor/github.com/jackc/pgx/v4/internal/sanitize/sanitize.go
new file mode 100644
index 000000000..2dba3b810
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/internal/sanitize/sanitize.go
@@ -0,0 +1,304 @@
+package sanitize
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+// Part is either a string or an int. A string is raw SQL. An int is a
+// argument placeholder.
+type Part interface{}
+
+type Query struct {
+ Parts []Part
+}
+
+func (q *Query) Sanitize(args ...interface{}) (string, error) {
+ argUse := make([]bool, len(args))
+ buf := &bytes.Buffer{}
+
+ for _, part := range q.Parts {
+ var str string
+ switch part := part.(type) {
+ case string:
+ str = part
+ case int:
+ argIdx := part - 1
+ if argIdx >= len(args) {
+ return "", fmt.Errorf("insufficient arguments")
+ }
+ arg := args[argIdx]
+ switch arg := arg.(type) {
+ case nil:
+ str = "null"
+ case int64:
+ str = strconv.FormatInt(arg, 10)
+ case float64:
+ str = strconv.FormatFloat(arg, 'f', -1, 64)
+ case bool:
+ str = strconv.FormatBool(arg)
+ case []byte:
+ str = QuoteBytes(arg)
+ case string:
+ str = QuoteString(arg)
+ case time.Time:
+ str = arg.Truncate(time.Microsecond).Format("'2006-01-02 15:04:05.999999999Z07:00:00'")
+ default:
+ return "", fmt.Errorf("invalid arg type: %T", arg)
+ }
+ argUse[argIdx] = true
+ default:
+ return "", fmt.Errorf("invalid Part type: %T", part)
+ }
+ buf.WriteString(str)
+ }
+
+ for i, used := range argUse {
+ if !used {
+ return "", fmt.Errorf("unused argument: %d", i)
+ }
+ }
+ return buf.String(), nil
+}
+
+func NewQuery(sql string) (*Query, error) {
+ l := &sqlLexer{
+ src: sql,
+ stateFn: rawState,
+ }
+
+ for l.stateFn != nil {
+ l.stateFn = l.stateFn(l)
+ }
+
+ query := &Query{Parts: l.parts}
+
+ return query, nil
+}
+
+func QuoteString(str string) string {
+ return "'" + strings.ReplaceAll(str, "'", "''") + "'"
+}
+
+func QuoteBytes(buf []byte) string {
+ return `'\x` + hex.EncodeToString(buf) + "'"
+}
+
+type sqlLexer struct {
+ src string
+ start int
+ pos int
+ nested int // multiline comment nesting level.
+ stateFn stateFn
+ parts []Part
+}
+
+type stateFn func(*sqlLexer) stateFn
+
+func rawState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case 'e', 'E':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune == '\'' {
+ l.pos += width
+ return escapeStringState
+ }
+ case '\'':
+ return singleQuoteState
+ case '"':
+ return doubleQuoteState
+ case '$':
+ nextRune, _ := utf8.DecodeRuneInString(l.src[l.pos:])
+ if '0' <= nextRune && nextRune <= '9' {
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos-width])
+ }
+ l.start = l.pos
+ return placeholderState
+ }
+ case '-':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune == '-' {
+ l.pos += width
+ return oneLineCommentState
+ }
+ case '/':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune == '*' {
+ l.pos += width
+ return multilineCommentState
+ }
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+func singleQuoteState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case '\'':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune != '\'' {
+ return rawState
+ }
+ l.pos += width
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+func doubleQuoteState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case '"':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune != '"' {
+ return rawState
+ }
+ l.pos += width
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+// placeholderState consumes a placeholder value. The $ must have already has
+// already been consumed. The first rune must be a digit.
+func placeholderState(l *sqlLexer) stateFn {
+ num := 0
+
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ if '0' <= r && r <= '9' {
+ num *= 10
+ num += int(r - '0')
+ } else {
+ l.parts = append(l.parts, num)
+ l.pos -= width
+ l.start = l.pos
+ return rawState
+ }
+ }
+}
+
+func escapeStringState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case '\\':
+ _, width = utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+ case '\'':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune != '\'' {
+ return rawState
+ }
+ l.pos += width
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+func oneLineCommentState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case '\\':
+ _, width = utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+ case '\n':
+ return rawState
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+func multilineCommentState(l *sqlLexer) stateFn {
+ for {
+ r, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ l.pos += width
+
+ switch r {
+ case '/':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune == '*' {
+ l.pos += width
+ l.nested++
+ }
+ case '*':
+ nextRune, width := utf8.DecodeRuneInString(l.src[l.pos:])
+ if nextRune != '/' {
+ continue
+ }
+
+ l.pos += width
+ if l.nested == 0 {
+ return rawState
+ }
+ l.nested--
+
+ case utf8.RuneError:
+ if l.pos-l.start > 0 {
+ l.parts = append(l.parts, l.src[l.start:l.pos])
+ l.start = l.pos
+ }
+ return nil
+ }
+ }
+}
+
+// SanitizeSQL replaces placeholder values with args. It quotes and escapes args
+// as necessary. This function is only safe when standard_conforming_strings is
+// on.
+func SanitizeSQL(sql string, args ...interface{}) (string, error) {
+ query, err := NewQuery(sql)
+ if err != nil {
+ return "", err
+ }
+ return query.Sanitize(args...)
+}
diff --git a/vendor/github.com/jackc/pgx/v4/large_objects.go b/vendor/github.com/jackc/pgx/v4/large_objects.go
new file mode 100644
index 000000000..5255a3b48
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/large_objects.go
@@ -0,0 +1,121 @@
+package pgx
+
+import (
+ "context"
+ "errors"
+ "io"
+)
+
+// LargeObjects is a structure used to access the large objects API. It is only valid within the transaction where it
+// was created.
+//
+// For more details see: http://www.postgresql.org/docs/current/static/largeobjects.html
+type LargeObjects struct {
+ tx Tx
+}
+
+type LargeObjectMode int32
+
+const (
+ LargeObjectModeWrite LargeObjectMode = 0x20000
+ LargeObjectModeRead LargeObjectMode = 0x40000
+)
+
+// Create creates a new large object. If oid is zero, the server assigns an unused OID.
+func (o *LargeObjects) Create(ctx context.Context, oid uint32) (uint32, error) {
+ err := o.tx.QueryRow(ctx, "select lo_create($1)", oid).Scan(&oid)
+ return oid, err
+}
+
+// Open opens an existing large object with the given mode. ctx will also be used for all operations on the opened large
+// object.
+func (o *LargeObjects) Open(ctx context.Context, oid uint32, mode LargeObjectMode) (*LargeObject, error) {
+ var fd int32
+ err := o.tx.QueryRow(ctx, "select lo_open($1, $2)", oid, mode).Scan(&fd)
+ if err != nil {
+ return nil, err
+ }
+ return &LargeObject{fd: fd, tx: o.tx, ctx: ctx}, nil
+}
+
+// Unlink removes a large object from the database.
+func (o *LargeObjects) Unlink(ctx context.Context, oid uint32) error {
+ var result int32
+ err := o.tx.QueryRow(ctx, "select lo_unlink($1)", oid).Scan(&result)
+ if err != nil {
+ return err
+ }
+
+ if result != 1 {
+ return errors.New("failed to remove large object")
+ }
+
+ return nil
+}
+
+// A LargeObject is a large object stored on the server. It is only valid within the transaction that it was initialized
+// in. It uses the context it was initialized with for all operations. It implements these interfaces:
+//
+// io.Writer
+// io.Reader
+// io.Seeker
+// io.Closer
+type LargeObject struct {
+ ctx context.Context
+ tx Tx
+ fd int32
+}
+
+// Write writes p to the large object and returns the number of bytes written and an error if not all of p was written.
+func (o *LargeObject) Write(p []byte) (int, error) {
+ var n int
+ err := o.tx.QueryRow(o.ctx, "select lowrite($1, $2)", o.fd, p).Scan(&n)
+ if err != nil {
+ return n, err
+ }
+
+ if n < 0 {
+ return 0, errors.New("failed to write to large object")
+ }
+
+ return n, nil
+}
+
+// Read reads up to len(p) bytes into p returning the number of bytes read.
+func (o *LargeObject) Read(p []byte) (int, error) {
+ var res []byte
+ err := o.tx.QueryRow(o.ctx, "select loread($1, $2)", o.fd, len(p)).Scan(&res)
+ copy(p, res)
+ if err != nil {
+ return len(res), err
+ }
+
+ if len(res) < len(p) {
+ err = io.EOF
+ }
+ return len(res), err
+}
+
+// Seek moves the current location pointer to the new location specified by offset.
+func (o *LargeObject) Seek(offset int64, whence int) (n int64, err error) {
+ err = o.tx.QueryRow(o.ctx, "select lo_lseek64($1, $2, $3)", o.fd, offset, whence).Scan(&n)
+ return n, err
+}
+
+// Tell returns the current read or write location of the large object descriptor.
+func (o *LargeObject) Tell() (n int64, err error) {
+ err = o.tx.QueryRow(o.ctx, "select lo_tell64($1)", o.fd).Scan(&n)
+ return n, err
+}
+
+// Trunctes the large object to size.
+func (o *LargeObject) Truncate(size int64) (err error) {
+ _, err = o.tx.Exec(o.ctx, "select lo_truncate64($1, $2)", o.fd, size)
+ return err
+}
+
+// Close closees the large object descriptor.
+func (o *LargeObject) Close() error {
+ _, err := o.tx.Exec(o.ctx, "select lo_close($1)", o.fd)
+ return err
+}
diff --git a/vendor/github.com/jackc/pgx/v4/logger.go b/vendor/github.com/jackc/pgx/v4/logger.go
new file mode 100644
index 000000000..89fd5af51
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/logger.go
@@ -0,0 +1,98 @@
+package pgx
+
+import (
+ "context"
+ "encoding/hex"
+ "errors"
+ "fmt"
+)
+
+// The values for log levels are chosen such that the zero value means that no
+// log level was specified.
+const (
+ LogLevelTrace = 6
+ LogLevelDebug = 5
+ LogLevelInfo = 4
+ LogLevelWarn = 3
+ LogLevelError = 2
+ LogLevelNone = 1
+)
+
+// LogLevel represents the pgx logging level. See LogLevel* constants for
+// possible values.
+type LogLevel int
+
+func (ll LogLevel) String() string {
+ switch ll {
+ case LogLevelTrace:
+ return "trace"
+ case LogLevelDebug:
+ return "debug"
+ case LogLevelInfo:
+ return "info"
+ case LogLevelWarn:
+ return "warn"
+ case LogLevelError:
+ return "error"
+ case LogLevelNone:
+ return "none"
+ default:
+ return fmt.Sprintf("invalid level %d", ll)
+ }
+}
+
+// Logger is the interface used to get logging from pgx internals.
+type Logger interface {
+ // Log a message at the given level with data key/value pairs. data may be nil.
+ Log(ctx context.Context, level LogLevel, msg string, data map[string]interface{})
+}
+
+// LogLevelFromString converts log level string to constant
+//
+// Valid levels:
+// trace
+// debug
+// info
+// warn
+// error
+// none
+func LogLevelFromString(s string) (LogLevel, error) {
+ switch s {
+ case "trace":
+ return LogLevelTrace, nil
+ case "debug":
+ return LogLevelDebug, nil
+ case "info":
+ return LogLevelInfo, nil
+ case "warn":
+ return LogLevelWarn, nil
+ case "error":
+ return LogLevelError, nil
+ case "none":
+ return LogLevelNone, nil
+ default:
+ return 0, errors.New("invalid log level")
+ }
+}
+
+func logQueryArgs(args []interface{}) []interface{} {
+ logArgs := make([]interface{}, 0, len(args))
+
+ for _, a := range args {
+ switch v := a.(type) {
+ case []byte:
+ if len(v) < 64 {
+ a = hex.EncodeToString(v)
+ } else {
+ a = fmt.Sprintf("%x (truncated %d bytes)", v[:64], len(v)-64)
+ }
+ case string:
+ if len(v) > 64 {
+ a = fmt.Sprintf("%s (truncated %d bytes)", v[:64], len(v)-64)
+ }
+ }
+ logArgs = append(logArgs, a)
+ }
+
+ return logArgs
+}
diff --git a/vendor/github.com/jackc/pgx/v4/messages.go b/vendor/github.com/jackc/pgx/v4/messages.go
new file mode 100644
index 000000000..5324cbb5c
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/messages.go
@@ -0,0 +1,23 @@
+package pgx
+
+import (
+ "database/sql/driver"
+
+ "github.com/jackc/pgtype"
+)
+
+func convertDriverValuers(args []interface{}) ([]interface{}, error) {
+ for i, arg := range args {
+ switch arg := arg.(type) {
+ case pgtype.BinaryEncoder:
+ case pgtype.TextEncoder:
+ case driver.Valuer:
+ v, err := callValuerValue(arg)
+ if err != nil {
+ return nil, err
+ }
+ args[i] = v
+ }
+ }
+ return args, nil
+}
diff --git a/vendor/github.com/jackc/pgx/v4/rows.go b/vendor/github.com/jackc/pgx/v4/rows.go
new file mode 100644
index 000000000..d57d5cbf6
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/rows.go
@@ -0,0 +1,347 @@
+package pgx
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "time"
+
+ "github.com/jackc/pgconn"
+ "github.com/jackc/pgproto3/v2"
+ "github.com/jackc/pgtype"
+)
+
+// Rows is the result set returned from *Conn.Query. Rows must be closed before
+// the *Conn can be used again. Rows are closed by explicitly calling Close(),
+// calling Next() until it returns false, or when a fatal error occurs.
+//
+// Once a Rows is closed the only methods that may be called are Close(), Err(), and CommandTag().
+//
+// Rows is an interface instead of a struct to allow tests to mock Query. However,
+// adding a method to an interface is technically a breaking change. Because of this
+// the Rows interface is partially excluded from semantic version requirements.
+// Methods will not be removed or changed, but new methods may be added.
+type Rows interface {
+ // Close closes the rows, making the connection ready for use again. It is safe
+ // to call Close after rows is already closed.
+ Close()
+
+ // Err returns any error that occurred while reading.
+ Err() error
+
+ // CommandTag returns the command tag from this query. It is only available after Rows is closed.
+ CommandTag() pgconn.CommandTag
+
+ FieldDescriptions() []pgproto3.FieldDescription
+
+ // Next prepares the next row for reading. It returns true if there is another
+ // row and false if no more rows are available. It automatically closes rows
+ // when all rows are read.
+ Next() bool
+
+ // Scan reads the values from the current row into dest values positionally.
+ // dest can include pointers to core types, values implementing the Scanner
+ // interface, and nil. nil will skip the value entirely.
+ Scan(dest ...interface{}) error
+
+ // Values returns the decoded row values.
+ Values() ([]interface{}, error)
+
+ // RawValues returns the unparsed bytes of the row values. The returned [][]byte is only valid until the next Next
+ // call or the Rows is closed. However, the underlying byte data is safe to retain a reference to and mutate.
+ RawValues() [][]byte
+}
+
+// Row is a convenience wrapper over Rows that is returned by QueryRow.
+//
+// Row is an interface instead of a struct to allow tests to mock QueryRow. However,
+// adding a method to an interface is technically a breaking change. Because of this
+// the Row interface is partially excluded from semantic version requirements.
+// Methods will not be removed or changed, but new methods may be added.
+type Row interface {
+ // Scan works the same as Rows. with the following exceptions. If no
+ // rows were found it returns ErrNoRows. If multiple rows are returned it
+ // ignores all but the first.
+ Scan(dest ...interface{}) error
+}
+
+// connRow implements the Row interface for Conn.QueryRow.
+type connRow connRows
+
+func (r *connRow) Scan(dest ...interface{}) (err error) {
+ rows := (*connRows)(r)
+
+ if rows.Err() != nil {
+ return rows.Err()
+ }
+
+ if !rows.Next() {
+ if rows.Err() == nil {
+ return ErrNoRows
+ }
+ return rows.Err()
+ }
+
+ rows.Scan(dest...)
+ rows.Close()
+ return rows.Err()
+}
+
+type rowLog interface {
+ shouldLog(lvl LogLevel) bool
+ log(ctx context.Context, lvl LogLevel, msg string, data map[string]interface{})
+}
+
+// connRows implements the Rows interface for Conn.Query.
+type connRows struct {
+ ctx context.Context
+ logger rowLog
+ connInfo *pgtype.ConnInfo
+ values [][]byte
+ rowCount int
+ err error
+ commandTag pgconn.CommandTag
+ startTime time.Time
+ sql string
+ args []interface{}
+ closed bool
+ conn *Conn
+
+ resultReader *pgconn.ResultReader
+ multiResultReader *pgconn.MultiResultReader
+
+ scanPlans []pgtype.ScanPlan
+}
+
+func (rows *connRows) FieldDescriptions() []pgproto3.FieldDescription {
+ return rows.resultReader.FieldDescriptions()
+}
+
+func (rows *connRows) Close() {
+ if rows.closed {
+ return
+ }
+
+ rows.closed = true
+
+ if rows.resultReader != nil {
+ var closeErr error
+ rows.commandTag, closeErr = rows.resultReader.Close()
+ if rows.err == nil {
+ rows.err = closeErr
+ }
+ }
+
+ if rows.multiResultReader != nil {
+ closeErr := rows.multiResultReader.Close()
+ if rows.err == nil {
+ rows.err = closeErr
+ }
+ }
+
+ if rows.logger != nil {
+ if rows.err == nil {
+ if rows.logger.shouldLog(LogLevelInfo) {
+ endTime := time.Now()
+ rows.logger.log(rows.ctx, LogLevelInfo, "Query", map[string]interface{}{"sql": rows.sql, "args": logQueryArgs(rows.args), "time": endTime.Sub(rows.startTime), "rowCount": rows.rowCount})
+ }
+ } else {
+ if rows.logger.shouldLog(LogLevelError) {
+ rows.logger.log(rows.ctx, LogLevelError, "Query", map[string]interface{}{"err": rows.err, "sql": rows.sql, "args": logQueryArgs(rows.args)})
+ }
+ if rows.err != nil && rows.conn.stmtcache != nil {
+ rows.conn.stmtcache.StatementErrored(rows.sql, rows.err)
+ }
+ }
+ }
+}
+
+func (rows *connRows) CommandTag() pgconn.CommandTag {
+ return rows.commandTag
+}
+
+func (rows *connRows) Err() error {
+ return rows.err
+}
+
+// fatal signals an error occurred after the query was sent to the server. It
+// closes the rows automatically.
+func (rows *connRows) fatal(err error) {
+ if rows.err != nil {
+ return
+ }
+
+ rows.err = err
+ rows.Close()
+}
+
+func (rows *connRows) Next() bool {
+ if rows.closed {
+ return false
+ }
+
+ if rows.resultReader.NextRow() {
+ rows.rowCount++
+ rows.values = rows.resultReader.Values()
+ return true
+ } else {
+ rows.Close()
+ return false
+ }
+}
+
+func (rows *connRows) Scan(dest ...interface{}) error {
+ ci := rows.connInfo
+ fieldDescriptions := rows.FieldDescriptions()
+ values := rows.values
+
+ if len(fieldDescriptions) != len(values) {
+ err := fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
+ rows.fatal(err)
+ return err
+ }
+ if len(fieldDescriptions) != len(dest) {
+ err := fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
+ rows.fatal(err)
+ return err
+ }
+
+ if rows.scanPlans == nil {
+ rows.scanPlans = make([]pgtype.ScanPlan, len(values))
+ for i := range dest {
+ rows.scanPlans[i] = ci.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, dest[i])
+ }
+ }
+
+ for i, dst := range dest {
+ if dst == nil {
+ continue
+ }
+
+ err := rows.scanPlans[i].Scan(ci, fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], dst)
+ if err != nil {
+ err = ScanArgError{ColumnIndex: i, Err: err}
+ rows.fatal(err)
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (rows *connRows) Values() ([]interface{}, error) {
+ if rows.closed {
+ return nil, errors.New("rows is closed")
+ }
+
+ values := make([]interface{}, 0, len(rows.FieldDescriptions()))
+
+ for i := range rows.FieldDescriptions() {
+ buf := rows.values[i]
+ fd := &rows.FieldDescriptions()[i]
+
+ if buf == nil {
+ values = append(values, nil)
+ continue
+ }
+
+ if dt, ok := rows.connInfo.DataTypeForOID(fd.DataTypeOID); ok {
+ value := dt.Value
+
+ switch fd.Format {
+ case TextFormatCode:
+ decoder, ok := value.(pgtype.TextDecoder)
+ if !ok {
+ decoder = &pgtype.GenericText{}
+ }
+ err := decoder.DecodeText(rows.connInfo, buf)
+ if err != nil {
+ rows.fatal(err)
+ }
+ values = append(values, decoder.(pgtype.Value).Get())
+ case BinaryFormatCode:
+ decoder, ok := value.(pgtype.BinaryDecoder)
+ if !ok {
+ decoder = &pgtype.GenericBinary{}
+ }
+ err := decoder.DecodeBinary(rows.connInfo, buf)
+ if err != nil {
+ rows.fatal(err)
+ }
+ values = append(values, value.Get())
+ default:
+ rows.fatal(errors.New("Unknown format code"))
+ }
+ } else {
+ switch fd.Format {
+ case TextFormatCode:
+ decoder := &pgtype.GenericText{}
+ err := decoder.DecodeText(rows.connInfo, buf)
+ if err != nil {
+ rows.fatal(err)
+ }
+ values = append(values, decoder.Get())
+ case BinaryFormatCode:
+ decoder := &pgtype.GenericBinary{}
+ err := decoder.DecodeBinary(rows.connInfo, buf)
+ if err != nil {
+ rows.fatal(err)
+ }
+ values = append(values, decoder.Get())
+ default:
+ rows.fatal(errors.New("Unknown format code"))
+ }
+ }
+
+ if rows.Err() != nil {
+ return nil, rows.Err()
+ }
+ }
+
+ return values, rows.Err()
+}
+
+func (rows *connRows) RawValues() [][]byte {
+ return rows.values
+}
+
+type ScanArgError struct {
+ ColumnIndex int
+ Err error
+}
+
+func (e ScanArgError) Error() string {
+ return fmt.Sprintf("can't scan into dest[%d]: %v", e.ColumnIndex, e.Err)
+}
+
+func (e ScanArgError) Unwrap() error {
+ return e.Err
+}
+
+// ScanRow decodes raw row data into dest. It can be used to scan rows read from the lower level pgconn interface.
+//
+// connInfo - OID to Go type mapping.
+// fieldDescriptions - OID and format of values
+// values - the raw data as returned from the PostgreSQL server
+// dest - the destination that values will be decoded into
+func ScanRow(connInfo *pgtype.ConnInfo, fieldDescriptions []pgproto3.FieldDescription, values [][]byte, dest ...interface{}) error {
+ if len(fieldDescriptions) != len(values) {
+ return fmt.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values))
+ }
+ if len(fieldDescriptions) != len(dest) {
+ return fmt.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest))
+ }
+
+ for i, d := range dest {
+ if d == nil {
+ continue
+ }
+
+ err := connInfo.Scan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], d)
+ if err != nil {
+ return ScanArgError{ColumnIndex: i, Err: err}
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/jackc/pgx/v4/stdlib/sql.go b/vendor/github.com/jackc/pgx/v4/stdlib/sql.go
new file mode 100644
index 000000000..fa81e73d5
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/stdlib/sql.go
@@ -0,0 +1,858 @@
+// Package stdlib is the compatibility layer from pgx to database/sql.
+//
+// A database/sql connection can be established through sql.Open.
+//
+// db, err := sql.Open("pgx", "postgres://pgx_md5:secret@localhost:5432/pgx_test?sslmode=disable")
+// if err != nil {
+// return err
+// }
+//
+// Or from a DSN string.
+//
+// db, err := sql.Open("pgx", "user=postgres password=secret host=localhost port=5432 database=pgx_test sslmode=disable")
+// if err != nil {
+// return err
+// }
+//
+// Or a pgx.ConnConfig can be used to set configuration not accessible via connection string. In this case the
+// pgx.ConnConfig must first be registered with the driver. This registration returns a connection string which is used
+// with sql.Open.
+//
+// connConfig, _ := pgx.ParseConfig(os.Getenv("DATABASE_URL"))
+// connConfig.Logger = myLogger
+// connStr := stdlib.RegisterConnConfig(connConfig)
+// db, _ := sql.Open("pgx", connStr)
+//
+// pgx uses standard PostgreSQL positional parameters in queries. e.g. $1, $2.
+// It does not support named parameters.
+//
+// db.QueryRow("select * from users where id=$1", userID)
+//
+// In Go 1.13 and above (*sql.Conn) Raw() can be used to get a *pgx.Conn from the standard
+// database/sql.DB connection pool. This allows operations that use pgx specific functionality.
+//
+// // Given db is a *sql.DB
+// conn, err := db.Conn(context.Background())
+// if err != nil {
+// // handle error from acquiring connection from DB pool
+// }
+//
+// err = conn.Raw(func(driverConn interface{}) error {
+// conn := driverConn.(*stdlib.Conn).Conn() // conn is a *pgx.Conn
+// // Do pgx specific stuff with conn
+// conn.CopyFrom(...)
+// return nil
+// })
+// if err != nil {
+// // handle error that occurred while using *pgx.Conn
+// }
+package stdlib
+
+import (
+ "context"
+ "database/sql"
+ "database/sql/driver"
+ "errors"
+ "fmt"
+ "io"
+ "math"
+ "math/rand"
+ "reflect"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/jackc/pgconn"
+ "github.com/jackc/pgtype"
+ "github.com/jackc/pgx/v4"
+)
+
+// Only intrinsic types should be binary format with database/sql.
+var databaseSQLResultFormats pgx.QueryResultFormatsByOID
+
+var pgxDriver *Driver
+
+type ctxKey int
+
+var ctxKeyFakeTx ctxKey = 0
+
+var ErrNotPgx = errors.New("not pgx *sql.DB")
+
+func init() {
+ pgxDriver = &Driver{
+ configs: make(map[string]*pgx.ConnConfig),
+ }
+ fakeTxConns = make(map[*pgx.Conn]*sql.Tx)
+ sql.Register("pgx", pgxDriver)
+
+ databaseSQLResultFormats = pgx.QueryResultFormatsByOID{
+ pgtype.BoolOID: 1,
+ pgtype.ByteaOID: 1,
+ pgtype.CIDOID: 1,
+ pgtype.DateOID: 1,
+ pgtype.Float4OID: 1,
+ pgtype.Float8OID: 1,
+ pgtype.Int2OID: 1,
+ pgtype.Int4OID: 1,
+ pgtype.Int8OID: 1,
+ pgtype.OIDOID: 1,
+ pgtype.TimestampOID: 1,
+ pgtype.TimestamptzOID: 1,
+ pgtype.XIDOID: 1,
+ }
+}
+
+var (
+ fakeTxMutex sync.Mutex
+ fakeTxConns map[*pgx.Conn]*sql.Tx
+)
+
+// OptionOpenDB options for configuring the driver when opening a new db pool.
+type OptionOpenDB func(*connector)
+
+// OptionBeforeConnect provides a callback for before connect. It is passed a shallow copy of the ConnConfig that will
+// be used to connect, so only its immediate members should be modified.
+func OptionBeforeConnect(bc func(context.Context, *pgx.ConnConfig) error) OptionOpenDB {
+ return func(dc *connector) {
+ dc.BeforeConnect = bc
+ }
+}
+
+// OptionAfterConnect provides a callback for after connect.
+func OptionAfterConnect(ac func(context.Context, *pgx.Conn) error) OptionOpenDB {
+ return func(dc *connector) {
+ dc.AfterConnect = ac
+ }
+}
+
+// OptionResetSession provides a callback that can be used to add custom logic prior to executing a query on the
+// connection if the connection has been used before.
+// If ResetSessionFunc returns ErrBadConn error the connection will be discarded.
+func OptionResetSession(rs func(context.Context, *pgx.Conn) error) OptionOpenDB {
+ return func(dc *connector) {
+ dc.ResetSession = rs
+ }
+}
+
+// RandomizeHostOrderFunc is a BeforeConnect hook that randomizes the host order in the provided connConfig, so that a
+// new host becomes primary each time. This is useful to distribute connections for multi-master databases like
+// CockroachDB. If you use this you likely should set https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime as well
+// to ensure that connections are periodically rebalanced across your nodes.
+func RandomizeHostOrderFunc(ctx context.Context, connConfig *pgx.ConnConfig) error {
+ if len(connConfig.Fallbacks) == 0 {
+ return nil
+ }
+
+ newFallbacks := append([]*pgconn.FallbackConfig{&pgconn.FallbackConfig{
+ Host: connConfig.Host,
+ Port: connConfig.Port,
+ TLSConfig: connConfig.TLSConfig,
+ }}, connConfig.Fallbacks...)
+
+ rand.Shuffle(len(newFallbacks), func(i, j int) {
+ newFallbacks[i], newFallbacks[j] = newFallbacks[j], newFallbacks[i]
+ })
+
+ // Use the one that sorted last as the primary and keep the rest as the fallbacks
+ newPrimary := newFallbacks[len(newFallbacks)-1]
+ connConfig.Host = newPrimary.Host
+ connConfig.Port = newPrimary.Port
+ connConfig.TLSConfig = newPrimary.TLSConfig
+ connConfig.Fallbacks = newFallbacks[:len(newFallbacks)-1]
+ return nil
+}
+
+func OpenDB(config pgx.ConnConfig, opts ...OptionOpenDB) *sql.DB {
+ c := connector{
+ ConnConfig: config,
+ BeforeConnect: func(context.Context, *pgx.ConnConfig) error { return nil }, // noop before connect by default
+ AfterConnect: func(context.Context, *pgx.Conn) error { return nil }, // noop after connect by default
+ ResetSession: func(context.Context, *pgx.Conn) error { return nil }, // noop reset session by default
+ driver: pgxDriver,
+ }
+
+ for _, opt := range opts {
+ opt(&c)
+ }
+
+ return sql.OpenDB(c)
+}
+
+type connector struct {
+ pgx.ConnConfig
+ BeforeConnect func(context.Context, *pgx.ConnConfig) error // function to call before creation of every new connection
+ AfterConnect func(context.Context, *pgx.Conn) error // function to call after creation of every new connection
+ ResetSession func(context.Context, *pgx.Conn) error // function is called before a connection is reused
+ driver *Driver
+}
+
+// Connect implement driver.Connector interface
+func (c connector) Connect(ctx context.Context) (driver.Conn, error) {
+ var (
+ err error
+ conn *pgx.Conn
+ )
+
+ // Create a shallow copy of the config, so that BeforeConnect can safely modify it
+ connConfig := c.ConnConfig
+ if err = c.BeforeConnect(ctx, &connConfig); err != nil {
+ return nil, err
+ }
+
+ if conn, err = pgx.ConnectConfig(ctx, &connConfig); err != nil {
+ return nil, err
+ }
+
+ if err = c.AfterConnect(ctx, conn); err != nil {
+ return nil, err
+ }
+
+ return &Conn{conn: conn, driver: c.driver, connConfig: connConfig, resetSessionFunc: c.ResetSession}, nil
+}
+
+// Driver implement driver.Connector interface
+func (c connector) Driver() driver.Driver {
+ return c.driver
+}
+
+// GetDefaultDriver returns the driver initialized in the init function
+// and used when the pgx driver is registered.
+func GetDefaultDriver() driver.Driver {
+ return pgxDriver
+}
+
+type Driver struct {
+ configMutex sync.Mutex
+ configs map[string]*pgx.ConnConfig
+ sequence int
+}
+
+func (d *Driver) Open(name string) (driver.Conn, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) // Ensure eventual timeout
+ defer cancel()
+
+ connector, err := d.OpenConnector(name)
+ if err != nil {
+ return nil, err
+ }
+ return connector.Connect(ctx)
+}
+
+func (d *Driver) OpenConnector(name string) (driver.Connector, error) {
+ return &driverConnector{driver: d, name: name}, nil
+}
+
+func (d *Driver) registerConnConfig(c *pgx.ConnConfig) string {
+ d.configMutex.Lock()
+ connStr := fmt.Sprintf("registeredConnConfig%d", d.sequence)
+ d.sequence++
+ d.configs[connStr] = c
+ d.configMutex.Unlock()
+ return connStr
+}
+
+func (d *Driver) unregisterConnConfig(connStr string) {
+ d.configMutex.Lock()
+ delete(d.configs, connStr)
+ d.configMutex.Unlock()
+}
+
+type driverConnector struct {
+ driver *Driver
+ name string
+}
+
+func (dc *driverConnector) Connect(ctx context.Context) (driver.Conn, error) {
+ var connConfig *pgx.ConnConfig
+
+ dc.driver.configMutex.Lock()
+ connConfig = dc.driver.configs[dc.name]
+ dc.driver.configMutex.Unlock()
+
+ if connConfig == nil {
+ var err error
+ connConfig, err = pgx.ParseConfig(dc.name)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ conn, err := pgx.ConnectConfig(ctx, connConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ c := &Conn{
+ conn: conn,
+ driver: dc.driver,
+ connConfig: *connConfig,
+ resetSessionFunc: func(context.Context, *pgx.Conn) error { return nil },
+ }
+
+ return c, nil
+}
+
+func (dc *driverConnector) Driver() driver.Driver {
+ return dc.driver
+}
+
+// RegisterConnConfig registers a ConnConfig and returns the connection string to use with Open.
+func RegisterConnConfig(c *pgx.ConnConfig) string {
+ return pgxDriver.registerConnConfig(c)
+}
+
+// UnregisterConnConfig removes the ConnConfig registration for connStr.
+func UnregisterConnConfig(connStr string) {
+ pgxDriver.unregisterConnConfig(connStr)
+}
+
+type Conn struct {
+ conn *pgx.Conn
+ psCount int64 // Counter used for creating unique prepared statement names
+ driver *Driver
+ connConfig pgx.ConnConfig
+ resetSessionFunc func(context.Context, *pgx.Conn) error // Function is called before a connection is reused
+}
+
+// Conn returns the underlying *pgx.Conn
+func (c *Conn) Conn() *pgx.Conn {
+ return c.conn
+}
+
+func (c *Conn) Prepare(query string) (driver.Stmt, error) {
+ return c.PrepareContext(context.Background(), query)
+}
+
+func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
+ if c.conn.IsClosed() {
+ return nil, driver.ErrBadConn
+ }
+
+ name := fmt.Sprintf("pgx_%d", c.psCount)
+ c.psCount++
+
+ sd, err := c.conn.Prepare(ctx, name, query)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Stmt{sd: sd, conn: c}, nil
+}
+
+func (c *Conn) Close() error {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancel()
+ return c.conn.Close(ctx)
+}
+
+func (c *Conn) Begin() (driver.Tx, error) {
+ return c.BeginTx(context.Background(), driver.TxOptions{})
+}
+
+func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+ if c.conn.IsClosed() {
+ return nil, driver.ErrBadConn
+ }
+
+ if pconn, ok := ctx.Value(ctxKeyFakeTx).(**pgx.Conn); ok {
+ *pconn = c.conn
+ return fakeTx{}, nil
+ }
+
+ var pgxOpts pgx.TxOptions
+ switch sql.IsolationLevel(opts.Isolation) {
+ case sql.LevelDefault:
+ case sql.LevelReadUncommitted:
+ pgxOpts.IsoLevel = pgx.ReadUncommitted
+ case sql.LevelReadCommitted:
+ pgxOpts.IsoLevel = pgx.ReadCommitted
+ case sql.LevelRepeatableRead, sql.LevelSnapshot:
+ pgxOpts.IsoLevel = pgx.RepeatableRead
+ case sql.LevelSerializable:
+ pgxOpts.IsoLevel = pgx.Serializable
+ default:
+ return nil, fmt.Errorf("unsupported isolation: %v", opts.Isolation)
+ }
+
+ if opts.ReadOnly {
+ pgxOpts.AccessMode = pgx.ReadOnly
+ }
+
+ tx, err := c.conn.BeginTx(ctx, pgxOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ return wrapTx{ctx: ctx, tx: tx}, nil
+}
+
+func (c *Conn) ExecContext(ctx context.Context, query string, argsV []driver.NamedValue) (driver.Result, error) {
+ if c.conn.IsClosed() {
+ return nil, driver.ErrBadConn
+ }
+
+ args := namedValueToInterface(argsV)
+
+ commandTag, err := c.conn.Exec(ctx, query, args...)
+ // if we got a network error before we had a chance to send the query, retry
+ if err != nil {
+ if pgconn.SafeToRetry(err) {
+ return nil, driver.ErrBadConn
+ }
+ }
+ return driver.RowsAffected(commandTag.RowsAffected()), err
+}
+
+func (c *Conn) QueryContext(ctx context.Context, query string, argsV []driver.NamedValue) (driver.Rows, error) {
+ if c.conn.IsClosed() {
+ return nil, driver.ErrBadConn
+ }
+
+ args := []interface{}{databaseSQLResultFormats}
+ args = append(args, namedValueToInterface(argsV)...)
+
+ rows, err := c.conn.Query(ctx, query, args...)
+ if err != nil {
+ if pgconn.SafeToRetry(err) {
+ return nil, driver.ErrBadConn
+ }
+ return nil, err
+ }
+
+ // Preload first row because otherwise we won't know what columns are available when database/sql asks.
+ more := rows.Next()
+ if err = rows.Err(); err != nil {
+ rows.Close()
+ return nil, err
+ }
+ return &Rows{conn: c, rows: rows, skipNext: true, skipNextMore: more}, nil
+}
+
+func (c *Conn) Ping(ctx context.Context) error {
+ if c.conn.IsClosed() {
+ return driver.ErrBadConn
+ }
+
+ err := c.conn.Ping(ctx)
+ if err != nil {
+ // A Ping failure implies some sort of fatal state. The connection is almost certainly already closed by the
+ // failure, but manually close it just to be sure.
+ c.Close()
+ return driver.ErrBadConn
+ }
+
+ return nil
+}
+
+func (c *Conn) CheckNamedValue(*driver.NamedValue) error {
+ // Underlying pgx supports sql.Scanner and driver.Valuer interfaces natively. So everything can be passed through directly.
+ return nil
+}
+
+func (c *Conn) ResetSession(ctx context.Context) error {
+ if c.conn.IsClosed() {
+ return driver.ErrBadConn
+ }
+
+ return c.resetSessionFunc(ctx, c.conn)
+}
+
+type Stmt struct {
+ sd *pgconn.StatementDescription
+ conn *Conn
+}
+
+func (s *Stmt) Close() error {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
+ defer cancel()
+ return s.conn.conn.Deallocate(ctx, s.sd.Name)
+}
+
+func (s *Stmt) NumInput() int {
+ return len(s.sd.ParamOIDs)
+}
+
+func (s *Stmt) Exec(argsV []driver.Value) (driver.Result, error) {
+ return nil, errors.New("Stmt.Exec deprecated and not implemented")
+}
+
+func (s *Stmt) ExecContext(ctx context.Context, argsV []driver.NamedValue) (driver.Result, error) {
+ return s.conn.ExecContext(ctx, s.sd.Name, argsV)
+}
+
+func (s *Stmt) Query(argsV []driver.Value) (driver.Rows, error) {
+ return nil, errors.New("Stmt.Query deprecated and not implemented")
+}
+
+func (s *Stmt) QueryContext(ctx context.Context, argsV []driver.NamedValue) (driver.Rows, error) {
+ return s.conn.QueryContext(ctx, s.sd.Name, argsV)
+}
+
+type rowValueFunc func(src []byte) (driver.Value, error)
+
+type Rows struct {
+ conn *Conn
+ rows pgx.Rows
+ valueFuncs []rowValueFunc
+ skipNext bool
+ skipNextMore bool
+
+ columnNames []string
+}
+
+func (r *Rows) Columns() []string {
+ if r.columnNames == nil {
+ fields := r.rows.FieldDescriptions()
+ r.columnNames = make([]string, len(fields))
+ for i, fd := range fields {
+ r.columnNames[i] = string(fd.Name)
+ }
+ }
+
+ return r.columnNames
+}
+
+// ColumnTypeDatabaseTypeName returns the database system type name. If the name is unknown the OID is returned.
+func (r *Rows) ColumnTypeDatabaseTypeName(index int) string {
+ if dt, ok := r.conn.conn.ConnInfo().DataTypeForOID(r.rows.FieldDescriptions()[index].DataTypeOID); ok {
+ return strings.ToUpper(dt.Name)
+ }
+
+ return strconv.FormatInt(int64(r.rows.FieldDescriptions()[index].DataTypeOID), 10)
+}
+
+const varHeaderSize = 4
+
+// ColumnTypeLength returns the length of the column type if the column is a
+// variable length type. If the column is not a variable length type ok
+// should return false.
+func (r *Rows) ColumnTypeLength(index int) (int64, bool) {
+ fd := r.rows.FieldDescriptions()[index]
+
+ switch fd.DataTypeOID {
+ case pgtype.TextOID, pgtype.ByteaOID:
+ return math.MaxInt64, true
+ case pgtype.VarcharOID, pgtype.BPCharArrayOID:
+ return int64(fd.TypeModifier - varHeaderSize), true
+ default:
+ return 0, false
+ }
+}
+
+// ColumnTypePrecisionScale should return the precision and scale for decimal
+// types. If not applicable, ok should be false.
+func (r *Rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
+ fd := r.rows.FieldDescriptions()[index]
+
+ switch fd.DataTypeOID {
+ case pgtype.NumericOID:
+ mod := fd.TypeModifier - varHeaderSize
+ precision = int64((mod >> 16) & 0xffff)
+ scale = int64(mod & 0xffff)
+ return precision, scale, true
+ default:
+ return 0, 0, false
+ }
+}
+
+// ColumnTypeScanType returns the value type that can be used to scan types into.
+func (r *Rows) ColumnTypeScanType(index int) reflect.Type {
+ fd := r.rows.FieldDescriptions()[index]
+
+ switch fd.DataTypeOID {
+ case pgtype.Float8OID:
+ return reflect.TypeOf(float64(0))
+ case pgtype.Float4OID:
+ return reflect.TypeOf(float32(0))
+ case pgtype.Int8OID:
+ return reflect.TypeOf(int64(0))
+ case pgtype.Int4OID:
+ return reflect.TypeOf(int32(0))
+ case pgtype.Int2OID:
+ return reflect.TypeOf(int16(0))
+ case pgtype.BoolOID:
+ return reflect.TypeOf(false)
+ case pgtype.NumericOID:
+ return reflect.TypeOf(float64(0))
+ case pgtype.DateOID, pgtype.TimestampOID, pgtype.TimestamptzOID:
+ return reflect.TypeOf(time.Time{})
+ case pgtype.ByteaOID:
+ return reflect.TypeOf([]byte(nil))
+ default:
+ return reflect.TypeOf("")
+ }
+}
+
+func (r *Rows) Close() error {
+ r.rows.Close()
+ return r.rows.Err()
+}
+
+func (r *Rows) Next(dest []driver.Value) error {
+ ci := r.conn.conn.ConnInfo()
+ fieldDescriptions := r.rows.FieldDescriptions()
+
+ if r.valueFuncs == nil {
+ r.valueFuncs = make([]rowValueFunc, len(fieldDescriptions))
+
+ for i, fd := range fieldDescriptions {
+ dataTypeOID := fd.DataTypeOID
+ format := fd.Format
+
+ switch fd.DataTypeOID {
+ case pgtype.BoolOID:
+ var d bool
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return d, err
+ }
+ case pgtype.ByteaOID:
+ var d []byte
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return d, err
+ }
+ case pgtype.CIDOID:
+ var d pgtype.CID
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.DateOID:
+ var d pgtype.Date
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.Float4OID:
+ var d float32
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return float64(d), err
+ }
+ case pgtype.Float8OID:
+ var d float64
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return d, err
+ }
+ case pgtype.Int2OID:
+ var d int16
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return int64(d), err
+ }
+ case pgtype.Int4OID:
+ var d int32
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return int64(d), err
+ }
+ case pgtype.Int8OID:
+ var d int64
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return d, err
+ }
+ case pgtype.JSONOID:
+ var d pgtype.JSON
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.JSONBOID:
+ var d pgtype.JSONB
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.OIDOID:
+ var d pgtype.OIDValue
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.TimestampOID:
+ var d pgtype.Timestamp
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.TimestamptzOID:
+ var d pgtype.Timestamptz
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ case pgtype.XIDOID:
+ var d pgtype.XID
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ if err != nil {
+ return nil, err
+ }
+ return d.Value()
+ }
+ default:
+ var d string
+ scanPlan := ci.PlanScan(dataTypeOID, format, &d)
+ r.valueFuncs[i] = func(src []byte) (driver.Value, error) {
+ err := scanPlan.Scan(ci, dataTypeOID, format, src, &d)
+ return d, err
+ }
+ }
+ }
+ }
+
+ var more bool
+ if r.skipNext {
+ more = r.skipNextMore
+ r.skipNext = false
+ } else {
+ more = r.rows.Next()
+ }
+
+ if !more {
+ if r.rows.Err() == nil {
+ return io.EOF
+ } else {
+ return r.rows.Err()
+ }
+ }
+
+ for i, rv := range r.rows.RawValues() {
+ if rv != nil {
+ var err error
+ dest[i], err = r.valueFuncs[i](rv)
+ if err != nil {
+ return fmt.Errorf("convert field %d failed: %v", i, err)
+ }
+ } else {
+ dest[i] = nil
+ }
+ }
+
+ return nil
+}
+
+func valueToInterface(argsV []driver.Value) []interface{} {
+ args := make([]interface{}, 0, len(argsV))
+ for _, v := range argsV {
+ if v != nil {
+ args = append(args, v.(interface{}))
+ } else {
+ args = append(args, nil)
+ }
+ }
+ return args
+}
+
+func namedValueToInterface(argsV []driver.NamedValue) []interface{} {
+ args := make([]interface{}, 0, len(argsV))
+ for _, v := range argsV {
+ if v.Value != nil {
+ args = append(args, v.Value.(interface{}))
+ } else {
+ args = append(args, nil)
+ }
+ }
+ return args
+}
+
+type wrapTx struct {
+ ctx context.Context
+ tx pgx.Tx
+}
+
+func (wtx wrapTx) Commit() error { return wtx.tx.Commit(wtx.ctx) }
+
+func (wtx wrapTx) Rollback() error { return wtx.tx.Rollback(wtx.ctx) }
+
+type fakeTx struct{}
+
+func (fakeTx) Commit() error { return nil }
+
+func (fakeTx) Rollback() error { return nil }
+
+// AcquireConn acquires a *pgx.Conn from database/sql connection pool. It must be released with ReleaseConn.
+//
+// In Go 1.13 this functionality has been incorporated into the standard library in the db.Conn.Raw() method.
+func AcquireConn(db *sql.DB) (*pgx.Conn, error) {
+ var conn *pgx.Conn
+ ctx := context.WithValue(context.Background(), ctxKeyFakeTx, &conn)
+ tx, err := db.BeginTx(ctx, nil)
+ if err != nil {
+ return nil, err
+ }
+ if conn == nil {
+ tx.Rollback()
+ return nil, ErrNotPgx
+ }
+
+ fakeTxMutex.Lock()
+ fakeTxConns[conn] = tx
+ fakeTxMutex.Unlock()
+
+ return conn, nil
+}
+
+// ReleaseConn releases a *pgx.Conn acquired with AcquireConn.
+func ReleaseConn(db *sql.DB, conn *pgx.Conn) error {
+ var tx *sql.Tx
+ var ok bool
+
+ if conn.PgConn().IsBusy() || conn.PgConn().TxStatus() != 'I' {
+ ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+ defer cancel()
+ conn.Close(ctx)
+ }
+
+ fakeTxMutex.Lock()
+ tx, ok = fakeTxConns[conn]
+ if ok {
+ delete(fakeTxConns, conn)
+ fakeTxMutex.Unlock()
+ } else {
+ fakeTxMutex.Unlock()
+ return fmt.Errorf("can't release conn that is not acquired")
+ }
+
+ return tx.Rollback()
+}
diff --git a/vendor/github.com/jackc/pgx/v4/tx.go b/vendor/github.com/jackc/pgx/v4/tx.go
new file mode 100644
index 000000000..7a296f4fe
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/tx.go
@@ -0,0 +1,444 @@
+package pgx
+
+import (
+ "bytes"
+ "context"
+ "errors"
+ "fmt"
+ "strconv"
+
+ "github.com/jackc/pgconn"
+)
+
+type TxIsoLevel string
+
+// Transaction isolation levels
+const (
+ Serializable = TxIsoLevel("serializable")
+ RepeatableRead = TxIsoLevel("repeatable read")
+ ReadCommitted = TxIsoLevel("read committed")
+ ReadUncommitted = TxIsoLevel("read uncommitted")
+)
+
+type TxAccessMode string
+
+// Transaction access modes
+const (
+ ReadWrite = TxAccessMode("read write")
+ ReadOnly = TxAccessMode("read only")
+)
+
+type TxDeferrableMode string
+
+// Transaction deferrable modes
+const (
+ Deferrable = TxDeferrableMode("deferrable")
+ NotDeferrable = TxDeferrableMode("not deferrable")
+)
+
+type TxOptions struct {
+ IsoLevel TxIsoLevel
+ AccessMode TxAccessMode
+ DeferrableMode TxDeferrableMode
+}
+
+var emptyTxOptions TxOptions
+
+func (txOptions TxOptions) beginSQL() string {
+ if txOptions == emptyTxOptions {
+ return "begin"
+ }
+ buf := &bytes.Buffer{}
+ buf.WriteString("begin")
+ if txOptions.IsoLevel != "" {
+ fmt.Fprintf(buf, " isolation level %s", txOptions.IsoLevel)
+ }
+ if txOptions.AccessMode != "" {
+ fmt.Fprintf(buf, " %s", txOptions.AccessMode)
+ }
+ if txOptions.DeferrableMode != "" {
+ fmt.Fprintf(buf, " %s", txOptions.DeferrableMode)
+ }
+
+ return buf.String()
+}
+
+var ErrTxClosed = errors.New("tx is closed")
+
+// ErrTxCommitRollback occurs when an error has occurred in a transaction and
+// Commit() is called. PostgreSQL accepts COMMIT on aborted transactions, but
+// it is treated as ROLLBACK.
+var ErrTxCommitRollback = errors.New("commit unexpectedly resulted in rollback")
+
+// Begin starts a transaction. Unlike database/sql, the context only affects the begin command. i.e. there is no
+// auto-rollback on context cancellation.
+func (c *Conn) Begin(ctx context.Context) (Tx, error) {
+ return c.BeginTx(ctx, TxOptions{})
+}
+
+// BeginTx starts a transaction with txOptions determining the transaction mode. Unlike database/sql, the context only
+// affects the begin command. i.e. there is no auto-rollback on context cancellation.
+func (c *Conn) BeginTx(ctx context.Context, txOptions TxOptions) (Tx, error) {
+ _, err := c.Exec(ctx, txOptions.beginSQL())
+ if err != nil {
+ // begin should never fail unless there is an underlying connection issue or
+ // a context timeout. In either case, the connection is possibly broken.
+ c.die(errors.New("failed to begin transaction"))
+ return nil, err
+ }
+
+ return &dbTx{conn: c}, nil
+}
+
+// BeginFunc starts a transaction and calls f. If f does not return an error the transaction is committed. If f returns
+// an error the transaction is rolled back. The context will be used when executing the transaction control statements
+// (BEGIN, ROLLBACK, and COMMIT) but does not otherwise affect the execution of f.
+func (c *Conn) BeginFunc(ctx context.Context, f func(Tx) error) (err error) {
+ return c.BeginTxFunc(ctx, TxOptions{}, f)
+}
+
+// BeginTxFunc starts a transaction with txOptions determining the transaction mode and calls f. If f does not return
+// an error the transaction is committed. If f returns an error the transaction is rolled back. The context will be
+// used when executing the transaction control statements (BEGIN, ROLLBACK, and COMMIT) but does not otherwise affect
+// the execution of f.
+func (c *Conn) BeginTxFunc(ctx context.Context, txOptions TxOptions, f func(Tx) error) (err error) {
+ var tx Tx
+ tx, err = c.BeginTx(ctx, txOptions)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ rollbackErr := tx.Rollback(ctx)
+ if !(rollbackErr == nil || errors.Is(rollbackErr, ErrTxClosed)) {
+ err = rollbackErr
+ }
+ }()
+
+ fErr := f(tx)
+ if fErr != nil {
+ _ = tx.Rollback(ctx) // ignore rollback error as there is already an error to return
+ return fErr
+ }
+
+ return tx.Commit(ctx)
+}
+
+// Tx represents a database transaction.
+//
+// Tx is an interface instead of a struct to enable connection pools to be implemented without relying on internal pgx
+// state, to support pseudo-nested transactions with savepoints, and to allow tests to mock transactions. However,
+// adding a method to an interface is technically a breaking change. If new methods are added to Conn it may be
+// desirable to add them to Tx as well. Because of this the Tx interface is partially excluded from semantic version
+// requirements. Methods will not be removed or changed, but new methods may be added.
+type Tx interface {
+ // Begin starts a pseudo nested transaction.
+ Begin(ctx context.Context) (Tx, error)
+
+ // BeginFunc starts a pseudo nested transaction and executes f. If f does not return an err the pseudo nested
+ // transaction will be committed. If it does then it will be rolled back.
+ BeginFunc(ctx context.Context, f func(Tx) error) (err error)
+
+ // Commit commits the transaction if this is a real transaction or releases the savepoint if this is a pseudo nested
+ // transaction. Commit will return ErrTxClosed if the Tx is already closed, but is otherwise safe to call multiple
+ // times. If the commit fails with a rollback status (e.g. the transaction was already in a broken state) then
+ // ErrTxCommitRollback will be returned.
+ Commit(ctx context.Context) error
+
+ // Rollback rolls back the transaction if this is a real transaction or rolls back to the savepoint if this is a
+ // pseudo nested transaction. Rollback will return ErrTxClosed if the Tx is already closed, but is otherwise safe to
+ // call multiple times. Hence, a defer tx.Rollback() is safe even if tx.Commit() will be called first in a non-error
+ // condition. Any other failure of a real transaction will result in the connection being closed.
+ Rollback(ctx context.Context) error
+
+ CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error)
+ SendBatch(ctx context.Context, b *Batch) BatchResults
+ LargeObjects() LargeObjects
+
+ Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error)
+
+ Exec(ctx context.Context, sql string, arguments ...interface{}) (commandTag pgconn.CommandTag, err error)
+ Query(ctx context.Context, sql string, args ...interface{}) (Rows, error)
+ QueryRow(ctx context.Context, sql string, args ...interface{}) Row
+ QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error)
+
+ // Conn returns the underlying *Conn that on which this transaction is executing.
+ Conn() *Conn
+}
+
+// dbTx represents a database transaction.
+//
+// All dbTx methods return ErrTxClosed if Commit or Rollback has already been
+// called on the dbTx.
+type dbTx struct {
+ conn *Conn
+ err error
+ savepointNum int64
+ closed bool
+}
+
+// Begin starts a pseudo nested transaction implemented with a savepoint.
+func (tx *dbTx) Begin(ctx context.Context) (Tx, error) {
+ if tx.closed {
+ return nil, ErrTxClosed
+ }
+
+ tx.savepointNum++
+ _, err := tx.conn.Exec(ctx, "savepoint sp_"+strconv.FormatInt(tx.savepointNum, 10))
+ if err != nil {
+ return nil, err
+ }
+
+ return &dbSavepoint{tx: tx, savepointNum: tx.savepointNum}, nil
+}
+
+func (tx *dbTx) BeginFunc(ctx context.Context, f func(Tx) error) (err error) {
+ if tx.closed {
+ return ErrTxClosed
+ }
+
+ var savepoint Tx
+ savepoint, err = tx.Begin(ctx)
+ if err != nil {
+ return err
+ }
+ defer func() {
+ rollbackErr := savepoint.Rollback(ctx)
+ if !(rollbackErr == nil || errors.Is(rollbackErr, ErrTxClosed)) {
+ err = rollbackErr
+ }
+ }()
+
+ fErr := f(savepoint)
+ if fErr != nil {
+ _ = savepoint.Rollback(ctx) // ignore rollback error as there is already an error to return
+ return fErr
+ }
+
+ return savepoint.Commit(ctx)
+}
+
+// Commit commits the transaction.
+func (tx *dbTx) Commit(ctx context.Context) error {
+ if tx.closed {
+ return ErrTxClosed
+ }
+
+ commandTag, err := tx.conn.Exec(ctx, "commit")
+ tx.closed = true
+ if err != nil {
+ if tx.conn.PgConn().TxStatus() != 'I' {
+ _ = tx.conn.Close(ctx) // already have error to return
+ }
+ return err
+ }
+ if string(commandTag) == "ROLLBACK" {
+ return ErrTxCommitRollback
+ }
+
+ return nil
+}
+
+// Rollback rolls back the transaction. Rollback will return ErrTxClosed if the
+// Tx is already closed, but is otherwise safe to call multiple times. Hence, a
+// defer tx.Rollback() is safe even if tx.Commit() will be called first in a
+// non-error condition.
+func (tx *dbTx) Rollback(ctx context.Context) error {
+ if tx.closed {
+ return ErrTxClosed
+ }
+
+ _, err := tx.conn.Exec(ctx, "rollback")
+ tx.closed = true
+ if err != nil {
+ // A rollback failure leaves the connection in an undefined state
+ tx.conn.die(fmt.Errorf("rollback failed: %w", err))
+ return err
+ }
+
+ return nil
+}
+
+// Exec delegates to the underlying *Conn
+func (tx *dbTx) Exec(ctx context.Context, sql string, arguments ...interface{}) (commandTag pgconn.CommandTag, err error) {
+ return tx.conn.Exec(ctx, sql, arguments...)
+}
+
+// Prepare delegates to the underlying *Conn
+func (tx *dbTx) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
+ if tx.closed {
+ return nil, ErrTxClosed
+ }
+
+ return tx.conn.Prepare(ctx, name, sql)
+}
+
+// Query delegates to the underlying *Conn
+func (tx *dbTx) Query(ctx context.Context, sql string, args ...interface{}) (Rows, error) {
+ if tx.closed {
+ // Because checking for errors can be deferred to the *Rows, build one with the error
+ err := ErrTxClosed
+ return &connRows{closed: true, err: err}, err
+ }
+
+ return tx.conn.Query(ctx, sql, args...)
+}
+
+// QueryRow delegates to the underlying *Conn
+func (tx *dbTx) QueryRow(ctx context.Context, sql string, args ...interface{}) Row {
+ rows, _ := tx.Query(ctx, sql, args...)
+ return (*connRow)(rows.(*connRows))
+}
+
+// QueryFunc delegates to the underlying *Conn.
+func (tx *dbTx) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error) {
+ if tx.closed {
+ return nil, ErrTxClosed
+ }
+
+ return tx.conn.QueryFunc(ctx, sql, args, scans, f)
+}
+
+// CopyFrom delegates to the underlying *Conn
+func (tx *dbTx) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+ if tx.closed {
+ return 0, ErrTxClosed
+ }
+
+ return tx.conn.CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// SendBatch delegates to the underlying *Conn
+func (tx *dbTx) SendBatch(ctx context.Context, b *Batch) BatchResults {
+ if tx.closed {
+ return &batchResults{err: ErrTxClosed}
+ }
+
+ return tx.conn.SendBatch(ctx, b)
+}
+
+// LargeObjects returns a LargeObjects instance for the transaction.
+func (tx *dbTx) LargeObjects() LargeObjects {
+ return LargeObjects{tx: tx}
+}
+
+func (tx *dbTx) Conn() *Conn {
+ return tx.conn
+}
+
+// dbSavepoint represents a nested transaction implemented by a savepoint.
+type dbSavepoint struct {
+ tx Tx
+ savepointNum int64
+ closed bool
+}
+
+// Begin starts a pseudo nested transaction implemented with a savepoint.
+func (sp *dbSavepoint) Begin(ctx context.Context) (Tx, error) {
+ if sp.closed {
+ return nil, ErrTxClosed
+ }
+
+ return sp.tx.Begin(ctx)
+}
+
+func (sp *dbSavepoint) BeginFunc(ctx context.Context, f func(Tx) error) (err error) {
+ if sp.closed {
+ return ErrTxClosed
+ }
+
+ return sp.tx.BeginFunc(ctx, f)
+}
+
+// Commit releases the savepoint essentially committing the pseudo nested transaction.
+func (sp *dbSavepoint) Commit(ctx context.Context) error {
+ if sp.closed {
+ return ErrTxClosed
+ }
+
+ _, err := sp.Exec(ctx, "release savepoint sp_"+strconv.FormatInt(sp.savepointNum, 10))
+ sp.closed = true
+ return err
+}
+
+// Rollback rolls back to the savepoint essentially rolling back the pseudo nested transaction. Rollback will return
+// ErrTxClosed if the dbSavepoint is already closed, but is otherwise safe to call multiple times. Hence, a defer sp.Rollback()
+// is safe even if sp.Commit() will be called first in a non-error condition.
+func (sp *dbSavepoint) Rollback(ctx context.Context) error {
+ if sp.closed {
+ return ErrTxClosed
+ }
+
+ _, err := sp.Exec(ctx, "rollback to savepoint sp_"+strconv.FormatInt(sp.savepointNum, 10))
+ sp.closed = true
+ return err
+}
+
+// Exec delegates to the underlying Tx
+func (sp *dbSavepoint) Exec(ctx context.Context, sql string, arguments ...interface{}) (commandTag pgconn.CommandTag, err error) {
+ if sp.closed {
+ return nil, ErrTxClosed
+ }
+
+ return sp.tx.Exec(ctx, sql, arguments...)
+}
+
+// Prepare delegates to the underlying Tx
+func (sp *dbSavepoint) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) {
+ if sp.closed {
+ return nil, ErrTxClosed
+ }
+
+ return sp.tx.Prepare(ctx, name, sql)
+}
+
+// Query delegates to the underlying Tx
+func (sp *dbSavepoint) Query(ctx context.Context, sql string, args ...interface{}) (Rows, error) {
+ if sp.closed {
+ // Because checking for errors can be deferred to the *Rows, build one with the error
+ err := ErrTxClosed
+ return &connRows{closed: true, err: err}, err
+ }
+
+ return sp.tx.Query(ctx, sql, args...)
+}
+
+// QueryRow delegates to the underlying Tx
+func (sp *dbSavepoint) QueryRow(ctx context.Context, sql string, args ...interface{}) Row {
+ rows, _ := sp.Query(ctx, sql, args...)
+ return (*connRow)(rows.(*connRows))
+}
+
+// QueryFunc delegates to the underlying Tx.
+func (sp *dbSavepoint) QueryFunc(ctx context.Context, sql string, args []interface{}, scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error) {
+ if sp.closed {
+ return nil, ErrTxClosed
+ }
+
+ return sp.tx.QueryFunc(ctx, sql, args, scans, f)
+}
+
+// CopyFrom delegates to the underlying *Conn
+func (sp *dbSavepoint) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) {
+ if sp.closed {
+ return 0, ErrTxClosed
+ }
+
+ return sp.tx.CopyFrom(ctx, tableName, columnNames, rowSrc)
+}
+
+// SendBatch delegates to the underlying *Conn
+func (sp *dbSavepoint) SendBatch(ctx context.Context, b *Batch) BatchResults {
+ if sp.closed {
+ return &batchResults{err: ErrTxClosed}
+ }
+
+ return sp.tx.SendBatch(ctx, b)
+}
+
+func (sp *dbSavepoint) LargeObjects() LargeObjects {
+ return LargeObjects{tx: sp}
+}
+
+func (sp *dbSavepoint) Conn() *Conn {
+ return sp.tx.Conn()
+}
diff --git a/vendor/github.com/jackc/pgx/v4/values.go b/vendor/github.com/jackc/pgx/v4/values.go
new file mode 100644
index 000000000..1a9454753
--- /dev/null
+++ b/vendor/github.com/jackc/pgx/v4/values.go
@@ -0,0 +1,280 @@
+package pgx
+
+import (
+ "database/sql/driver"
+ "fmt"
+ "math"
+ "reflect"
+ "time"
+
+ "github.com/jackc/pgio"
+ "github.com/jackc/pgtype"
+)
+
+// PostgreSQL format codes
+const (
+ TextFormatCode = 0
+ BinaryFormatCode = 1
+)
+
+// SerializationError occurs on failure to encode or decode a value
+type SerializationError string
+
+func (e SerializationError) Error() string {
+ return string(e)
+}
+
+func convertSimpleArgument(ci *pgtype.ConnInfo, arg interface{}) (interface{}, error) {
+ if arg == nil {
+ return nil, nil
+ }
+
+ refVal := reflect.ValueOf(arg)
+ if refVal.Kind() == reflect.Ptr && refVal.IsNil() {
+ return nil, nil
+ }
+
+ switch arg := arg.(type) {
+
+ // https://github.com/jackc/pgx/issues/409 Changed JSON and JSONB to surface
+ // []byte to database/sql instead of string. But that caused problems with the
+ // simple protocol because the driver.Valuer case got taken before the
+ // pgtype.TextEncoder case. And driver.Valuer needed to be first in the usual
+ // case because of https://github.com/jackc/pgx/issues/339. So instead we
+ // special case JSON and JSONB.
+ case *pgtype.JSON:
+ buf, err := arg.EncodeText(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ return string(buf), nil
+ case *pgtype.JSONB:
+ buf, err := arg.EncodeText(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ return string(buf), nil
+
+ case driver.Valuer:
+ return callValuerValue(arg)
+ case pgtype.TextEncoder:
+ buf, err := arg.EncodeText(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ return string(buf), nil
+ case float32:
+ return float64(arg), nil
+ case float64:
+ return arg, nil
+ case bool:
+ return arg, nil
+ case time.Duration:
+ return fmt.Sprintf("%d microsecond", int64(arg)/1000), nil
+ case time.Time:
+ return arg, nil
+ case string:
+ return arg, nil
+ case []byte:
+ return arg, nil
+ case int8:
+ return int64(arg), nil
+ case int16:
+ return int64(arg), nil
+ case int32:
+ return int64(arg), nil
+ case int64:
+ return arg, nil
+ case int:
+ return int64(arg), nil
+ case uint8:
+ return int64(arg), nil
+ case uint16:
+ return int64(arg), nil
+ case uint32:
+ return int64(arg), nil
+ case uint64:
+ if arg > math.MaxInt64 {
+ return nil, fmt.Errorf("arg too big for int64: %v", arg)
+ }
+ return int64(arg), nil
+ case uint:
+ if uint64(arg) > math.MaxInt64 {
+ return nil, fmt.Errorf("arg too big for int64: %v", arg)
+ }
+ return int64(arg), nil
+ }
+
+ if dt, found := ci.DataTypeForValue(arg); found {
+ v := dt.Value
+ err := v.Set(arg)
+ if err != nil {
+ return nil, err
+ }
+ buf, err := v.(pgtype.TextEncoder).EncodeText(ci, nil)
+ if err != nil {
+ return nil, err
+ }
+ if buf == nil {
+ return nil, nil
+ }
+ return string(buf), nil
+ }
+
+ if refVal.Kind() == reflect.Ptr {
+ arg = refVal.Elem().Interface()
+ return convertSimpleArgument(ci, arg)
+ }
+
+ if strippedArg, ok := stripNamedType(&refVal); ok {
+ return convertSimpleArgument(ci, strippedArg)
+ }
+ return nil, SerializationError(fmt.Sprintf("Cannot encode %T in simple protocol - %T must implement driver.Valuer, pgtype.TextEncoder, or be a native type", arg, arg))
+}
+
+func encodePreparedStatementArgument(ci *pgtype.ConnInfo, buf []byte, oid uint32, arg interface{}) ([]byte, error) {
+ if arg == nil {
+ return pgio.AppendInt32(buf, -1), nil
+ }
+
+ switch arg := arg.(type) {
+ case pgtype.BinaryEncoder:
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+ argBuf, err := arg.EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if argBuf != nil {
+ buf = argBuf
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+ return buf, nil
+ case pgtype.TextEncoder:
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+ argBuf, err := arg.EncodeText(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if argBuf != nil {
+ buf = argBuf
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+ return buf, nil
+ case string:
+ buf = pgio.AppendInt32(buf, int32(len(arg)))
+ buf = append(buf, arg...)
+ return buf, nil
+ }
+
+ refVal := reflect.ValueOf(arg)
+
+ if refVal.Kind() == reflect.Ptr {
+ if refVal.IsNil() {
+ return pgio.AppendInt32(buf, -1), nil
+ }
+ arg = refVal.Elem().Interface()
+ return encodePreparedStatementArgument(ci, buf, oid, arg)
+ }
+
+ if dt, ok := ci.DataTypeForOID(oid); ok {
+ value := dt.Value
+ err := value.Set(arg)
+ if err != nil {
+ {
+ if arg, ok := arg.(driver.Valuer); ok {
+ v, err := callValuerValue(arg)
+ if err != nil {
+ return nil, err
+ }
+ return encodePreparedStatementArgument(ci, buf, oid, v)
+ }
+ }
+
+ return nil, err
+ }
+
+ sp := len(buf)
+ buf = pgio.AppendInt32(buf, -1)
+ argBuf, err := value.(pgtype.BinaryEncoder).EncodeBinary(ci, buf)
+ if err != nil {
+ return nil, err
+ }
+ if argBuf != nil {
+ buf = argBuf
+ pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
+ }
+ return buf, nil
+ }
+
+ if strippedArg, ok := stripNamedType(&refVal); ok {
+ return encodePreparedStatementArgument(ci, buf, oid, strippedArg)
+ }
+ return nil, SerializationError(fmt.Sprintf("Cannot encode %T into oid %v - %T must implement Encoder or be converted to a string", arg, oid, arg))
+}
+
+// chooseParameterFormatCode determines the correct format code for an
+// argument to a prepared statement. It defaults to TextFormatCode if no
+// determination can be made.
+func chooseParameterFormatCode(ci *pgtype.ConnInfo, oid uint32, arg interface{}) int16 {
+ switch arg := arg.(type) {
+ case pgtype.ParamFormatPreferrer:
+ return arg.PreferredParamFormat()
+ case pgtype.BinaryEncoder:
+ return BinaryFormatCode
+ case string, *string, pgtype.TextEncoder:
+ return TextFormatCode
+ }
+
+ return ci.ParamFormatCodeForOID(oid)
+}
+
+func stripNamedType(val *reflect.Value) (interface{}, bool) {
+ switch val.Kind() {
+ case reflect.Int:
+ convVal := int(val.Int())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Int8:
+ convVal := int8(val.Int())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Int16:
+ convVal := int16(val.Int())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Int32:
+ convVal := int32(val.Int())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Int64:
+ convVal := int64(val.Int())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Uint:
+ convVal := uint(val.Uint())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Uint8:
+ convVal := uint8(val.Uint())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Uint16:
+ convVal := uint16(val.Uint())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Uint32:
+ convVal := uint32(val.Uint())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.Uint64:
+ convVal := uint64(val.Uint())
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ case reflect.String:
+ convVal := val.String()
+ return convVal, reflect.TypeOf(convVal) != val.Type()
+ }
+
+ return nil, false
+}