summaryrefslogtreecommitdiff
path: root/vendor/github.com/go-pg/pg/v10/internal
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-pg/pg/v10/internal')
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/context.go26
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/error.go61
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/internal.go27
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/log.go28
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/parser/parser.go141
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go65
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/conn.go158
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/pool.go506
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go58
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go202
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/reader.go80
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go431
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go121
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go114
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/safe.go11
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/strconv.go19
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/underscore.go93
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/unsafe.go22
-rw-r--r--vendor/github.com/go-pg/pg/v10/internal/util.go71
19 files changed, 2234 insertions, 0 deletions
diff --git a/vendor/github.com/go-pg/pg/v10/internal/context.go b/vendor/github.com/go-pg/pg/v10/internal/context.go
new file mode 100644
index 000000000..06d20c152
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/context.go
@@ -0,0 +1,26 @@
+package internal
+
+import (
+ "context"
+ "time"
+)
+
+type UndoneContext struct {
+ context.Context
+}
+
+func UndoContext(ctx context.Context) UndoneContext {
+ return UndoneContext{Context: ctx}
+}
+
+func (UndoneContext) Deadline() (deadline time.Time, ok bool) {
+ return time.Time{}, false
+}
+
+func (UndoneContext) Done() <-chan struct{} {
+ return nil
+}
+
+func (UndoneContext) Err() error {
+ return nil
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/error.go b/vendor/github.com/go-pg/pg/v10/internal/error.go
new file mode 100644
index 000000000..ae6524aeb
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/error.go
@@ -0,0 +1,61 @@
+package internal
+
+import (
+ "fmt"
+)
+
+var (
+ ErrNoRows = Errorf("pg: no rows in result set")
+ ErrMultiRows = Errorf("pg: multiple rows in result set")
+)
+
+type Error struct {
+ s string
+}
+
+func Errorf(s string, args ...interface{}) Error {
+ return Error{s: fmt.Sprintf(s, args...)}
+}
+
+func (err Error) Error() string {
+ return err.s
+}
+
+type PGError struct {
+ m map[byte]string
+}
+
+func NewPGError(m map[byte]string) PGError {
+ return PGError{
+ m: m,
+ }
+}
+
+func (err PGError) Field(k byte) string {
+ return err.m[k]
+}
+
+func (err PGError) IntegrityViolation() bool {
+ switch err.Field('C') {
+ case "23000", "23001", "23502", "23503", "23505", "23514", "23P01":
+ return true
+ default:
+ return false
+ }
+}
+
+func (err PGError) Error() string {
+ return fmt.Sprintf("%s #%s %s",
+ err.Field('S'), err.Field('C'), err.Field('M'))
+}
+
+func AssertOneRow(l int) error {
+ switch {
+ case l == 0:
+ return ErrNoRows
+ case l > 1:
+ return ErrMultiRows
+ default:
+ return nil
+ }
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/internal.go b/vendor/github.com/go-pg/pg/v10/internal/internal.go
new file mode 100644
index 000000000..bda5028c6
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/internal.go
@@ -0,0 +1,27 @@
+/*
+internal is a private internal package.
+*/
+package internal
+
+import (
+ "math/rand"
+ "time"
+)
+
+func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration {
+ if retry < 0 {
+ panic("not reached")
+ }
+ if minBackoff == 0 {
+ return 0
+ }
+
+ d := minBackoff << uint(retry)
+ d = minBackoff + time.Duration(rand.Int63n(int64(d)))
+
+ if d > maxBackoff || d < minBackoff {
+ d = maxBackoff
+ }
+
+ return d
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/log.go b/vendor/github.com/go-pg/pg/v10/internal/log.go
new file mode 100644
index 000000000..7ea547b10
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/log.go
@@ -0,0 +1,28 @@
+package internal
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "os"
+)
+
+var Warn = log.New(os.Stderr, "WARN: pg: ", log.LstdFlags)
+
+var Deprecated = log.New(os.Stderr, "DEPRECATED: pg: ", log.LstdFlags)
+
+type Logging interface {
+ Printf(ctx context.Context, format string, v ...interface{})
+}
+
+type logger struct {
+ log *log.Logger
+}
+
+func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) {
+ _ = l.log.Output(2, fmt.Sprintf(format, v...))
+}
+
+var Logger Logging = &logger{
+ log: log.New(os.Stderr, "pg: ", log.LstdFlags|log.Lshortfile),
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go b/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go
new file mode 100644
index 000000000..f2db676c9
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/parser/parser.go
@@ -0,0 +1,141 @@
+package parser
+
+import (
+ "bytes"
+ "strconv"
+
+ "github.com/go-pg/pg/v10/internal"
+)
+
+type Parser struct {
+ b []byte
+ i int
+}
+
+func New(b []byte) *Parser {
+ return &Parser{
+ b: b,
+ }
+}
+
+func NewString(s string) *Parser {
+ return New(internal.StringToBytes(s))
+}
+
+func (p *Parser) Valid() bool {
+ return p.i < len(p.b)
+}
+
+func (p *Parser) Bytes() []byte {
+ return p.b[p.i:]
+}
+
+func (p *Parser) Read() byte {
+ if p.Valid() {
+ c := p.b[p.i]
+ p.Advance()
+ return c
+ }
+ return 0
+}
+
+func (p *Parser) Peek() byte {
+ if p.Valid() {
+ return p.b[p.i]
+ }
+ return 0
+}
+
+func (p *Parser) Advance() {
+ p.i++
+}
+
+func (p *Parser) Skip(skip byte) bool {
+ if p.Peek() == skip {
+ p.Advance()
+ return true
+ }
+ return false
+}
+
+func (p *Parser) SkipBytes(skip []byte) bool {
+ if len(skip) > len(p.b[p.i:]) {
+ return false
+ }
+ if !bytes.Equal(p.b[p.i:p.i+len(skip)], skip) {
+ return false
+ }
+ p.i += len(skip)
+ return true
+}
+
+func (p *Parser) ReadSep(sep byte) ([]byte, bool) {
+ ind := bytes.IndexByte(p.b[p.i:], sep)
+ if ind == -1 {
+ b := p.b[p.i:]
+ p.i = len(p.b)
+ return b, false
+ }
+
+ b := p.b[p.i : p.i+ind]
+ p.i += ind + 1
+ return b, true
+}
+
+func (p *Parser) ReadIdentifier() (string, bool) {
+ if p.i < len(p.b) && p.b[p.i] == '(' {
+ s := p.i + 1
+ if ind := bytes.IndexByte(p.b[s:], ')'); ind != -1 {
+ b := p.b[s : s+ind]
+ p.i = s + ind + 1
+ return internal.BytesToString(b), false
+ }
+ }
+
+ ind := len(p.b) - p.i
+ var alpha bool
+ for i, c := range p.b[p.i:] {
+ if isNum(c) {
+ continue
+ }
+ if isAlpha(c) || (i > 0 && alpha && c == '_') {
+ alpha = true
+ continue
+ }
+ ind = i
+ break
+ }
+ if ind == 0 {
+ return "", false
+ }
+ b := p.b[p.i : p.i+ind]
+ p.i += ind
+ return internal.BytesToString(b), !alpha
+}
+
+func (p *Parser) ReadNumber() int {
+ ind := len(p.b) - p.i
+ for i, c := range p.b[p.i:] {
+ if !isNum(c) {
+ ind = i
+ break
+ }
+ }
+ if ind == 0 {
+ return 0
+ }
+ n, err := strconv.Atoi(string(p.b[p.i : p.i+ind]))
+ if err != nil {
+ panic(err)
+ }
+ p.i += ind
+ return n
+}
+
+func isNum(c byte) bool {
+ return c >= '0' && c <= '9'
+}
+
+func isAlpha(c byte) bool {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go b/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go
new file mode 100644
index 000000000..723c12b16
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/parser/streaming_parser.go
@@ -0,0 +1,65 @@
+package parser
+
+import (
+ "fmt"
+
+ "github.com/go-pg/pg/v10/internal/pool"
+)
+
+type StreamingParser struct {
+ pool.Reader
+}
+
+func NewStreamingParser(rd pool.Reader) StreamingParser {
+ return StreamingParser{
+ Reader: rd,
+ }
+}
+
+func (p StreamingParser) SkipByte(skip byte) error {
+ c, err := p.ReadByte()
+ if err != nil {
+ return err
+ }
+ if c == skip {
+ return nil
+ }
+ _ = p.UnreadByte()
+ return fmt.Errorf("got %q, wanted %q", c, skip)
+}
+
+func (p StreamingParser) ReadSubstring(b []byte) ([]byte, error) {
+ c, err := p.ReadByte()
+ if err != nil {
+ return b, err
+ }
+
+ for {
+ if c == '"' {
+ return b, nil
+ }
+
+ next, err := p.ReadByte()
+ if err != nil {
+ return b, err
+ }
+
+ if c == '\\' {
+ switch next {
+ case '\\', '"':
+ b = append(b, next)
+ c, err = p.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ default:
+ b = append(b, '\\')
+ c = next
+ }
+ continue
+ }
+
+ b = append(b, c)
+ c = next
+ }
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go b/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go
new file mode 100644
index 000000000..91045245b
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/conn.go
@@ -0,0 +1,158 @@
+package pool
+
+import (
+ "context"
+ "net"
+ "strconv"
+ "sync/atomic"
+ "time"
+)
+
+var noDeadline = time.Time{}
+
+type Conn struct {
+ netConn net.Conn
+ rd *ReaderContext
+
+ ProcessID int32
+ SecretKey int32
+ lastID int64
+
+ createdAt time.Time
+ usedAt uint32 // atomic
+ pooled bool
+ Inited bool
+}
+
+func NewConn(netConn net.Conn) *Conn {
+ cn := &Conn{
+ createdAt: time.Now(),
+ }
+ cn.SetNetConn(netConn)
+ cn.SetUsedAt(time.Now())
+ return cn
+}
+
+func (cn *Conn) UsedAt() time.Time {
+ unix := atomic.LoadUint32(&cn.usedAt)
+ return time.Unix(int64(unix), 0)
+}
+
+func (cn *Conn) SetUsedAt(tm time.Time) {
+ atomic.StoreUint32(&cn.usedAt, uint32(tm.Unix()))
+}
+
+func (cn *Conn) RemoteAddr() net.Addr {
+ return cn.netConn.RemoteAddr()
+}
+
+func (cn *Conn) SetNetConn(netConn net.Conn) {
+ cn.netConn = netConn
+ if cn.rd != nil {
+ cn.rd.Reset(netConn)
+ }
+}
+
+func (cn *Conn) LockReader() {
+ if cn.rd != nil {
+ panic("not reached")
+ }
+ cn.rd = NewReaderContext()
+ cn.rd.Reset(cn.netConn)
+}
+
+func (cn *Conn) NetConn() net.Conn {
+ return cn.netConn
+}
+
+func (cn *Conn) NextID() string {
+ cn.lastID++
+ return strconv.FormatInt(cn.lastID, 10)
+}
+
+func (cn *Conn) WithReader(
+ ctx context.Context, timeout time.Duration, fn func(rd *ReaderContext) error,
+) error {
+ if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil {
+ return err
+ }
+
+ rd := cn.rd
+ if rd == nil {
+ rd = GetReaderContext()
+ defer PutReaderContext(rd)
+
+ rd.Reset(cn.netConn)
+ }
+
+ rd.bytesRead = 0
+
+ if err := fn(rd); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (cn *Conn) WithWriter(
+ ctx context.Context, timeout time.Duration, fn func(wb *WriteBuffer) error,
+) error {
+ wb := GetWriteBuffer()
+ defer PutWriteBuffer(wb)
+
+ if err := fn(wb); err != nil {
+ return err
+ }
+
+ return cn.writeBuffer(ctx, timeout, wb)
+}
+
+func (cn *Conn) WriteBuffer(ctx context.Context, timeout time.Duration, wb *WriteBuffer) error {
+ return cn.writeBuffer(ctx, timeout, wb)
+}
+
+func (cn *Conn) writeBuffer(
+ ctx context.Context,
+ timeout time.Duration,
+ wb *WriteBuffer,
+) error {
+ if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil {
+ return err
+ }
+ if _, err := cn.netConn.Write(wb.Bytes); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (cn *Conn) Close() error {
+ return cn.netConn.Close()
+}
+
+func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time {
+ tm := time.Now()
+ cn.SetUsedAt(tm)
+
+ if timeout > 0 {
+ tm = tm.Add(timeout)
+ }
+
+ if ctx != nil {
+ deadline, ok := ctx.Deadline()
+ if ok {
+ if timeout == 0 {
+ return deadline
+ }
+ if deadline.Before(tm) {
+ return deadline
+ }
+ return tm
+ }
+ }
+
+ if timeout > 0 {
+ return tm
+ }
+
+ return noDeadline
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/pool.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool.go
new file mode 100644
index 000000000..59f2c72d0
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool.go
@@ -0,0 +1,506 @@
+package pool
+
+import (
+ "context"
+ "errors"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+
+ "github.com/go-pg/pg/v10/internal"
+)
+
+var (
+ ErrClosed = errors.New("pg: database is closed")
+ ErrPoolTimeout = errors.New("pg: connection pool timeout")
+)
+
+var timers = sync.Pool{
+ New: func() interface{} {
+ t := time.NewTimer(time.Hour)
+ t.Stop()
+ return t
+ },
+}
+
+// Stats contains pool state information and accumulated stats.
+type Stats struct {
+ Hits uint32 // number of times free connection was found in the pool
+ Misses uint32 // number of times free connection was NOT found in the pool
+ Timeouts uint32 // number of times a wait timeout occurred
+
+ TotalConns uint32 // number of total connections in the pool
+ IdleConns uint32 // number of idle connections in the pool
+ StaleConns uint32 // number of stale connections removed from the pool
+}
+
+type Pooler interface {
+ NewConn(context.Context) (*Conn, error)
+ CloseConn(*Conn) error
+
+ Get(context.Context) (*Conn, error)
+ Put(context.Context, *Conn)
+ Remove(context.Context, *Conn, error)
+
+ Len() int
+ IdleLen() int
+ Stats() *Stats
+
+ Close() error
+}
+
+type Options struct {
+ Dialer func(context.Context) (net.Conn, error)
+ OnClose func(*Conn) error
+
+ PoolSize int
+ MinIdleConns int
+ MaxConnAge time.Duration
+ PoolTimeout time.Duration
+ IdleTimeout time.Duration
+ IdleCheckFrequency time.Duration
+}
+
+type ConnPool struct {
+ opt *Options
+
+ dialErrorsNum uint32 // atomic
+
+ _closed uint32 // atomic
+
+ lastDialErrorMu sync.RWMutex
+ lastDialError error
+
+ queue chan struct{}
+
+ stats Stats
+
+ connsMu sync.Mutex
+ conns []*Conn
+ idleConns []*Conn
+
+ poolSize int
+ idleConnsLen int
+}
+
+var _ Pooler = (*ConnPool)(nil)
+
+func NewConnPool(opt *Options) *ConnPool {
+ p := &ConnPool{
+ opt: opt,
+
+ queue: make(chan struct{}, opt.PoolSize),
+ conns: make([]*Conn, 0, opt.PoolSize),
+ idleConns: make([]*Conn, 0, opt.PoolSize),
+ }
+
+ p.connsMu.Lock()
+ p.checkMinIdleConns()
+ p.connsMu.Unlock()
+
+ if opt.IdleTimeout > 0 && opt.IdleCheckFrequency > 0 {
+ go p.reaper(opt.IdleCheckFrequency)
+ }
+
+ return p
+}
+
+func (p *ConnPool) checkMinIdleConns() {
+ if p.opt.MinIdleConns == 0 {
+ return
+ }
+ for p.poolSize < p.opt.PoolSize && p.idleConnsLen < p.opt.MinIdleConns {
+ p.poolSize++
+ p.idleConnsLen++
+ go func() {
+ err := p.addIdleConn()
+ if err != nil {
+ p.connsMu.Lock()
+ p.poolSize--
+ p.idleConnsLen--
+ p.connsMu.Unlock()
+ }
+ }()
+ }
+}
+
+func (p *ConnPool) addIdleConn() error {
+ cn, err := p.dialConn(context.TODO(), true)
+ if err != nil {
+ return err
+ }
+
+ p.connsMu.Lock()
+ p.conns = append(p.conns, cn)
+ p.idleConns = append(p.idleConns, cn)
+ p.connsMu.Unlock()
+ return nil
+}
+
+func (p *ConnPool) NewConn(c context.Context) (*Conn, error) {
+ return p.newConn(c, false)
+}
+
+func (p *ConnPool) newConn(c context.Context, pooled bool) (*Conn, error) {
+ cn, err := p.dialConn(c, pooled)
+ if err != nil {
+ return nil, err
+ }
+
+ p.connsMu.Lock()
+
+ p.conns = append(p.conns, cn)
+ if pooled {
+ // If pool is full remove the cn on next Put.
+ if p.poolSize >= p.opt.PoolSize {
+ cn.pooled = false
+ } else {
+ p.poolSize++
+ }
+ }
+
+ p.connsMu.Unlock()
+ return cn, nil
+}
+
+func (p *ConnPool) dialConn(c context.Context, pooled bool) (*Conn, error) {
+ if p.closed() {
+ return nil, ErrClosed
+ }
+
+ if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
+ return nil, p.getLastDialError()
+ }
+
+ netConn, err := p.opt.Dialer(c)
+ if err != nil {
+ p.setLastDialError(err)
+ if atomic.AddUint32(&p.dialErrorsNum, 1) == uint32(p.opt.PoolSize) {
+ go p.tryDial()
+ }
+ return nil, err
+ }
+
+ cn := NewConn(netConn)
+ cn.pooled = pooled
+ return cn, nil
+}
+
+func (p *ConnPool) tryDial() {
+ for {
+ if p.closed() {
+ return
+ }
+
+ conn, err := p.opt.Dialer(context.TODO())
+ if err != nil {
+ p.setLastDialError(err)
+ time.Sleep(time.Second)
+ continue
+ }
+
+ atomic.StoreUint32(&p.dialErrorsNum, 0)
+ _ = conn.Close()
+ return
+ }
+}
+
+func (p *ConnPool) setLastDialError(err error) {
+ p.lastDialErrorMu.Lock()
+ p.lastDialError = err
+ p.lastDialErrorMu.Unlock()
+}
+
+func (p *ConnPool) getLastDialError() error {
+ p.lastDialErrorMu.RLock()
+ err := p.lastDialError
+ p.lastDialErrorMu.RUnlock()
+ return err
+}
+
+// Get returns existed connection from the pool or creates a new one.
+func (p *ConnPool) Get(ctx context.Context) (*Conn, error) {
+ if p.closed() {
+ return nil, ErrClosed
+ }
+
+ err := p.waitTurn(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ for {
+ p.connsMu.Lock()
+ cn := p.popIdle()
+ p.connsMu.Unlock()
+
+ if cn == nil {
+ break
+ }
+
+ if p.isStaleConn(cn) {
+ _ = p.CloseConn(cn)
+ continue
+ }
+
+ atomic.AddUint32(&p.stats.Hits, 1)
+ return cn, nil
+ }
+
+ atomic.AddUint32(&p.stats.Misses, 1)
+
+ newcn, err := p.newConn(ctx, true)
+ if err != nil {
+ p.freeTurn()
+ return nil, err
+ }
+
+ return newcn, nil
+}
+
+func (p *ConnPool) getTurn() {
+ p.queue <- struct{}{}
+}
+
+func (p *ConnPool) waitTurn(c context.Context) error {
+ select {
+ case <-c.Done():
+ return c.Err()
+ default:
+ }
+
+ select {
+ case p.queue <- struct{}{}:
+ return nil
+ default:
+ }
+
+ timer := timers.Get().(*time.Timer)
+ timer.Reset(p.opt.PoolTimeout)
+
+ select {
+ case <-c.Done():
+ if !timer.Stop() {
+ <-timer.C
+ }
+ timers.Put(timer)
+ return c.Err()
+ case p.queue <- struct{}{}:
+ if !timer.Stop() {
+ <-timer.C
+ }
+ timers.Put(timer)
+ return nil
+ case <-timer.C:
+ timers.Put(timer)
+ atomic.AddUint32(&p.stats.Timeouts, 1)
+ return ErrPoolTimeout
+ }
+}
+
+func (p *ConnPool) freeTurn() {
+ <-p.queue
+}
+
+func (p *ConnPool) popIdle() *Conn {
+ if len(p.idleConns) == 0 {
+ return nil
+ }
+
+ idx := len(p.idleConns) - 1
+ cn := p.idleConns[idx]
+ p.idleConns = p.idleConns[:idx]
+ p.idleConnsLen--
+ p.checkMinIdleConns()
+ return cn
+}
+
+func (p *ConnPool) Put(ctx context.Context, cn *Conn) {
+ if !cn.pooled {
+ p.Remove(ctx, cn, nil)
+ return
+ }
+
+ p.connsMu.Lock()
+ p.idleConns = append(p.idleConns, cn)
+ p.idleConnsLen++
+ p.connsMu.Unlock()
+ p.freeTurn()
+}
+
+func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ p.removeConnWithLock(cn)
+ p.freeTurn()
+ _ = p.closeConn(cn)
+}
+
+func (p *ConnPool) CloseConn(cn *Conn) error {
+ p.removeConnWithLock(cn)
+ return p.closeConn(cn)
+}
+
+func (p *ConnPool) removeConnWithLock(cn *Conn) {
+ p.connsMu.Lock()
+ p.removeConn(cn)
+ p.connsMu.Unlock()
+}
+
+func (p *ConnPool) removeConn(cn *Conn) {
+ for i, c := range p.conns {
+ if c == cn {
+ p.conns = append(p.conns[:i], p.conns[i+1:]...)
+ if cn.pooled {
+ p.poolSize--
+ p.checkMinIdleConns()
+ }
+ return
+ }
+ }
+}
+
+func (p *ConnPool) closeConn(cn *Conn) error {
+ if p.opt.OnClose != nil {
+ _ = p.opt.OnClose(cn)
+ }
+ return cn.Close()
+}
+
+// Len returns total number of connections.
+func (p *ConnPool) Len() int {
+ p.connsMu.Lock()
+ n := len(p.conns)
+ p.connsMu.Unlock()
+ return n
+}
+
+// IdleLen returns number of idle connections.
+func (p *ConnPool) IdleLen() int {
+ p.connsMu.Lock()
+ n := p.idleConnsLen
+ p.connsMu.Unlock()
+ return n
+}
+
+func (p *ConnPool) Stats() *Stats {
+ idleLen := p.IdleLen()
+ return &Stats{
+ Hits: atomic.LoadUint32(&p.stats.Hits),
+ Misses: atomic.LoadUint32(&p.stats.Misses),
+ Timeouts: atomic.LoadUint32(&p.stats.Timeouts),
+
+ TotalConns: uint32(p.Len()),
+ IdleConns: uint32(idleLen),
+ StaleConns: atomic.LoadUint32(&p.stats.StaleConns),
+ }
+}
+
+func (p *ConnPool) closed() bool {
+ return atomic.LoadUint32(&p._closed) == 1
+}
+
+func (p *ConnPool) Filter(fn func(*Conn) bool) error {
+ var firstErr error
+ p.connsMu.Lock()
+ for _, cn := range p.conns {
+ if fn(cn) {
+ if err := p.closeConn(cn); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+ }
+ p.connsMu.Unlock()
+ return firstErr
+}
+
+func (p *ConnPool) Close() error {
+ if !atomic.CompareAndSwapUint32(&p._closed, 0, 1) {
+ return ErrClosed
+ }
+
+ var firstErr error
+ p.connsMu.Lock()
+ for _, cn := range p.conns {
+ if err := p.closeConn(cn); err != nil && firstErr == nil {
+ firstErr = err
+ }
+ }
+ p.conns = nil
+ p.poolSize = 0
+ p.idleConns = nil
+ p.idleConnsLen = 0
+ p.connsMu.Unlock()
+
+ return firstErr
+}
+
+func (p *ConnPool) reaper(frequency time.Duration) {
+ ticker := time.NewTicker(frequency)
+ defer ticker.Stop()
+
+ for range ticker.C {
+ if p.closed() {
+ break
+ }
+ n, err := p.ReapStaleConns()
+ if err != nil {
+ internal.Logger.Printf(context.TODO(), "ReapStaleConns failed: %s", err)
+ continue
+ }
+ atomic.AddUint32(&p.stats.StaleConns, uint32(n))
+ }
+}
+
+func (p *ConnPool) ReapStaleConns() (int, error) {
+ var n int
+ for {
+ p.getTurn()
+
+ p.connsMu.Lock()
+ cn := p.reapStaleConn()
+ p.connsMu.Unlock()
+
+ p.freeTurn()
+
+ if cn != nil {
+ _ = p.closeConn(cn)
+ n++
+ } else {
+ break
+ }
+ }
+ return n, nil
+}
+
+func (p *ConnPool) reapStaleConn() *Conn {
+ if len(p.idleConns) == 0 {
+ return nil
+ }
+
+ cn := p.idleConns[0]
+ if !p.isStaleConn(cn) {
+ return nil
+ }
+
+ p.idleConns = append(p.idleConns[:0], p.idleConns[1:]...)
+ p.idleConnsLen--
+ p.removeConn(cn)
+
+ return cn
+}
+
+func (p *ConnPool) isStaleConn(cn *Conn) bool {
+ if p.opt.IdleTimeout == 0 && p.opt.MaxConnAge == 0 {
+ return false
+ }
+
+ now := time.Now()
+ if p.opt.IdleTimeout > 0 && now.Sub(cn.UsedAt()) >= p.opt.IdleTimeout {
+ return true
+ }
+ if p.opt.MaxConnAge > 0 && now.Sub(cn.createdAt) >= p.opt.MaxConnAge {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go
new file mode 100644
index 000000000..5a3fde191
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_single.go
@@ -0,0 +1,58 @@
+package pool
+
+import "context"
+
+type SingleConnPool struct {
+ pool Pooler
+ cn *Conn
+ stickyErr error
+}
+
+var _ Pooler = (*SingleConnPool)(nil)
+
+func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool {
+ return &SingleConnPool{
+ pool: pool,
+ cn: cn,
+ }
+}
+
+func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) {
+ return p.pool.NewConn(ctx)
+}
+
+func (p *SingleConnPool) CloseConn(cn *Conn) error {
+ return p.pool.CloseConn(cn)
+}
+
+func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) {
+ if p.stickyErr != nil {
+ return nil, p.stickyErr
+ }
+ return p.cn, nil
+}
+
+func (p *SingleConnPool) Put(ctx context.Context, cn *Conn) {}
+
+func (p *SingleConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ p.cn = nil
+ p.stickyErr = reason
+}
+
+func (p *SingleConnPool) Close() error {
+ p.cn = nil
+ p.stickyErr = ErrClosed
+ return nil
+}
+
+func (p *SingleConnPool) Len() int {
+ return 0
+}
+
+func (p *SingleConnPool) IdleLen() int {
+ return 0
+}
+
+func (p *SingleConnPool) Stats() *Stats {
+ return &Stats{}
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go
new file mode 100644
index 000000000..0415b5e87
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/pool_sticky.go
@@ -0,0 +1,202 @@
+package pool
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "sync/atomic"
+)
+
+const (
+ stateDefault = 0
+ stateInited = 1
+ stateClosed = 2
+)
+
+type BadConnError struct {
+ wrapped error
+}
+
+var _ error = (*BadConnError)(nil)
+
+func (e BadConnError) Error() string {
+ s := "pg: Conn is in a bad state"
+ if e.wrapped != nil {
+ s += ": " + e.wrapped.Error()
+ }
+ return s
+}
+
+func (e BadConnError) Unwrap() error {
+ return e.wrapped
+}
+
+//------------------------------------------------------------------------------
+
+type StickyConnPool struct {
+ pool Pooler
+ shared int32 // atomic
+
+ state uint32 // atomic
+ ch chan *Conn
+
+ _badConnError atomic.Value
+}
+
+var _ Pooler = (*StickyConnPool)(nil)
+
+func NewStickyConnPool(pool Pooler) *StickyConnPool {
+ p, ok := pool.(*StickyConnPool)
+ if !ok {
+ p = &StickyConnPool{
+ pool: pool,
+ ch: make(chan *Conn, 1),
+ }
+ }
+ atomic.AddInt32(&p.shared, 1)
+ return p
+}
+
+func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) {
+ return p.pool.NewConn(ctx)
+}
+
+func (p *StickyConnPool) CloseConn(cn *Conn) error {
+ return p.pool.CloseConn(cn)
+}
+
+func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) {
+ // In worst case this races with Close which is not a very common operation.
+ for i := 0; i < 1000; i++ {
+ switch atomic.LoadUint32(&p.state) {
+ case stateDefault:
+ cn, err := p.pool.Get(ctx)
+ if err != nil {
+ return nil, err
+ }
+ if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) {
+ return cn, nil
+ }
+ p.pool.Remove(ctx, cn, ErrClosed)
+ case stateInited:
+ if err := p.badConnError(); err != nil {
+ return nil, err
+ }
+ cn, ok := <-p.ch
+ if !ok {
+ return nil, ErrClosed
+ }
+ return cn, nil
+ case stateClosed:
+ return nil, ErrClosed
+ default:
+ panic("not reached")
+ }
+ }
+ return nil, fmt.Errorf("pg: StickyConnPool.Get: infinite loop")
+}
+
+func (p *StickyConnPool) Put(ctx context.Context, cn *Conn) {
+ defer func() {
+ if recover() != nil {
+ p.freeConn(ctx, cn)
+ }
+ }()
+ p.ch <- cn
+}
+
+func (p *StickyConnPool) freeConn(ctx context.Context, cn *Conn) {
+ if err := p.badConnError(); err != nil {
+ p.pool.Remove(ctx, cn, err)
+ } else {
+ p.pool.Put(ctx, cn)
+ }
+}
+
+func (p *StickyConnPool) Remove(ctx context.Context, cn *Conn, reason error) {
+ defer func() {
+ if recover() != nil {
+ p.pool.Remove(ctx, cn, ErrClosed)
+ }
+ }()
+ p._badConnError.Store(BadConnError{wrapped: reason})
+ p.ch <- cn
+}
+
+func (p *StickyConnPool) Close() error {
+ if shared := atomic.AddInt32(&p.shared, -1); shared > 0 {
+ return nil
+ }
+
+ for i := 0; i < 1000; i++ {
+ state := atomic.LoadUint32(&p.state)
+ if state == stateClosed {
+ return ErrClosed
+ }
+ if atomic.CompareAndSwapUint32(&p.state, state, stateClosed) {
+ close(p.ch)
+ cn, ok := <-p.ch
+ if ok {
+ p.freeConn(context.TODO(), cn)
+ }
+ return nil
+ }
+ }
+
+ return errors.New("pg: StickyConnPool.Close: infinite loop")
+}
+
+func (p *StickyConnPool) Reset(ctx context.Context) error {
+ if p.badConnError() == nil {
+ return nil
+ }
+
+ select {
+ case cn, ok := <-p.ch:
+ if !ok {
+ return ErrClosed
+ }
+ p.pool.Remove(ctx, cn, ErrClosed)
+ p._badConnError.Store(BadConnError{wrapped: nil})
+ default:
+ return errors.New("pg: StickyConnPool does not have a Conn")
+ }
+
+ if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) {
+ state := atomic.LoadUint32(&p.state)
+ return fmt.Errorf("pg: invalid StickyConnPool state: %d", state)
+ }
+
+ return nil
+}
+
+func (p *StickyConnPool) badConnError() error {
+ if v := p._badConnError.Load(); v != nil {
+ err := v.(BadConnError)
+ if err.wrapped != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *StickyConnPool) Len() int {
+ switch atomic.LoadUint32(&p.state) {
+ case stateDefault:
+ return 0
+ case stateInited:
+ return 1
+ case stateClosed:
+ return 0
+ default:
+ panic("not reached")
+ }
+}
+
+func (p *StickyConnPool) IdleLen() int {
+ return len(p.ch)
+}
+
+func (p *StickyConnPool) Stats() *Stats {
+ return &Stats{}
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go
new file mode 100644
index 000000000..b5d00807d
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader.go
@@ -0,0 +1,80 @@
+package pool
+
+import (
+ "sync"
+)
+
+type Reader interface {
+ Buffered() int
+
+ Bytes() []byte
+ Read([]byte) (int, error)
+ ReadByte() (byte, error)
+ UnreadByte() error
+ ReadSlice(byte) ([]byte, error)
+ Discard(int) (int, error)
+
+ // ReadBytes(fn func(byte) bool) ([]byte, error)
+ // ReadN(int) ([]byte, error)
+ ReadFull() ([]byte, error)
+ ReadFullTemp() ([]byte, error)
+}
+
+type ColumnInfo struct {
+ Index int16
+ DataType int32
+ Name string
+}
+
+type ColumnAlloc struct {
+ columns []ColumnInfo
+}
+
+func NewColumnAlloc() *ColumnAlloc {
+ return new(ColumnAlloc)
+}
+
+func (c *ColumnAlloc) Reset() {
+ c.columns = c.columns[:0]
+}
+
+func (c *ColumnAlloc) New(index int16, name []byte) *ColumnInfo {
+ c.columns = append(c.columns, ColumnInfo{
+ Index: index,
+ Name: string(name),
+ })
+ return &c.columns[len(c.columns)-1]
+}
+
+func (c *ColumnAlloc) Columns() []ColumnInfo {
+ return c.columns
+}
+
+type ReaderContext struct {
+ *BufReader
+ ColumnAlloc *ColumnAlloc
+}
+
+func NewReaderContext() *ReaderContext {
+ const bufSize = 1 << 20 // 1mb
+ return &ReaderContext{
+ BufReader: NewBufReader(bufSize),
+ ColumnAlloc: NewColumnAlloc(),
+ }
+}
+
+var readerPool = sync.Pool{
+ New: func() interface{} {
+ return NewReaderContext()
+ },
+}
+
+func GetReaderContext() *ReaderContext {
+ rd := readerPool.Get().(*ReaderContext)
+ return rd
+}
+
+func PutReaderContext(rd *ReaderContext) {
+ rd.ColumnAlloc.Reset()
+ readerPool.Put(rd)
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go
new file mode 100644
index 000000000..3172e8b05
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_buf.go
@@ -0,0 +1,431 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pool
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+)
+
+type BufReader struct {
+ rd io.Reader // reader provided by the client
+
+ buf []byte
+ r, w int // buf read and write positions
+ lastByte int
+ bytesRead int64
+ err error
+
+ available int // bytes available for reading
+ brd BytesReader // reusable bytes reader
+}
+
+func NewBufReader(bufSize int) *BufReader {
+ return &BufReader{
+ buf: make([]byte, bufSize),
+ available: -1,
+ }
+}
+
+func (b *BufReader) BytesReader(n int) *BytesReader {
+ if n == -1 {
+ n = 0
+ }
+ buf := b.buf[b.r : b.r+n]
+ b.r += n
+ b.brd.Reset(buf)
+ return &b.brd
+}
+
+func (b *BufReader) SetAvailable(n int) {
+ b.available = n
+}
+
+func (b *BufReader) Available() int {
+ return b.available
+}
+
+func (b *BufReader) changeAvailable(n int) {
+ if b.available != -1 {
+ b.available += n
+ }
+}
+
+func (b *BufReader) Reset(rd io.Reader) {
+ b.rd = rd
+ b.r, b.w = 0, 0
+ b.err = nil
+}
+
+// Buffered returns the number of bytes that can be read from the current buffer.
+func (b *BufReader) Buffered() int {
+ buffered := b.w - b.r
+ if b.available == -1 || buffered <= b.available {
+ return buffered
+ }
+ return b.available
+}
+
+func (b *BufReader) Bytes() []byte {
+ if b.available == -1 {
+ return b.buf[b.r:b.w]
+ }
+ w := b.r + b.available
+ if w > b.w {
+ w = b.w
+ }
+ return b.buf[b.r:w]
+}
+
+func (b *BufReader) flush() []byte {
+ if b.available == -1 {
+ buf := b.buf[b.r:b.w]
+ b.r = b.w
+ return buf
+ }
+
+ w := b.r + b.available
+ if w > b.w {
+ w = b.w
+ }
+ buf := b.buf[b.r:w]
+ b.r = w
+ b.changeAvailable(-len(buf))
+ return buf
+}
+
+// fill reads a new chunk into the buffer.
+func (b *BufReader) fill() {
+ // Slide existing data to beginning.
+ if b.r > 0 {
+ copy(b.buf, b.buf[b.r:b.w])
+ b.w -= b.r
+ b.r = 0
+ }
+
+ if b.w >= len(b.buf) {
+ panic("bufio: tried to fill full buffer")
+ }
+ if b.available == 0 {
+ b.err = io.EOF
+ return
+ }
+
+ // Read new data: try a limited number of times.
+ const maxConsecutiveEmptyReads = 100
+ for i := maxConsecutiveEmptyReads; i > 0; i-- {
+ n, err := b.read(b.buf[b.w:])
+ b.w += n
+ if err != nil {
+ b.err = err
+ return
+ }
+ if n > 0 {
+ return
+ }
+ }
+ b.err = io.ErrNoProgress
+}
+
+func (b *BufReader) readErr() error {
+ err := b.err
+ b.err = nil
+ return err
+}
+
+func (b *BufReader) Read(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return 0, b.readErr()
+ }
+
+ if b.available != -1 {
+ if b.available == 0 {
+ return 0, io.EOF
+ }
+ if len(p) > b.available {
+ p = p[:b.available]
+ }
+ }
+
+ if b.r == b.w {
+ if b.err != nil {
+ return 0, b.readErr()
+ }
+
+ if len(p) >= len(b.buf) {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ n, err = b.read(p)
+ if n > 0 {
+ b.changeAvailable(-n)
+ b.lastByte = int(p[n-1])
+ }
+ return n, err
+ }
+
+ // One read.
+ // Do not use b.fill, which will loop.
+ b.r = 0
+ b.w = 0
+ n, b.err = b.read(b.buf)
+ if n == 0 {
+ return 0, b.readErr()
+ }
+ b.w += n
+ }
+
+ // copy as much as we can
+ n = copy(p, b.Bytes())
+ b.r += n
+ b.changeAvailable(-n)
+ b.lastByte = int(b.buf[b.r-1])
+ return n, nil
+}
+
+// ReadSlice reads until the first occurrence of delim in the input,
+// returning a slice pointing at the bytes in the buffer.
+// The bytes stop being valid at the next read.
+// If ReadSlice encounters an error before finding a delimiter,
+// it returns all the data in the buffer and the error itself (often io.EOF).
+// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
+// Because the data returned from ReadSlice will be overwritten
+// by the next I/O operation, most clients should use
+// ReadBytes or ReadString instead.
+// ReadSlice returns err != nil if and only if line does not end in delim.
+func (b *BufReader) ReadSlice(delim byte) (line []byte, err error) {
+ for {
+ // Search buffer.
+ if i := bytes.IndexByte(b.Bytes(), delim); i >= 0 {
+ i++
+ line = b.buf[b.r : b.r+i]
+ b.r += i
+ b.changeAvailable(-i)
+ break
+ }
+
+ // Pending error?
+ if b.err != nil {
+ line = b.flush()
+ err = b.readErr()
+ break
+ }
+
+ buffered := b.Buffered()
+
+ // Out of available.
+ if b.available != -1 && buffered >= b.available {
+ line = b.flush()
+ err = io.EOF
+ break
+ }
+
+ // Buffer full?
+ if buffered >= len(b.buf) {
+ line = b.flush()
+ err = bufio.ErrBufferFull
+ break
+ }
+
+ b.fill() // buffer is not full
+ }
+
+ // Handle last byte, if any.
+ if i := len(line) - 1; i >= 0 {
+ b.lastByte = int(line[i])
+ }
+
+ return line, err
+}
+
+func (b *BufReader) ReadBytes(fn func(byte) bool) (line []byte, err error) {
+ for {
+ for i, c := range b.Bytes() {
+ if !fn(c) {
+ i--
+ line = b.buf[b.r : b.r+i] //nolint
+ b.r += i
+ b.changeAvailable(-i)
+ break
+ }
+ }
+
+ // Pending error?
+ if b.err != nil {
+ line = b.flush()
+ err = b.readErr()
+ break
+ }
+
+ buffered := b.Buffered()
+
+ // Out of available.
+ if b.available != -1 && buffered >= b.available {
+ line = b.flush()
+ err = io.EOF
+ break
+ }
+
+ // Buffer full?
+ if buffered >= len(b.buf) {
+ line = b.flush()
+ err = bufio.ErrBufferFull
+ break
+ }
+
+ b.fill() // buffer is not full
+ }
+
+ // Handle last byte, if any.
+ if i := len(line) - 1; i >= 0 {
+ b.lastByte = int(line[i])
+ }
+
+ return line, err
+}
+
+func (b *BufReader) ReadByte() (byte, error) {
+ if b.available == 0 {
+ return 0, io.EOF
+ }
+ for b.r == b.w {
+ if b.err != nil {
+ return 0, b.readErr()
+ }
+ b.fill() // buffer is empty
+ }
+ c := b.buf[b.r]
+ b.r++
+ b.lastByte = int(c)
+ b.changeAvailable(-1)
+ return c, nil
+}
+
+func (b *BufReader) UnreadByte() error {
+ if b.lastByte < 0 || b.r == 0 && b.w > 0 {
+ return bufio.ErrInvalidUnreadByte
+ }
+ // b.r > 0 || b.w == 0
+ if b.r > 0 {
+ b.r--
+ } else {
+ // b.r == 0 && b.w == 0
+ b.w = 1
+ }
+ b.buf[b.r] = byte(b.lastByte)
+ b.lastByte = -1
+ b.changeAvailable(+1)
+ return nil
+}
+
+// Discard skips the next n bytes, returning the number of bytes discarded.
+//
+// If Discard skips fewer than n bytes, it also returns an error.
+// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without
+// reading from the underlying io.BufReader.
+func (b *BufReader) Discard(n int) (discarded int, err error) {
+ if n < 0 {
+ return 0, bufio.ErrNegativeCount
+ }
+ if n == 0 {
+ return
+ }
+ remain := n
+ for {
+ skip := b.Buffered()
+ if skip == 0 {
+ b.fill()
+ skip = b.Buffered()
+ }
+ if skip > remain {
+ skip = remain
+ }
+ b.r += skip
+ b.changeAvailable(-skip)
+ remain -= skip
+ if remain == 0 {
+ return n, nil
+ }
+ if b.err != nil {
+ return n - remain, b.readErr()
+ }
+ }
+}
+
+func (b *BufReader) ReadN(n int) (line []byte, err error) {
+ if n < 0 {
+ return nil, bufio.ErrNegativeCount
+ }
+ if n == 0 {
+ return
+ }
+
+ nn := n
+ if b.available != -1 && nn > b.available {
+ nn = b.available
+ }
+
+ for {
+ buffered := b.Buffered()
+
+ if buffered >= nn {
+ line = b.buf[b.r : b.r+nn]
+ b.r += nn
+ b.changeAvailable(-nn)
+ if n > nn {
+ err = io.EOF
+ }
+ break
+ }
+
+ // Pending error?
+ if b.err != nil {
+ line = b.flush()
+ err = b.readErr()
+ break
+ }
+
+ // Buffer full?
+ if buffered >= len(b.buf) {
+ line = b.flush()
+ err = bufio.ErrBufferFull
+ break
+ }
+
+ b.fill() // buffer is not full
+ }
+
+ // Handle last byte, if any.
+ if i := len(line) - 1; i >= 0 {
+ b.lastByte = int(line[i])
+ }
+
+ return line, err
+}
+
+func (b *BufReader) ReadFull() ([]byte, error) {
+ if b.available == -1 {
+ panic("not reached")
+ }
+ buf := make([]byte, b.available)
+ _, err := io.ReadFull(b, buf)
+ return buf, err
+}
+
+func (b *BufReader) ReadFullTemp() ([]byte, error) {
+ if b.available == -1 {
+ panic("not reached")
+ }
+ if b.available <= len(b.buf) {
+ return b.ReadN(b.available)
+ }
+ return b.ReadFull()
+}
+
+func (b *BufReader) read(buf []byte) (int, error) {
+ n, err := b.rd.Read(buf)
+ b.bytesRead += int64(n)
+ return n, err
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go
new file mode 100644
index 000000000..93646b1da
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/reader_bytes.go
@@ -0,0 +1,121 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pool
+
+import (
+ "bytes"
+ "errors"
+ "io"
+)
+
+type BytesReader struct {
+ s []byte
+ i int
+}
+
+func NewBytesReader(b []byte) *BytesReader {
+ return &BytesReader{
+ s: b,
+ }
+}
+
+func (r *BytesReader) Reset(b []byte) {
+ r.s = b
+ r.i = 0
+}
+
+func (r *BytesReader) Buffered() int {
+ return len(r.s) - r.i
+}
+
+func (r *BytesReader) Bytes() []byte {
+ return r.s[r.i:]
+}
+
+func (r *BytesReader) Read(b []byte) (n int, err error) {
+ if r.i >= len(r.s) {
+ return 0, io.EOF
+ }
+ n = copy(b, r.s[r.i:])
+ r.i += n
+ return
+}
+
+func (r *BytesReader) ReadByte() (byte, error) {
+ if r.i >= len(r.s) {
+ return 0, io.EOF
+ }
+ b := r.s[r.i]
+ r.i++
+ return b, nil
+}
+
+func (r *BytesReader) UnreadByte() error {
+ if r.i <= 0 {
+ return errors.New("UnreadByte: at beginning of slice")
+ }
+ r.i--
+ return nil
+}
+
+func (r *BytesReader) ReadSlice(delim byte) ([]byte, error) {
+ if i := bytes.IndexByte(r.s[r.i:], delim); i >= 0 {
+ i++
+ line := r.s[r.i : r.i+i]
+ r.i += i
+ return line, nil
+ }
+
+ line := r.s[r.i:]
+ r.i = len(r.s)
+ return line, io.EOF
+}
+
+func (r *BytesReader) ReadBytes(fn func(byte) bool) ([]byte, error) {
+ for i, c := range r.s[r.i:] {
+ if !fn(c) {
+ i++
+ line := r.s[r.i : r.i+i]
+ r.i += i
+ return line, nil
+ }
+ }
+
+ line := r.s[r.i:]
+ r.i = len(r.s)
+ return line, io.EOF
+}
+
+func (r *BytesReader) Discard(n int) (int, error) {
+ b, err := r.ReadN(n)
+ return len(b), err
+}
+
+func (r *BytesReader) ReadN(n int) ([]byte, error) {
+ nn := n
+ if nn > len(r.s) {
+ nn = len(r.s)
+ }
+
+ b := r.s[r.i : r.i+nn]
+ r.i += nn
+ if n > nn {
+ return b, io.EOF
+ }
+ return b, nil
+}
+
+func (r *BytesReader) ReadFull() ([]byte, error) {
+ b := make([]byte, len(r.s)-r.i)
+ copy(b, r.s[r.i:])
+ r.i = len(r.s)
+ return b, nil
+}
+
+func (r *BytesReader) ReadFullTemp() ([]byte, error) {
+ b := r.s[r.i:]
+ r.i = len(r.s)
+ return b, nil
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go b/vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go
new file mode 100644
index 000000000..6981d3f4c
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/pool/write_buffer.go
@@ -0,0 +1,114 @@
+package pool
+
+import (
+ "encoding/binary"
+ "io"
+ "sync"
+)
+
+const defaultBufSize = 65 << 10 // 65kb
+
+var wbPool = sync.Pool{
+ New: func() interface{} {
+ return NewWriteBuffer()
+ },
+}
+
+func GetWriteBuffer() *WriteBuffer {
+ wb := wbPool.Get().(*WriteBuffer)
+ return wb
+}
+
+func PutWriteBuffer(wb *WriteBuffer) {
+ wb.Reset()
+ wbPool.Put(wb)
+}
+
+type WriteBuffer struct {
+ Bytes []byte
+
+ msgStart int
+ paramStart int
+}
+
+func NewWriteBuffer() *WriteBuffer {
+ return &WriteBuffer{
+ Bytes: make([]byte, 0, defaultBufSize),
+ }
+}
+
+func (buf *WriteBuffer) Reset() {
+ buf.Bytes = buf.Bytes[:0]
+}
+
+func (buf *WriteBuffer) StartMessage(c byte) {
+ if c == 0 {
+ buf.msgStart = len(buf.Bytes)
+ buf.Bytes = append(buf.Bytes, 0, 0, 0, 0)
+ } else {
+ buf.msgStart = len(buf.Bytes) + 1
+ buf.Bytes = append(buf.Bytes, c, 0, 0, 0, 0)
+ }
+}
+
+func (buf *WriteBuffer) FinishMessage() {
+ binary.BigEndian.PutUint32(
+ buf.Bytes[buf.msgStart:], uint32(len(buf.Bytes)-buf.msgStart))
+}
+
+func (buf *WriteBuffer) Query() []byte {
+ return buf.Bytes[buf.msgStart+4 : len(buf.Bytes)-1]
+}
+
+func (buf *WriteBuffer) StartParam() {
+ buf.paramStart = len(buf.Bytes)
+ buf.Bytes = append(buf.Bytes, 0, 0, 0, 0)
+}
+
+func (buf *WriteBuffer) FinishParam() {
+ binary.BigEndian.PutUint32(
+ buf.Bytes[buf.paramStart:], uint32(len(buf.Bytes)-buf.paramStart-4))
+}
+
+var nullParamLength = int32(-1)
+
+func (buf *WriteBuffer) FinishNullParam() {
+ binary.BigEndian.PutUint32(
+ buf.Bytes[buf.paramStart:], uint32(nullParamLength))
+}
+
+func (buf *WriteBuffer) Write(b []byte) (int, error) {
+ buf.Bytes = append(buf.Bytes, b...)
+ return len(b), nil
+}
+
+func (buf *WriteBuffer) WriteInt16(num int16) {
+ buf.Bytes = append(buf.Bytes, 0, 0)
+ binary.BigEndian.PutUint16(buf.Bytes[len(buf.Bytes)-2:], uint16(num))
+}
+
+func (buf *WriteBuffer) WriteInt32(num int32) {
+ buf.Bytes = append(buf.Bytes, 0, 0, 0, 0)
+ binary.BigEndian.PutUint32(buf.Bytes[len(buf.Bytes)-4:], uint32(num))
+}
+
+func (buf *WriteBuffer) WriteString(s string) {
+ buf.Bytes = append(buf.Bytes, s...)
+ buf.Bytes = append(buf.Bytes, 0)
+}
+
+func (buf *WriteBuffer) WriteBytes(b []byte) {
+ buf.Bytes = append(buf.Bytes, b...)
+ buf.Bytes = append(buf.Bytes, 0)
+}
+
+func (buf *WriteBuffer) WriteByte(c byte) error {
+ buf.Bytes = append(buf.Bytes, c)
+ return nil
+}
+
+func (buf *WriteBuffer) ReadFrom(r io.Reader) (int64, error) {
+ n, err := r.Read(buf.Bytes[len(buf.Bytes):cap(buf.Bytes)])
+ buf.Bytes = buf.Bytes[:len(buf.Bytes)+n]
+ return int64(n), err
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/safe.go b/vendor/github.com/go-pg/pg/v10/internal/safe.go
new file mode 100644
index 000000000..870fe541f
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/safe.go
@@ -0,0 +1,11 @@
+// +build appengine
+
+package internal
+
+func BytesToString(b []byte) string {
+ return string(b)
+}
+
+func StringToBytes(s string) []byte {
+ return []byte(s)
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/strconv.go b/vendor/github.com/go-pg/pg/v10/internal/strconv.go
new file mode 100644
index 000000000..9e42ffb03
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/strconv.go
@@ -0,0 +1,19 @@
+package internal
+
+import "strconv"
+
+func Atoi(b []byte) (int, error) {
+ return strconv.Atoi(BytesToString(b))
+}
+
+func ParseInt(b []byte, base int, bitSize int) (int64, error) {
+ return strconv.ParseInt(BytesToString(b), base, bitSize)
+}
+
+func ParseUint(b []byte, base int, bitSize int) (uint64, error) {
+ return strconv.ParseUint(BytesToString(b), base, bitSize)
+}
+
+func ParseFloat(b []byte, bitSize int) (float64, error) {
+ return strconv.ParseFloat(BytesToString(b), bitSize)
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/underscore.go b/vendor/github.com/go-pg/pg/v10/internal/underscore.go
new file mode 100644
index 000000000..e71c11705
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/underscore.go
@@ -0,0 +1,93 @@
+package internal
+
+func IsUpper(c byte) bool {
+ return c >= 'A' && c <= 'Z'
+}
+
+func IsLower(c byte) bool {
+ return c >= 'a' && c <= 'z'
+}
+
+func ToUpper(c byte) byte {
+ return c - 32
+}
+
+func ToLower(c byte) byte {
+ return c + 32
+}
+
+// Underscore converts "CamelCasedString" to "camel_cased_string".
+func Underscore(s string) string {
+ r := make([]byte, 0, len(s)+5)
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if IsUpper(c) {
+ if i > 0 && i+1 < len(s) && (IsLower(s[i-1]) || IsLower(s[i+1])) {
+ r = append(r, '_', ToLower(c))
+ } else {
+ r = append(r, ToLower(c))
+ }
+ } else {
+ r = append(r, c)
+ }
+ }
+ return string(r)
+}
+
+func CamelCased(s string) string {
+ r := make([]byte, 0, len(s))
+ upperNext := true
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if c == '_' {
+ upperNext = true
+ continue
+ }
+ if upperNext {
+ if IsLower(c) {
+ c = ToUpper(c)
+ }
+ upperNext = false
+ }
+ r = append(r, c)
+ }
+ return string(r)
+}
+
+func ToExported(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+ if c := s[0]; IsLower(c) {
+ b := []byte(s)
+ b[0] = ToUpper(c)
+ return string(b)
+ }
+ return s
+}
+
+func UpperString(s string) string {
+ if isUpperString(s) {
+ return s
+ }
+
+ b := make([]byte, len(s))
+ for i := range b {
+ c := s[i]
+ if IsLower(c) {
+ c = ToUpper(c)
+ }
+ b[i] = c
+ }
+ return string(b)
+}
+
+func isUpperString(s string) bool {
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if IsLower(c) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/unsafe.go b/vendor/github.com/go-pg/pg/v10/internal/unsafe.go
new file mode 100644
index 000000000..f8bc18d91
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/unsafe.go
@@ -0,0 +1,22 @@
+// +build !appengine
+
+package internal
+
+import (
+ "unsafe"
+)
+
+// BytesToString converts byte slice to string.
+func BytesToString(b []byte) string {
+ return *(*string)(unsafe.Pointer(&b))
+}
+
+// StringToBytes converts string to byte slice.
+func StringToBytes(s string) []byte {
+ return *(*[]byte)(unsafe.Pointer(
+ &struct {
+ string
+ Cap int
+ }{s, len(s)},
+ ))
+}
diff --git a/vendor/github.com/go-pg/pg/v10/internal/util.go b/vendor/github.com/go-pg/pg/v10/internal/util.go
new file mode 100644
index 000000000..80ad1dd9a
--- /dev/null
+++ b/vendor/github.com/go-pg/pg/v10/internal/util.go
@@ -0,0 +1,71 @@
+package internal
+
+import (
+ "context"
+ "reflect"
+ "time"
+)
+
+func Sleep(ctx context.Context, dur time.Duration) error {
+ t := time.NewTimer(dur)
+ defer t.Stop()
+
+ select {
+ case <-t.C:
+ return nil
+ case <-ctx.Done():
+ return ctx.Err()
+ }
+}
+
+func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
+ if v.Kind() == reflect.Array {
+ var pos int
+ return func() reflect.Value {
+ v := v.Index(pos)
+ pos++
+ return v
+ }
+ }
+
+ elemType := v.Type().Elem()
+
+ if elemType.Kind() == reflect.Ptr {
+ elemType = elemType.Elem()
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ elem := v.Index(v.Len() - 1)
+ if elem.IsNil() {
+ elem.Set(reflect.New(elemType))
+ }
+ return elem.Elem()
+ }
+
+ elem := reflect.New(elemType)
+ v.Set(reflect.Append(v, elem))
+ return elem.Elem()
+ }
+ }
+
+ zero := reflect.Zero(elemType)
+ return func() reflect.Value {
+ if v.Len() < v.Cap() {
+ v.Set(v.Slice(0, v.Len()+1))
+ return v.Index(v.Len() - 1)
+ }
+
+ v.Set(reflect.Append(v, zero))
+ return v.Index(v.Len() - 1)
+ }
+}
+
+func Unwrap(err error) error {
+ u, ok := err.(interface {
+ Unwrap() error
+ })
+ if !ok {
+ return nil
+ }
+ return u.Unwrap()
+}