]> source.dussan.org Git - gitea.git/commitdiff
Update vendor github.com/lib/pq (#2752)
authorAntoine GIRARD <sapk@users.noreply.github.com>
Sat, 21 Oct 2017 04:05:58 +0000 (06:05 +0200)
committerLunny Xiao <xiaolunwen@gmail.com>
Sat, 21 Oct 2017 04:05:58 +0000 (12:05 +0800)
17 files changed:
vendor/github.com/lib/pq/README.md
vendor/github.com/lib/pq/array.go
vendor/github.com/lib/pq/conn.go
vendor/github.com/lib/pq/conn_go18.go [new file with mode: 0644]
vendor/github.com/lib/pq/copy.go
vendor/github.com/lib/pq/encode.go
vendor/github.com/lib/pq/notify.go
vendor/github.com/lib/pq/oid/gen.go [deleted file]
vendor/github.com/lib/pq/oid/types.go
vendor/github.com/lib/pq/rows.go [new file with mode: 0644]
vendor/github.com/lib/pq/ssl.go [new file with mode: 0644]
vendor/github.com/lib/pq/ssl_go1.7.go [new file with mode: 0644]
vendor/github.com/lib/pq/ssl_permissions.go [new file with mode: 0644]
vendor/github.com/lib/pq/ssl_renegotiation.go [new file with mode: 0644]
vendor/github.com/lib/pq/ssl_windows.go [new file with mode: 0644]
vendor/github.com/lib/pq/uuid.go [new file with mode: 0644]
vendor/vendor.json

index 5eb9e144504b852998bcd41d36fac29c5fc0e03f..7670fc87a51eeddba3c219a67939bc902adf0c9a 100644 (file)
@@ -1,6 +1,6 @@
 # pq - A pure Go postgres driver for Go's database/sql package
 
-[![Build Status](https://travis-ci.org/lib/pq.png?branch=master)](https://travis-ci.org/lib/pq)
+[![Build Status](https://travis-ci.org/lib/pq.svg?branch=master)](https://travis-ci.org/lib/pq)
 
 ## Install
 
index 27eb07a9e17e4639bc1f35ea2b5b3b61f652cbe2..e4933e227649ace41604c1b2051e7569f6ad8785 100644 (file)
@@ -13,7 +13,7 @@ import (
 
 var typeByteSlice = reflect.TypeOf([]byte{})
 var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
-var typeSqlScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
+var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
 
 // Array returns the optimal driver.Valuer and sql.Scanner for an array or
 // slice of any dimension.
@@ -70,6 +70,9 @@ func (a *BoolArray) Scan(src interface{}) error {
                return a.scanBytes(src)
        case string:
                return a.scanBytes([]byte(src))
+       case nil:
+               *a = nil
+               return nil
        }
 
        return fmt.Errorf("pq: cannot convert %T to BoolArray", src)
@@ -80,7 +83,7 @@ func (a *BoolArray) scanBytes(src []byte) error {
        if err != nil {
                return err
        }
-       if len(elems) == 0 {
+       if *a != nil && len(elems) == 0 {
                *a = (*a)[:0]
        } else {
                b := make(BoolArray, len(elems))
@@ -141,6 +144,9 @@ func (a *ByteaArray) Scan(src interface{}) error {
                return a.scanBytes(src)
        case string:
                return a.scanBytes([]byte(src))
+       case nil:
+               *a = nil
+               return nil
        }
 
        return fmt.Errorf("pq: cannot convert %T to ByteaArray", src)
@@ -151,7 +157,7 @@ func (a *ByteaArray) scanBytes(src []byte) error {
        if err != nil {
                return err
        }
-       if len(elems) == 0 {
+       if *a != nil && len(elems) == 0 {
                *a = (*a)[:0]
        } else {
                b := make(ByteaArray, len(elems))
@@ -210,6 +216,9 @@ func (a *Float64Array) Scan(src interface{}) error {
                return a.scanBytes(src)
        case string:
                return a.scanBytes([]byte(src))
+       case nil:
+               *a = nil
+               return nil
        }
 
        return fmt.Errorf("pq: cannot convert %T to Float64Array", src)
@@ -220,7 +229,7 @@ func (a *Float64Array) scanBytes(src []byte) error {
        if err != nil {
                return err
        }
-       if len(elems) == 0 {
+       if *a != nil && len(elems) == 0 {
                *a = (*a)[:0]
        } else {
                b := make(Float64Array, len(elems))
@@ -269,7 +278,7 @@ func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]b
        // TODO calculate the assign function for other types
        // TODO repeat this section on the element type of arrays or slices (multidimensional)
        {
-               if reflect.PtrTo(rt).Implements(typeSqlScanner) {
+               if reflect.PtrTo(rt).Implements(typeSQLScanner) {
                        // dest is always addressable because it is an element of a slice.
                        assign = func(src []byte, dest reflect.Value) (err error) {
                                ss := dest.Addr().Interface().(sql.Scanner)
@@ -320,6 +329,11 @@ func (a GenericArray) Scan(src interface{}) error {
                return a.scanBytes(src, dv)
        case string:
                return a.scanBytes([]byte(src), dv)
+       case nil:
+               if dv.Kind() == reflect.Slice {
+                       dv.Set(reflect.Zero(dv.Type()))
+                       return nil
+               }
        }
 
        return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type())
@@ -386,7 +400,13 @@ func (a GenericArray) Value() (driver.Value, error) {
 
        rv := reflect.ValueOf(a.A)
 
-       if k := rv.Kind(); k != reflect.Array && k != reflect.Slice {
+       switch rv.Kind() {
+       case reflect.Slice:
+               if rv.IsNil() {
+                       return nil, nil
+               }
+       case reflect.Array:
+       default:
                return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A)
        }
 
@@ -412,6 +432,9 @@ func (a *Int64Array) Scan(src interface{}) error {
                return a.scanBytes(src)
        case string:
                return a.scanBytes([]byte(src))
+       case nil:
+               *a = nil
+               return nil
        }
 
        return fmt.Errorf("pq: cannot convert %T to Int64Array", src)
@@ -422,7 +445,7 @@ func (a *Int64Array) scanBytes(src []byte) error {
        if err != nil {
                return err
        }
-       if len(elems) == 0 {
+       if *a != nil && len(elems) == 0 {
                *a = (*a)[:0]
        } else {
                b := make(Int64Array, len(elems))
@@ -470,6 +493,9 @@ func (a *StringArray) Scan(src interface{}) error {
                return a.scanBytes(src)
        case string:
                return a.scanBytes([]byte(src))
+       case nil:
+               *a = nil
+               return nil
        }
 
        return fmt.Errorf("pq: cannot convert %T to StringArray", src)
@@ -480,7 +506,7 @@ func (a *StringArray) scanBytes(src []byte) error {
        if err != nil {
                return err
        }
-       if len(elems) == 0 {
+       if *a != nil && len(elems) == 0 {
                *a = (*a)[:0]
        } else {
                b := make(StringArray, len(elems))
@@ -561,7 +587,7 @@ func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) {
                }
        }
 
-       var del string = ","
+       var del = ","
        var err error
        var iv interface{} = rv.Interface()
 
@@ -639,6 +665,9 @@ Element:
        for i < len(src) {
                switch src[i] {
                case '{':
+                       if depth == len(dims) {
+                               break Element
+                       }
                        depth++
                        dims[depth-1] = 0
                        i++
@@ -680,11 +709,11 @@ Element:
        }
 
        for i < len(src) {
-               if bytes.HasPrefix(src[i:], del) {
+               if bytes.HasPrefix(src[i:], del) && depth > 0 {
                        dims[depth-1]++
                        i += len(del)
                        goto Element
-               } else if src[i] == '}' {
+               } else if src[i] == '}' && depth > 0 {
                        dims[depth-1]++
                        depth--
                        i++
index ca88dc8c6718ca7eab7b4e3289f9e7f2c8287933..df6b565f7338d112b96c9db63d7033dffc9cff5f 100644 (file)
@@ -3,15 +3,12 @@ package pq
 import (
        "bufio"
        "crypto/md5"
-       "crypto/tls"
-       "crypto/x509"
        "database/sql"
        "database/sql/driver"
        "encoding/binary"
        "errors"
        "fmt"
        "io"
-       "io/ioutil"
        "net"
        "os"
        "os/user"
@@ -30,22 +27,22 @@ var (
        ErrNotSupported              = errors.New("pq: Unsupported command")
        ErrInFailedTransaction       = errors.New("pq: Could not complete operation in a failed transaction")
        ErrSSLNotSupported           = errors.New("pq: SSL is not enabled on the server")
-       ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less.")
-       ErrCouldNotDetectUsername    = errors.New("pq: Could not detect default username. Please provide one explicitly.")
+       ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less")
+       ErrCouldNotDetectUsername    = errors.New("pq: Could not detect default username. Please provide one explicitly")
 
        errUnexpectedReady = errors.New("unexpected ReadyForQuery")
        errNoRowsAffected  = errors.New("no RowsAffected available after the empty statement")
-       errNoLastInsertId  = errors.New("no LastInsertId available after the empty statement")
+       errNoLastInsertID  = errors.New("no LastInsertId available after the empty statement")
 )
 
-type drv struct{}
+type Driver struct{}
 
-func (d *drv) Open(name string) (driver.Conn, error) {
+func (d *Driver) Open(name string) (driver.Conn, error) {
        return Open(name)
 }
 
 func init() {
-       sql.Register("postgres", &drv{})
+       sql.Register("postgres", &Driver{})
 }
 
 type parameterStatus struct {
@@ -101,6 +98,15 @@ type conn struct {
        namei     int
        scratch   [512]byte
        txnStatus transactionStatus
+       txnFinish func()
+
+       // Save connection arguments to use during CancelRequest.
+       dialer Dialer
+       opts   values
+
+       // Cancellation key data for use with CancelRequest messages.
+       processID int
+       secretKey int
 
        parameterStatus parameterStatus
 
@@ -125,9 +131,9 @@ type conn struct {
 }
 
 // Handle driver-side settings in parsed connection string.
-func (c *conn) handleDriverSettings(o values) (err error) {
+func (cn *conn) handleDriverSettings(o values) (err error) {
        boolSetting := func(key string, val *bool) error {
-               if value := o.Get(key); value != "" {
+               if value, ok := o[key]; ok {
                        if value == "yes" {
                                *val = true
                        } else if value == "no" {
@@ -139,32 +145,32 @@ func (c *conn) handleDriverSettings(o values) (err error) {
                return nil
        }
 
-       err = boolSetting("disable_prepared_binary_result", &c.disablePreparedBinaryResult)
+       err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult)
        if err != nil {
                return err
        }
-       err = boolSetting("binary_parameters", &c.binaryParameters)
-       if err != nil {
-               return err
-       }
-       return nil
+       return boolSetting("binary_parameters", &cn.binaryParameters)
 }
 
-func (c *conn) handlePgpass(o values) {
+func (cn *conn) handlePgpass(o values) {
        // if a password was supplied, do not process .pgpass
-       _, ok := o["password"]
-       if ok {
+       if _, ok := o["password"]; ok {
                return
        }
        filename := os.Getenv("PGPASSFILE")
        if filename == "" {
                // XXX this code doesn't work on Windows where the default filename is
                // XXX %APPDATA%\postgresql\pgpass.conf
-               user, err := user.Current()
-               if err != nil {
-                       return
+               // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
+               userHome := os.Getenv("HOME")
+               if userHome == "" {
+                       user, err := user.Current()
+                       if err != nil {
+                               return
+                       }
+                       userHome = user.HomeDir
                }
-               filename = filepath.Join(user.HomeDir, ".pgpass")
+               filename = filepath.Join(userHome, ".pgpass")
        }
        fileinfo, err := os.Stat(filename)
        if err != nil {
@@ -181,11 +187,11 @@ func (c *conn) handlePgpass(o values) {
        }
        defer file.Close()
        scanner := bufio.NewScanner(io.Reader(file))
-       hostname := o.Get("host")
+       hostname := o["host"]
        ntw, _ := network(o)
-       port := o.Get("port")
-       db := o.Get("dbname")
-       username := o.Get("user")
+       port := o["port"]
+       db := o["dbname"]
+       username := o["user"]
        // From: https://github.com/tg/pgpass/blob/master/reader.go
        getFields := func(s string) []string {
                fs := make([]string, 0, 5)
@@ -224,10 +230,10 @@ func (c *conn) handlePgpass(o values) {
        }
 }
 
-func (c *conn) writeBuf(b byte) *writeBuf {
-       c.scratch[0] = b
+func (cn *conn) writeBuf(b byte) *writeBuf {
+       cn.scratch[0] = b
        return &writeBuf{
-               buf: c.scratch[:5],
+               buf: cn.scratch[:5],
                pos: 1,
        }
 }
@@ -250,13 +256,13 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
        // * Very low precedence defaults applied in every situation
        // * Environment variables
        // * Explicitly passed connection information
-       o.Set("host", "localhost")
-       o.Set("port", "5432")
+       o["host"] = "localhost"
+       o["port"] = "5432"
        // N.B.: Extra float digits should be set to 3, but that breaks
        // Postgres 8.4 and older, where the max is 2.
-       o.Set("extra_float_digits", "2")
+       o["extra_float_digits"] = "2"
        for k, v := range parseEnviron(os.Environ()) {
-               o.Set(k, v)
+               o[k] = v
        }
 
        if strings.HasPrefix(name, "postgres://") || strings.HasPrefix(name, "postgresql://") {
@@ -271,9 +277,9 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
        }
 
        // Use the "fallback" application name if necessary
-       if fallback := o.Get("fallback_application_name"); fallback != "" {
-               if !o.Isset("application_name") {
-                       o.Set("application_name", fallback)
+       if fallback, ok := o["fallback_application_name"]; ok {
+               if _, ok := o["application_name"]; !ok {
+                       o["application_name"] = fallback
                }
        }
 
@@ -284,33 +290,35 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
        // parsing its value is not worth it.  Instead, we always explicitly send
        // client_encoding as a separate run-time parameter, which should override
        // anything set in options.
-       if enc := o.Get("client_encoding"); enc != "" && !isUTF8(enc) {
+       if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
                return nil, errors.New("client_encoding must be absent or 'UTF8'")
        }
-       o.Set("client_encoding", "UTF8")
+       o["client_encoding"] = "UTF8"
        // DateStyle needs a similar treatment.
-       if datestyle := o.Get("datestyle"); datestyle != "" {
+       if datestyle, ok := o["datestyle"]; ok {
                if datestyle != "ISO, MDY" {
                        panic(fmt.Sprintf("setting datestyle must be absent or %v; got %v",
                                "ISO, MDY", datestyle))
                }
        } else {
-               o.Set("datestyle", "ISO, MDY")
+               o["datestyle"] = "ISO, MDY"
        }
 
        // If a user is not provided by any other means, the last
        // resort is to use the current operating system provided user
        // name.
-       if o.Get("user") == "" {
+       if _, ok := o["user"]; !ok {
                u, err := userCurrent()
                if err != nil {
                        return nil, err
-               } else {
-                       o.Set("user", u)
                }
+               o["user"] = u
        }
 
-       cn := &conn{}
+       cn := &conn{
+               opts:   o,
+               dialer: d,
+       }
        err = cn.handleDriverSettings(o)
        if err != nil {
                return nil, err
@@ -326,7 +334,7 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
        cn.startup(o)
 
        // reset the deadline, in case one was set (see dial)
-       if timeout := o.Get("connect_timeout"); timeout != "" && timeout != "0" {
+       if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
                err = cn.c.SetDeadline(time.Time{})
        }
        return cn, err
@@ -340,7 +348,7 @@ func dial(d Dialer, o values) (net.Conn, error) {
        }
 
        // Zero or not specified means wait indefinitely.
-       if timeout := o.Get("connect_timeout"); timeout != "" && timeout != "0" {
+       if timeout, ok := o["connect_timeout"]; ok && timeout != "0" {
                seconds, err := strconv.ParseInt(timeout, 10, 0)
                if err != nil {
                        return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
@@ -362,31 +370,18 @@ func dial(d Dialer, o values) (net.Conn, error) {
 }
 
 func network(o values) (string, string) {
-       host := o.Get("host")
+       host := o["host"]
 
        if strings.HasPrefix(host, "/") {
-               sockPath := path.Join(host, ".s.PGSQL."+o.Get("port"))
+               sockPath := path.Join(host, ".s.PGSQL."+o["port"])
                return "unix", sockPath
        }
 
-       return "tcp", net.JoinHostPort(host, o.Get("port"))
+       return "tcp", net.JoinHostPort(host, o["port"])
 }
 
 type values map[string]string
 
-func (vs values) Set(k, v string) {
-       vs[k] = v
-}
-
-func (vs values) Get(k string) (v string) {
-       return vs[k]
-}
-
-func (vs values) Isset(k string) bool {
-       _, ok := vs[k]
-       return ok
-}
-
 // scanner implements a tokenizer for libpq-style option strings.
 type scanner struct {
        s []rune
@@ -457,7 +452,7 @@ func parseOpts(name string, o values) error {
                // Skip any whitespace after the =
                if r, ok = s.SkipSpaces(); !ok {
                        // If we reach the end here, the last value is just an empty string as per libpq.
-                       o.Set(string(keyRunes), "")
+                       o[string(keyRunes)] = ""
                        break
                }
 
@@ -492,7 +487,7 @@ func parseOpts(name string, o values) error {
                        }
                }
 
-               o.Set(string(keyRunes), string(valRunes))
+               o[string(keyRunes)] = string(valRunes)
        }
 
        return nil
@@ -511,13 +506,17 @@ func (cn *conn) checkIsInTransaction(intxn bool) {
 }
 
 func (cn *conn) Begin() (_ driver.Tx, err error) {
+       return cn.begin("")
+}
+
+func (cn *conn) begin(mode string) (_ driver.Tx, err error) {
        if cn.bad {
                return nil, driver.ErrBadConn
        }
        defer cn.errRecover(&err)
 
        cn.checkIsInTransaction(false)
-       _, commandTag, err := cn.simpleExec("BEGIN")
+       _, commandTag, err := cn.simpleExec("BEGIN" + mode)
        if err != nil {
                return nil, err
        }
@@ -532,7 +531,14 @@ func (cn *conn) Begin() (_ driver.Tx, err error) {
        return cn, nil
 }
 
+func (cn *conn) closeTxn() {
+       if finish := cn.txnFinish; finish != nil {
+               finish()
+       }
+}
+
 func (cn *conn) Commit() (err error) {
+       defer cn.closeTxn()
        if cn.bad {
                return driver.ErrBadConn
        }
@@ -568,6 +574,7 @@ func (cn *conn) Commit() (err error) {
 }
 
 func (cn *conn) Rollback() (err error) {
+       defer cn.closeTxn()
        if cn.bad {
                return driver.ErrBadConn
        }
@@ -647,6 +654,12 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
                                        cn: cn,
                                }
                        }
+                       // Set the result and tag to the last command complete if there wasn't a
+                       // query already run. Although queries usually return from here and cede
+                       // control to Next, a query with zero results does not.
+                       if t == 'C' && res.colNames == nil {
+                               res.result, res.tag = cn.parseComplete(r.string())
+                       }
                        res.done = true
                case 'Z':
                        cn.processReadyForQuery(r)
@@ -685,7 +698,7 @@ var emptyRows noRows
 var _ driver.Result = noRows{}
 
 func (noRows) LastInsertId() (int64, error) {
-       return 0, errNoLastInsertId
+       return 0, errNoLastInsertID
 }
 
 func (noRows) RowsAffected() (int64, error) {
@@ -694,7 +707,7 @@ func (noRows) RowsAffected() (int64, error) {
 
 // Decides which column formats to use for a prepared statement.  The input is
 // an array of type oids, one element per result column.
-func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, colFmtData []byte) {
+func decideColumnFormats(colTyps []fieldDesc, forceText bool) (colFmts []format, colFmtData []byte) {
        if len(colTyps) == 0 {
                return nil, colFmtDataAllText
        }
@@ -706,8 +719,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
 
        allBinary := true
        allText := true
-       for i, o := range colTyps {
-               switch o {
+       for i, t := range colTyps {
+               switch t.OID {
                // This is the list of types to use binary mode for when receiving them
                // through a prepared statement.  If a type appears in this list, it
                // must also be implemented in binaryDecode in encode.go.
@@ -718,6 +731,8 @@ func decideColumnFormats(colTyps []oid.Oid, forceText bool) (colFmts []format, c
                case oid.T_int4:
                        fallthrough
                case oid.T_int2:
+                       fallthrough
+               case oid.T_uuid:
                        colFmts[i] = formatBinary
                        allText = false
 
@@ -797,7 +812,11 @@ func (cn *conn) Close() (err error) {
 }
 
 // Implement the "Queryer" interface
-func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err error) {
+func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) {
+       return cn.query(query, args)
+}
+
+func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
        if cn.bad {
                return nil, driver.ErrBadConn
        }
@@ -821,16 +840,15 @@ func (cn *conn) Query(query string, args []driver.Value) (_ driver.Rows, err err
                rows.colNames, rows.colFmts, rows.colTyps = cn.readPortalDescribeResponse()
                cn.postExecuteWorkaround()
                return rows, nil
-       } else {
-               st := cn.prepareTo(query, "")
-               st.exec(args)
-               return &rows{
-                       cn:       cn,
-                       colNames: st.colNames,
-                       colTyps:  st.colTyps,
-                       colFmts:  st.colFmts,
-               }, nil
        }
+       st := cn.prepareTo(query, "")
+       st.exec(args)
+       return &rows{
+               cn:       cn,
+               colNames: st.colNames,
+               colTyps:  st.colTyps,
+               colFmts:  st.colFmts,
+       }, nil
 }
 
 // Implement the optional "Execer" interface for one-shot queries
@@ -857,17 +875,16 @@ func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err
                cn.postExecuteWorkaround()
                res, _, err = cn.readExecuteResponse("Execute")
                return res, err
-       } else {
-               // Use the unnamed statement to defer planning until bind
-               // time, or else value-based selectivity estimates cannot be
-               // used.
-               st := cn.prepareTo(query, "")
-               r, err := st.Exec(args)
-               if err != nil {
-                       panic(err)
-               }
-               return r, err
        }
+       // Use the unnamed statement to defer planning until bind
+       // time, or else value-based selectivity estimates cannot be
+       // used.
+       st := cn.prepareTo(query, "")
+       r, err := st.Exec(args)
+       if err != nil {
+               panic(err)
+       }
+       return r, err
 }
 
 func (cn *conn) send(m *writeBuf) {
@@ -877,16 +894,9 @@ func (cn *conn) send(m *writeBuf) {
        }
 }
 
-func (cn *conn) sendStartupPacket(m *writeBuf) {
-       // sanity check
-       if m.buf[0] != 0 {
-               panic("oops")
-       }
-
+func (cn *conn) sendStartupPacket(m *writeBuf) error {
        _, err := cn.c.Write((m.wrap())[1:])
-       if err != nil {
-               panic(err)
-       }
+       return err
 }
 
 // Send a message of type typ to the server on the other end of cn.  The
@@ -1000,45 +1010,17 @@ func (cn *conn) recv1() (t byte, r *readBuf) {
 }
 
 func (cn *conn) ssl(o values) {
-       verifyCaOnly := false
-       tlsConf := tls.Config{}
-       switch mode := o.Get("sslmode"); mode {
-       // "require" is the default.
-       case "", "require":
-               // We must skip TLS's own verification since it requires full
-               // verification since Go 1.3.
-               tlsConf.InsecureSkipVerify = true
-
-               // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
-               // Note: For backwards compatibility with earlier versions of PostgreSQL, if a
-               // root CA file exists, the behavior of sslmode=require will be the same as
-               // that of verify-ca, meaning the server certificate is validated against the
-               // CA. Relying on this behavior is discouraged, and applications that need
-               // certificate validation should always use verify-ca or verify-full.
-               if _, err := os.Stat(o.Get("sslrootcert")); err == nil {
-                       verifyCaOnly = true
-               } else {
-                       o.Set("sslrootcert", "")
-               }
-       case "verify-ca":
-               // We must skip TLS's own verification since it requires full
-               // verification since Go 1.3.
-               tlsConf.InsecureSkipVerify = true
-               verifyCaOnly = true
-       case "verify-full":
-               tlsConf.ServerName = o.Get("host")
-       case "disable":
+       upgrade := ssl(o)
+       if upgrade == nil {
+               // Nothing to do
                return
-       default:
-               errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
        }
 
-       cn.setupSSLClientCertificates(&tlsConf, o)
-       cn.setupSSLCA(&tlsConf, o)
-
        w := cn.writeBuf(0)
        w.int32(80877103)
-       cn.sendStartupPacket(w)
+       if err := cn.sendStartupPacket(w); err != nil {
+               panic(err)
+       }
 
        b := cn.scratch[:1]
        _, err := io.ReadFull(cn.c, b)
@@ -1050,114 +1032,7 @@ func (cn *conn) ssl(o values) {
                panic(ErrSSLNotSupported)
        }
 
-       client := tls.Client(cn.c, &tlsConf)
-       if verifyCaOnly {
-               cn.verifyCA(client, &tlsConf)
-       }
-       cn.c = client
-}
-
-// verifyCA carries out a TLS handshake to the server and verifies the
-// presented certificate against the effective CA, i.e. the one specified in
-// sslrootcert or the system CA if sslrootcert was not specified.
-func (cn *conn) verifyCA(client *tls.Conn, tlsConf *tls.Config) {
-       err := client.Handshake()
-       if err != nil {
-               panic(err)
-       }
-       certs := client.ConnectionState().PeerCertificates
-       opts := x509.VerifyOptions{
-               DNSName:       client.ConnectionState().ServerName,
-               Intermediates: x509.NewCertPool(),
-               Roots:         tlsConf.RootCAs,
-       }
-       for i, cert := range certs {
-               if i == 0 {
-                       continue
-               }
-               opts.Intermediates.AddCert(cert)
-       }
-       _, err = certs[0].Verify(opts)
-       if err != nil {
-               panic(err)
-       }
-}
-
-// This function sets up SSL client certificates based on either the "sslkey"
-// and "sslcert" settings (possibly set via the environment variables PGSSLKEY
-// and PGSSLCERT, respectively), or if they aren't set, from the .postgresql
-// directory in the user's home directory.  If the file paths are set
-// explicitly, the files must exist.  The key file must also not be
-// world-readable, or this function will panic with
-// ErrSSLKeyHasWorldPermissions.
-func (cn *conn) setupSSLClientCertificates(tlsConf *tls.Config, o values) {
-       var missingOk bool
-
-       sslkey := o.Get("sslkey")
-       sslcert := o.Get("sslcert")
-       if sslkey != "" && sslcert != "" {
-               // If the user has set an sslkey and sslcert, they *must* exist.
-               missingOk = false
-       } else {
-               // Automatically load certificates from ~/.postgresql.
-               user, err := user.Current()
-               if err != nil {
-                       // user.Current() might fail when cross-compiling.  We have to
-                       // ignore the error and continue without client certificates, since
-                       // we wouldn't know where to load them from.
-                       return
-               }
-
-               sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
-               sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
-               missingOk = true
-       }
-
-       // Check that both files exist, and report the error or stop, depending on
-       // which behaviour we want.  Note that we don't do any more extensive
-       // checks than this (such as checking that the paths aren't directories);
-       // LoadX509KeyPair() will take care of the rest.
-       keyfinfo, err := os.Stat(sslkey)
-       if err != nil && missingOk {
-               return
-       } else if err != nil {
-               panic(err)
-       }
-       _, err = os.Stat(sslcert)
-       if err != nil && missingOk {
-               return
-       } else if err != nil {
-               panic(err)
-       }
-
-       // If we got this far, the key file must also have the correct permissions
-       kmode := keyfinfo.Mode()
-       if kmode != kmode&0600 {
-               panic(ErrSSLKeyHasWorldPermissions)
-       }
-
-       cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
-       if err != nil {
-               panic(err)
-       }
-       tlsConf.Certificates = []tls.Certificate{cert}
-}
-
-// Sets up RootCAs in the TLS configuration if sslrootcert is set.
-func (cn *conn) setupSSLCA(tlsConf *tls.Config, o values) {
-       if sslrootcert := o.Get("sslrootcert"); sslrootcert != "" {
-               tlsConf.RootCAs = x509.NewCertPool()
-
-               cert, err := ioutil.ReadFile(sslrootcert)
-               if err != nil {
-                       panic(err)
-               }
-
-               ok := tlsConf.RootCAs.AppendCertsFromPEM(cert)
-               if !ok {
-                       errorf("couldn't parse pem in sslrootcert")
-               }
-       }
+       cn.c = upgrade(cn.c)
 }
 
 // isDriverSetting returns true iff a setting is purely for configuring the
@@ -1206,12 +1081,15 @@ func (cn *conn) startup(o values) {
                w.string(v)
        }
        w.string("")
-       cn.sendStartupPacket(w)
+       if err := cn.sendStartupPacket(w); err != nil {
+               panic(err)
+       }
 
        for {
                t, r := cn.recv()
                switch t {
                case 'K':
+                       cn.processBackendKeyData(r)
                case 'S':
                        cn.processParameterStatus(r)
                case 'R':
@@ -1231,7 +1109,7 @@ func (cn *conn) auth(r *readBuf, o values) {
                // OK
        case 3:
                w := cn.writeBuf('p')
-               w.string(o.Get("password"))
+               w.string(o["password"])
                cn.send(w)
 
                t, r := cn.recv()
@@ -1245,7 +1123,7 @@ func (cn *conn) auth(r *readBuf, o values) {
        case 5:
                s := string(r.next(4))
                w := cn.writeBuf('p')
-               w.string("md5" + md5s(md5s(o.Get("password")+o.Get("user"))+s))
+               w.string("md5" + md5s(md5s(o["password"]+o["user"])+s))
                cn.send(w)
 
                t, r := cn.recv()
@@ -1267,10 +1145,10 @@ const formatText format = 0
 const formatBinary format = 1
 
 // One result-column format code with the value 1 (i.e. all binary).
-var colFmtDataAllBinary []byte = []byte{0, 1, 0, 1}
+var colFmtDataAllBinary = []byte{0, 1, 0, 1}
 
 // No result-column format codes (i.e. all text).
-var colFmtDataAllText []byte = []byte{0, 0}
+var colFmtDataAllText = []byte{0, 0}
 
 type stmt struct {
        cn         *conn
@@ -1278,7 +1156,7 @@ type stmt struct {
        colNames   []string
        colFmts    []format
        colFmtData []byte
-       colTyps    []oid.Oid
+       colTyps    []fieldDesc
        paramTyps  []oid.Oid
        closed     bool
 }
@@ -1439,21 +1317,32 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
 
 type rows struct {
        cn       *conn
+       finish   func()
        colNames []string
-       colTyps  []oid.Oid
+       colTyps  []fieldDesc
        colFmts  []format
        done     bool
        rb       readBuf
+       result   driver.Result
+       tag      string
 }
 
 func (rs *rows) Close() error {
+       if finish := rs.finish; finish != nil {
+               defer finish()
+       }
        // no need to look at cn.bad as Next() will
        for {
                err := rs.Next(nil)
                switch err {
                case nil:
                case io.EOF:
-                       return nil
+                       // rs.Next can return io.EOF on both 'Z' (ready for query) and 'T' (row
+                       // description, used with HasNextResultSet). We need to fetch messages until
+                       // we hit a 'Z', which is done by waiting for done to be set.
+                       if rs.done {
+                               return nil
+                       }
                default:
                        return err
                }
@@ -1464,6 +1353,17 @@ func (rs *rows) Columns() []string {
        return rs.colNames
 }
 
+func (rs *rows) Result() driver.Result {
+       if rs.result == nil {
+               return emptyRows
+       }
+       return rs.result
+}
+
+func (rs *rows) Tag() string {
+       return rs.tag
+}
+
 func (rs *rows) Next(dest []driver.Value) (err error) {
        if rs.done {
                return io.EOF
@@ -1481,6 +1381,9 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
                case 'E':
                        err = parseError(&rs.rb)
                case 'C', 'I':
+                       if t == 'C' {
+                               rs.result, rs.tag = conn.parseComplete(rs.rb.string())
+                       }
                        continue
                case 'Z':
                        conn.processReadyForQuery(&rs.rb)
@@ -1504,7 +1407,7 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
                                        dest[i] = nil
                                        continue
                                }
-                               dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i], rs.colFmts[i])
+                               dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i])
                        }
                        return
                case 'T':
@@ -1610,7 +1513,7 @@ func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {
        cn.send(b)
 }
 
-func (c *conn) processParameterStatus(r *readBuf) {
+func (cn *conn) processParameterStatus(r *readBuf) {
        var err error
 
        param := r.string()
@@ -1621,13 +1524,13 @@ func (c *conn) processParameterStatus(r *readBuf) {
                var minor int
                _, err = fmt.Sscanf(r.string(), "%d.%d.%d", &major1, &major2, &minor)
                if err == nil {
-                       c.parameterStatus.serverVersion = major1*10000 + major2*100 + minor
+                       cn.parameterStatus.serverVersion = major1*10000 + major2*100 + minor
                }
 
        case "TimeZone":
-               c.parameterStatus.currentLocation, err = time.LoadLocation(r.string())
+               cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string())
                if err != nil {
-                       c.parameterStatus.currentLocation = nil
+                       cn.parameterStatus.currentLocation = nil
                }
 
        default:
@@ -1635,8 +1538,8 @@ func (c *conn) processParameterStatus(r *readBuf) {
        }
 }
 
-func (c *conn) processReadyForQuery(r *readBuf) {
-       c.txnStatus = transactionStatus(r.byte())
+func (cn *conn) processReadyForQuery(r *readBuf) {
+       cn.txnStatus = transactionStatus(r.byte())
 }
 
 func (cn *conn) readReadyForQuery() {
@@ -1651,6 +1554,11 @@ func (cn *conn) readReadyForQuery() {
        }
 }
 
+func (cn *conn) processBackendKeyData(r *readBuf) {
+       cn.processID = r.int32()
+       cn.secretKey = r.int32()
+}
+
 func (cn *conn) readParseResponse() {
        t, r := cn.recv1()
        switch t {
@@ -1666,7 +1574,7 @@ func (cn *conn) readParseResponse() {
        }
 }
 
-func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []oid.Oid) {
+func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc) {
        for {
                t, r := cn.recv1()
                switch t {
@@ -1692,7 +1600,7 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
        }
 }
 
-func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []oid.Oid) {
+func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) {
        t, r := cn.recv1()
        switch t {
        case 'T':
@@ -1788,31 +1696,33 @@ func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, co
        }
 }
 
-func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []oid.Oid) {
+func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) {
        n := r.int16()
        colNames = make([]string, n)
-       colTyps = make([]oid.Oid, n)
+       colTyps = make([]fieldDesc, n)
        for i := range colNames {
                colNames[i] = r.string()
                r.next(6)
-               colTyps[i] = r.oid()
-               r.next(6)
+               colTyps[i].OID = r.oid()
+               colTyps[i].Len = r.int16()
+               colTyps[i].Mod = r.int32()
                // format code not known when describing a statement; always 0
                r.next(2)
        }
        return
 }
 
-func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []oid.Oid) {
+func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) {
        n := r.int16()
        colNames = make([]string, n)
        colFmts = make([]format, n)
-       colTyps = make([]oid.Oid, n)
+       colTyps = make([]fieldDesc, n)
        for i := range colNames {
                colNames[i] = r.string()
                r.next(6)
-               colTyps[i] = r.oid()
-               r.next(6)
+               colTyps[i].OID = r.oid()
+               colTyps[i].Len = r.int16()
+               colTyps[i].Mod = r.int32()
                colFmts[i] = format(r.int16())
        }
        return
diff --git a/vendor/github.com/lib/pq/conn_go18.go b/vendor/github.com/lib/pq/conn_go18.go
new file mode 100644 (file)
index 0000000..ab97a10
--- /dev/null
@@ -0,0 +1,128 @@
+// +build go1.8
+
+package pq
+
+import (
+       "context"
+       "database/sql"
+       "database/sql/driver"
+       "fmt"
+       "io"
+       "io/ioutil"
+)
+
+// Implement the "QueryerContext" interface
+func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
+       list := make([]driver.Value, len(args))
+       for i, nv := range args {
+               list[i] = nv.Value
+       }
+       finish := cn.watchCancel(ctx)
+       r, err := cn.query(query, list)
+       if err != nil {
+               if finish != nil {
+                       finish()
+               }
+               return nil, err
+       }
+       r.finish = finish
+       return r, nil
+}
+
+// Implement the "ExecerContext" interface
+func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
+       list := make([]driver.Value, len(args))
+       for i, nv := range args {
+               list[i] = nv.Value
+       }
+
+       if finish := cn.watchCancel(ctx); finish != nil {
+               defer finish()
+       }
+
+       return cn.Exec(query, list)
+}
+
+// Implement the "ConnBeginTx" interface
+func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
+       var mode string
+
+       switch sql.IsolationLevel(opts.Isolation) {
+       case sql.LevelDefault:
+               // Don't touch mode: use the server's default
+       case sql.LevelReadUncommitted:
+               mode = " ISOLATION LEVEL READ UNCOMMITTED"
+       case sql.LevelReadCommitted:
+               mode = " ISOLATION LEVEL READ COMMITTED"
+       case sql.LevelRepeatableRead:
+               mode = " ISOLATION LEVEL REPEATABLE READ"
+       case sql.LevelSerializable:
+               mode = " ISOLATION LEVEL SERIALIZABLE"
+       default:
+               return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation)
+       }
+
+       if opts.ReadOnly {
+               mode += " READ ONLY"
+       } else {
+               mode += " READ WRITE"
+       }
+
+       tx, err := cn.begin(mode)
+       if err != nil {
+               return nil, err
+       }
+       cn.txnFinish = cn.watchCancel(ctx)
+       return tx, nil
+}
+
+func (cn *conn) watchCancel(ctx context.Context) func() {
+       if done := ctx.Done(); done != nil {
+               finished := make(chan struct{})
+               go func() {
+                       select {
+                       case <-done:
+                               _ = cn.cancel()
+                               finished <- struct{}{}
+                       case <-finished:
+                       }
+               }()
+               return func() {
+                       select {
+                       case <-finished:
+                       case finished <- struct{}{}:
+                       }
+               }
+       }
+       return nil
+}
+
+func (cn *conn) cancel() error {
+       c, err := dial(cn.dialer, cn.opts)
+       if err != nil {
+               return err
+       }
+       defer c.Close()
+
+       {
+               can := conn{
+                       c: c,
+               }
+               can.ssl(cn.opts)
+
+               w := can.writeBuf(0)
+               w.int32(80877102) // cancel request code
+               w.int32(cn.processID)
+               w.int32(cn.secretKey)
+
+               if err := can.sendStartupPacket(w); err != nil {
+                       return err
+               }
+       }
+
+       // Read until EOF to ensure that the server received the cancel.
+       {
+               _, err := io.Copy(ioutil.Discard, c)
+               return err
+       }
+}
index 86a7127e1d2971dd6c3c6c7c79937a35cfb3e093..345c2398f6cd93612f915f4c42e7656cc3f4e993 100644 (file)
@@ -97,13 +97,13 @@ awaitCopyInResponse:
                        err = parseError(r)
                case 'Z':
                        if err == nil {
-                               cn.bad = true
+                               ci.setBad()
                                errorf("unexpected ReadyForQuery in response to COPY")
                        }
                        cn.processReadyForQuery(r)
                        return nil, err
                default:
-                       cn.bad = true
+                       ci.setBad()
                        errorf("unknown response for copy query: %q", t)
                }
        }
@@ -122,7 +122,7 @@ awaitCopyInResponse:
                        cn.processReadyForQuery(r)
                        return nil, err
                default:
-                       cn.bad = true
+                       ci.setBad()
                        errorf("unknown response for CopyFail: %q", t)
                }
        }
@@ -143,7 +143,7 @@ func (ci *copyin) resploop() {
                var r readBuf
                t, err := ci.cn.recvMessage(&r)
                if err != nil {
-                       ci.cn.bad = true
+                       ci.setBad()
                        ci.setError(err)
                        ci.done <- true
                        return
@@ -161,7 +161,7 @@ func (ci *copyin) resploop() {
                        err := parseError(&r)
                        ci.setError(err)
                default:
-                       ci.cn.bad = true
+                       ci.setBad()
                        ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t))
                        ci.done <- true
                        return
@@ -169,6 +169,19 @@ func (ci *copyin) resploop() {
        }
 }
 
+func (ci *copyin) setBad() {
+       ci.Lock()
+       ci.cn.bad = true
+       ci.Unlock()
+}
+
+func (ci *copyin) isBad() bool {
+       ci.Lock()
+       b := ci.cn.bad
+       ci.Unlock()
+       return b
+}
+
 func (ci *copyin) isErrorSet() bool {
        ci.Lock()
        isSet := (ci.err != nil)
@@ -206,7 +219,7 @@ func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) {
                return nil, errCopyInClosed
        }
 
-       if ci.cn.bad {
+       if ci.isBad() {
                return nil, driver.ErrBadConn
        }
        defer ci.cn.errRecover(&err)
@@ -244,7 +257,7 @@ func (ci *copyin) Close() (err error) {
        }
        ci.closed = true
 
-       if ci.cn.bad {
+       if ci.isBad() {
                return driver.ErrBadConn
        }
        defer ci.cn.errRecover(&err)
index 29e8f6ff7ce34d6e457637ac08a39c3cd642b116..3b0d365f2964b94a93f92c5c398d3c76fd59abe1 100644 (file)
@@ -76,6 +76,12 @@ func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) inter
                return int64(int32(binary.BigEndian.Uint32(s)))
        case oid.T_int2:
                return int64(int16(binary.BigEndian.Uint16(s)))
+       case oid.T_uuid:
+               b, err := decodeUUIDBinary(s)
+               if err != nil {
+                       panic(err)
+               }
+               return b
 
        default:
                errorf("don't know how to decode binary parameter of type %d", uint32(typ))
@@ -361,8 +367,15 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
        timeSep := daySep + 3
        day := p.mustAtoi(str, daySep+1, timeSep)
 
+       minLen := monSep + len("01-01") + 1
+
+       isBC := strings.HasSuffix(str, " BC")
+       if isBC {
+               minLen += 3
+       }
+
        var hour, minute, second int
-       if len(str) > monSep+len("01-01")+1 {
+       if len(str) > minLen {
                p.expect(str, ' ', timeSep)
                minSep := timeSep + 3
                p.expect(str, ':', minSep)
@@ -418,7 +431,8 @@ func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, erro
                tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
        }
        var isoYear int
-       if remainderIdx+3 <= len(str) && str[remainderIdx:remainderIdx+3] == " BC" {
+
+       if isBC {
                isoYear = 1 - year
                remainderIdx += 3
        } else {
@@ -471,7 +485,7 @@ func FormatTimestamp(t time.Time) []byte {
                t = t.AddDate((-t.Year())*2+1, 0, 0)
                bc = true
        }
-       b := []byte(t.Format(time.RFC3339Nano))
+       b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
 
        _, offset := t.Zone()
        offset = offset % 60
index 09f94244b9bb2f89ee091c42efb65e48047a3334..a171651577617f4048372fb5539ca55765013483 100644 (file)
@@ -639,7 +639,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
                        // close and then return the error message from the connection, as
                        // per ListenerConn's interface.
                        if err != nil {
-                               for _ = range notificationChan {
+                               for range notificationChan {
                                }
                                doneChan <- cn.Err()
                                return
diff --git a/vendor/github.com/lib/pq/oid/gen.go b/vendor/github.com/lib/pq/oid/gen.go
deleted file mode 100644 (file)
index cd4aea8..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-// +build ignore
-
-// Generate the table of OID values
-// Run with 'go run gen.go'.
-package main
-
-import (
-       "database/sql"
-       "fmt"
-       "log"
-       "os"
-       "os/exec"
-
-       _ "github.com/lib/pq"
-)
-
-func main() {
-       datname := os.Getenv("PGDATABASE")
-       sslmode := os.Getenv("PGSSLMODE")
-
-       if datname == "" {
-               os.Setenv("PGDATABASE", "pqgotest")
-       }
-
-       if sslmode == "" {
-               os.Setenv("PGSSLMODE", "disable")
-       }
-
-       db, err := sql.Open("postgres", "")
-       if err != nil {
-               log.Fatal(err)
-       }
-       cmd := exec.Command("gofmt")
-       cmd.Stderr = os.Stderr
-       w, err := cmd.StdinPipe()
-       if err != nil {
-               log.Fatal(err)
-       }
-       f, err := os.Create("types.go")
-       if err != nil {
-               log.Fatal(err)
-       }
-       cmd.Stdout = f
-       err = cmd.Start()
-       if err != nil {
-               log.Fatal(err)
-       }
-       fmt.Fprintln(w, "// generated by 'go run gen.go'; do not edit")
-       fmt.Fprintln(w, "\npackage oid")
-       fmt.Fprintln(w, "const (")
-       rows, err := db.Query(`
-               SELECT typname, oid
-               FROM pg_type WHERE oid < 10000
-               ORDER BY oid;
-       `)
-       if err != nil {
-               log.Fatal(err)
-       }
-       var name string
-       var oid int
-       for rows.Next() {
-               err = rows.Scan(&name, &oid)
-               if err != nil {
-                       log.Fatal(err)
-               }
-               fmt.Fprintf(w, "T_%s Oid = %d\n", name, oid)
-       }
-       if err = rows.Err(); err != nil {
-               log.Fatal(err)
-       }
-       fmt.Fprintln(w, ")")
-       w.Close()
-       cmd.Wait()
-}
index 03df05a617aff4b5437e9e56d623e6759117f163..ecc84c2c862dfbee0cb1b2bb41323d75dcb5ad92 100644 (file)
@@ -1,4 +1,4 @@
-// generated by 'go run gen.go'; do not edit
+// Code generated by gen.go. DO NOT EDIT.
 
 package oid
 
@@ -18,6 +18,7 @@ const (
        T_xid              Oid = 28
        T_cid              Oid = 29
        T_oidvector        Oid = 30
+       T_pg_ddl_command   Oid = 32
        T_pg_type          Oid = 71
        T_pg_attribute     Oid = 75
        T_pg_proc          Oid = 81
@@ -28,6 +29,7 @@ const (
        T_pg_node_tree     Oid = 194
        T__json            Oid = 199
        T_smgr             Oid = 210
+       T_index_am_handler Oid = 325
        T_point            Oid = 600
        T_lseg             Oid = 601
        T_path             Oid = 602
@@ -133,6 +135,9 @@ const (
        T__uuid            Oid = 2951
        T_txid_snapshot    Oid = 2970
        T_fdw_handler      Oid = 3115
+       T_pg_lsn           Oid = 3220
+       T__pg_lsn          Oid = 3221
+       T_tsm_handler      Oid = 3310
        T_anyenum          Oid = 3500
        T_tsvector         Oid = 3614
        T_tsquery          Oid = 3615
@@ -144,6 +149,8 @@ const (
        T__regconfig       Oid = 3735
        T_regdictionary    Oid = 3769
        T__regdictionary   Oid = 3770
+       T_jsonb            Oid = 3802
+       T__jsonb           Oid = 3807
        T_anyrange         Oid = 3831
        T_event_trigger    Oid = 3838
        T_int4range        Oid = 3904
@@ -158,4 +165,179 @@ const (
        T__daterange       Oid = 3913
        T_int8range        Oid = 3926
        T__int8range       Oid = 3927
+       T_pg_shseclabel    Oid = 4066
+       T_regnamespace     Oid = 4089
+       T__regnamespace    Oid = 4090
+       T_regrole          Oid = 4096
+       T__regrole         Oid = 4097
 )
+
+var TypeName = map[Oid]string{
+       T_bool:             "BOOL",
+       T_bytea:            "BYTEA",
+       T_char:             "CHAR",
+       T_name:             "NAME",
+       T_int8:             "INT8",
+       T_int2:             "INT2",
+       T_int2vector:       "INT2VECTOR",
+       T_int4:             "INT4",
+       T_regproc:          "REGPROC",
+       T_text:             "TEXT",
+       T_oid:              "OID",
+       T_tid:              "TID",
+       T_xid:              "XID",
+       T_cid:              "CID",
+       T_oidvector:        "OIDVECTOR",
+       T_pg_ddl_command:   "PG_DDL_COMMAND",
+       T_pg_type:          "PG_TYPE",
+       T_pg_attribute:     "PG_ATTRIBUTE",
+       T_pg_proc:          "PG_PROC",
+       T_pg_class:         "PG_CLASS",
+       T_json:             "JSON",
+       T_xml:              "XML",
+       T__xml:             "_XML",
+       T_pg_node_tree:     "PG_NODE_TREE",
+       T__json:            "_JSON",
+       T_smgr:             "SMGR",
+       T_index_am_handler: "INDEX_AM_HANDLER",
+       T_point:            "POINT",
+       T_lseg:             "LSEG",
+       T_path:             "PATH",
+       T_box:              "BOX",
+       T_polygon:          "POLYGON",
+       T_line:             "LINE",
+       T__line:            "_LINE",
+       T_cidr:             "CIDR",
+       T__cidr:            "_CIDR",
+       T_float4:           "FLOAT4",
+       T_float8:           "FLOAT8",
+       T_abstime:          "ABSTIME",
+       T_reltime:          "RELTIME",
+       T_tinterval:        "TINTERVAL",
+       T_unknown:          "UNKNOWN",
+       T_circle:           "CIRCLE",
+       T__circle:          "_CIRCLE",
+       T_money:            "MONEY",
+       T__money:           "_MONEY",
+       T_macaddr:          "MACADDR",
+       T_inet:             "INET",
+       T__bool:            "_BOOL",
+       T__bytea:           "_BYTEA",
+       T__char:            "_CHAR",
+       T__name:            "_NAME",
+       T__int2:            "_INT2",
+       T__int2vector:      "_INT2VECTOR",
+       T__int4:            "_INT4",
+       T__regproc:         "_REGPROC",
+       T__text:            "_TEXT",
+       T__tid:             "_TID",
+       T__xid:             "_XID",
+       T__cid:             "_CID",
+       T__oidvector:       "_OIDVECTOR",
+       T__bpchar:          "_BPCHAR",
+       T__varchar:         "_VARCHAR",
+       T__int8:            "_INT8",
+       T__point:           "_POINT",
+       T__lseg:            "_LSEG",
+       T__path:            "_PATH",
+       T__box:             "_BOX",
+       T__float4:          "_FLOAT4",
+       T__float8:          "_FLOAT8",
+       T__abstime:         "_ABSTIME",
+       T__reltime:         "_RELTIME",
+       T__tinterval:       "_TINTERVAL",
+       T__polygon:         "_POLYGON",
+       T__oid:             "_OID",
+       T_aclitem:          "ACLITEM",
+       T__aclitem:         "_ACLITEM",
+       T__macaddr:         "_MACADDR",
+       T__inet:            "_INET",
+       T_bpchar:           "BPCHAR",
+       T_varchar:          "VARCHAR",
+       T_date:             "DATE",
+       T_time:             "TIME",
+       T_timestamp:        "TIMESTAMP",
+       T__timestamp:       "_TIMESTAMP",
+       T__date:            "_DATE",
+       T__time:            "_TIME",
+       T_timestamptz:      "TIMESTAMPTZ",
+       T__timestamptz:     "_TIMESTAMPTZ",
+       T_interval:         "INTERVAL",
+       T__interval:        "_INTERVAL",
+       T__numeric:         "_NUMERIC",
+       T_pg_database:      "PG_DATABASE",
+       T__cstring:         "_CSTRING",
+       T_timetz:           "TIMETZ",
+       T__timetz:          "_TIMETZ",
+       T_bit:              "BIT",
+       T__bit:             "_BIT",
+       T_varbit:           "VARBIT",
+       T__varbit:          "_VARBIT",
+       T_numeric:          "NUMERIC",
+       T_refcursor:        "REFCURSOR",
+       T__refcursor:       "_REFCURSOR",
+       T_regprocedure:     "REGPROCEDURE",
+       T_regoper:          "REGOPER",
+       T_regoperator:      "REGOPERATOR",
+       T_regclass:         "REGCLASS",
+       T_regtype:          "REGTYPE",
+       T__regprocedure:    "_REGPROCEDURE",
+       T__regoper:         "_REGOPER",
+       T__regoperator:     "_REGOPERATOR",
+       T__regclass:        "_REGCLASS",
+       T__regtype:         "_REGTYPE",
+       T_record:           "RECORD",
+       T_cstring:          "CSTRING",
+       T_any:              "ANY",
+       T_anyarray:         "ANYARRAY",
+       T_void:             "VOID",
+       T_trigger:          "TRIGGER",
+       T_language_handler: "LANGUAGE_HANDLER",
+       T_internal:         "INTERNAL",
+       T_opaque:           "OPAQUE",
+       T_anyelement:       "ANYELEMENT",
+       T__record:          "_RECORD",
+       T_anynonarray:      "ANYNONARRAY",
+       T_pg_authid:        "PG_AUTHID",
+       T_pg_auth_members:  "PG_AUTH_MEMBERS",
+       T__txid_snapshot:   "_TXID_SNAPSHOT",
+       T_uuid:             "UUID",
+       T__uuid:            "_UUID",
+       T_txid_snapshot:    "TXID_SNAPSHOT",
+       T_fdw_handler:      "FDW_HANDLER",
+       T_pg_lsn:           "PG_LSN",
+       T__pg_lsn:          "_PG_LSN",
+       T_tsm_handler:      "TSM_HANDLER",
+       T_anyenum:          "ANYENUM",
+       T_tsvector:         "TSVECTOR",
+       T_tsquery:          "TSQUERY",
+       T_gtsvector:        "GTSVECTOR",
+       T__tsvector:        "_TSVECTOR",
+       T__gtsvector:       "_GTSVECTOR",
+       T__tsquery:         "_TSQUERY",
+       T_regconfig:        "REGCONFIG",
+       T__regconfig:       "_REGCONFIG",
+       T_regdictionary:    "REGDICTIONARY",
+       T__regdictionary:   "_REGDICTIONARY",
+       T_jsonb:            "JSONB",
+       T__jsonb:           "_JSONB",
+       T_anyrange:         "ANYRANGE",
+       T_event_trigger:    "EVENT_TRIGGER",
+       T_int4range:        "INT4RANGE",
+       T__int4range:       "_INT4RANGE",
+       T_numrange:         "NUMRANGE",
+       T__numrange:        "_NUMRANGE",
+       T_tsrange:          "TSRANGE",
+       T__tsrange:         "_TSRANGE",
+       T_tstzrange:        "TSTZRANGE",
+       T__tstzrange:       "_TSTZRANGE",
+       T_daterange:        "DATERANGE",
+       T__daterange:       "_DATERANGE",
+       T_int8range:        "INT8RANGE",
+       T__int8range:       "_INT8RANGE",
+       T_pg_shseclabel:    "PG_SHSECLABEL",
+       T_regnamespace:     "REGNAMESPACE",
+       T__regnamespace:    "_REGNAMESPACE",
+       T_regrole:          "REGROLE",
+       T__regrole:         "_REGROLE",
+}
diff --git a/vendor/github.com/lib/pq/rows.go b/vendor/github.com/lib/pq/rows.go
new file mode 100644 (file)
index 0000000..c6aa5b9
--- /dev/null
@@ -0,0 +1,93 @@
+package pq
+
+import (
+       "math"
+       "reflect"
+       "time"
+
+       "github.com/lib/pq/oid"
+)
+
+const headerSize = 4
+
+type fieldDesc struct {
+       // The object ID of the data type.
+       OID oid.Oid
+       // The data type size (see pg_type.typlen).
+       // Note that negative values denote variable-width types.
+       Len int
+       // The type modifier (see pg_attribute.atttypmod).
+       // The meaning of the modifier is type-specific.
+       Mod int
+}
+
+func (fd fieldDesc) Type() reflect.Type {
+       switch fd.OID {
+       case oid.T_int8:
+               return reflect.TypeOf(int64(0))
+       case oid.T_int4:
+               return reflect.TypeOf(int32(0))
+       case oid.T_int2:
+               return reflect.TypeOf(int16(0))
+       case oid.T_varchar, oid.T_text:
+               return reflect.TypeOf("")
+       case oid.T_bool:
+               return reflect.TypeOf(false)
+       case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz:
+               return reflect.TypeOf(time.Time{})
+       case oid.T_bytea:
+               return reflect.TypeOf([]byte(nil))
+       default:
+               return reflect.TypeOf(new(interface{})).Elem()
+       }
+}
+
+func (fd fieldDesc) Name() string {
+       return oid.TypeName[fd.OID]
+}
+
+func (fd fieldDesc) Length() (length int64, ok bool) {
+       switch fd.OID {
+       case oid.T_text, oid.T_bytea:
+               return math.MaxInt64, true
+       case oid.T_varchar, oid.T_bpchar:
+               return int64(fd.Mod - headerSize), true
+       default:
+               return 0, false
+       }
+}
+
+func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) {
+       switch fd.OID {
+       case oid.T_numeric, oid.T__numeric:
+               mod := fd.Mod - headerSize
+               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 (rs *rows) ColumnTypeScanType(index int) reflect.Type {
+       return rs.colTyps[index].Type()
+}
+
+// ColumnTypeDatabaseTypeName return the database system type name.
+func (rs *rows) ColumnTypeDatabaseTypeName(index int) string {
+       return rs.colTyps[index].Name()
+}
+
+// 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 (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) {
+       return rs.colTyps[index].Length()
+}
+
+// ColumnTypePrecisionScale should return the precision and scale for decimal
+// types. If not applicable, ok should be false.
+func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) {
+       return rs.colTyps[index].PrecisionScale()
+}
diff --git a/vendor/github.com/lib/pq/ssl.go b/vendor/github.com/lib/pq/ssl.go
new file mode 100644 (file)
index 0000000..7deb304
--- /dev/null
@@ -0,0 +1,158 @@
+package pq
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "io/ioutil"
+       "net"
+       "os"
+       "os/user"
+       "path/filepath"
+)
+
+// ssl generates a function to upgrade a net.Conn based on the "sslmode" and
+// related settings. The function is nil when no upgrade should take place.
+func ssl(o values) func(net.Conn) net.Conn {
+       verifyCaOnly := false
+       tlsConf := tls.Config{}
+       switch mode := o["sslmode"]; mode {
+       // "require" is the default.
+       case "", "require":
+               // We must skip TLS's own verification since it requires full
+               // verification since Go 1.3.
+               tlsConf.InsecureSkipVerify = true
+
+               // From http://www.postgresql.org/docs/current/static/libpq-ssl.html:
+               //
+               // Note: For backwards compatibility with earlier versions of
+               // PostgreSQL, if a root CA file exists, the behavior of
+               // sslmode=require will be the same as that of verify-ca, meaning the
+               // server certificate is validated against the CA. Relying on this
+               // behavior is discouraged, and applications that need certificate
+               // validation should always use verify-ca or verify-full.
+               if sslrootcert, ok := o["sslrootcert"]; ok {
+                       if _, err := os.Stat(sslrootcert); err == nil {
+                               verifyCaOnly = true
+                       } else {
+                               delete(o, "sslrootcert")
+                       }
+               }
+       case "verify-ca":
+               // We must skip TLS's own verification since it requires full
+               // verification since Go 1.3.
+               tlsConf.InsecureSkipVerify = true
+               verifyCaOnly = true
+       case "verify-full":
+               tlsConf.ServerName = o["host"]
+       case "disable":
+               return nil
+       default:
+               errorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode)
+       }
+
+       sslClientCertificates(&tlsConf, o)
+       sslCertificateAuthority(&tlsConf, o)
+       sslRenegotiation(&tlsConf)
+
+       return func(conn net.Conn) net.Conn {
+               client := tls.Client(conn, &tlsConf)
+               if verifyCaOnly {
+                       sslVerifyCertificateAuthority(client, &tlsConf)
+               }
+               return client
+       }
+}
+
+// sslClientCertificates adds the certificate specified in the "sslcert" and
+// "sslkey" settings, or if they aren't set, from the .postgresql directory
+// in the user's home directory. The configured files must exist and have
+// the correct permissions.
+func sslClientCertificates(tlsConf *tls.Config, o values) {
+       // user.Current() might fail when cross-compiling. We have to ignore the
+       // error and continue without home directory defaults, since we wouldn't
+       // know from where to load them.
+       user, _ := user.Current()
+
+       // In libpq, the client certificate is only loaded if the setting is not blank.
+       //
+       // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037
+       sslcert := o["sslcert"]
+       if len(sslcert) == 0 && user != nil {
+               sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt")
+       }
+       // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045
+       if len(sslcert) == 0 {
+               return
+       }
+       // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054
+       if _, err := os.Stat(sslcert); os.IsNotExist(err) {
+               return
+       } else if err != nil {
+               panic(err)
+       }
+
+       // In libpq, the ssl key is only loaded if the setting is not blank.
+       //
+       // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222
+       sslkey := o["sslkey"]
+       if len(sslkey) == 0 && user != nil {
+               sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key")
+       }
+
+       if len(sslkey) > 0 {
+               if err := sslKeyPermissions(sslkey); err != nil {
+                       panic(err)
+               }
+       }
+
+       cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
+       if err != nil {
+               panic(err)
+       }
+       tlsConf.Certificates = []tls.Certificate{cert}
+}
+
+// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting.
+func sslCertificateAuthority(tlsConf *tls.Config, o values) {
+       // In libpq, the root certificate is only loaded if the setting is not blank.
+       //
+       // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951
+       if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 {
+               tlsConf.RootCAs = x509.NewCertPool()
+
+               cert, err := ioutil.ReadFile(sslrootcert)
+               if err != nil {
+                       panic(err)
+               }
+
+               if !tlsConf.RootCAs.AppendCertsFromPEM(cert) {
+                       errorf("couldn't parse pem in sslrootcert")
+               }
+       }
+}
+
+// sslVerifyCertificateAuthority carries out a TLS handshake to the server and
+// verifies the presented certificate against the CA, i.e. the one specified in
+// sslrootcert or the system CA if sslrootcert was not specified.
+func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) {
+       err := client.Handshake()
+       if err != nil {
+               panic(err)
+       }
+       certs := client.ConnectionState().PeerCertificates
+       opts := x509.VerifyOptions{
+               DNSName:       client.ConnectionState().ServerName,
+               Intermediates: x509.NewCertPool(),
+               Roots:         tlsConf.RootCAs,
+       }
+       for i, cert := range certs {
+               if i == 0 {
+                       continue
+               }
+               opts.Intermediates.AddCert(cert)
+       }
+       _, err = certs[0].Verify(opts)
+       if err != nil {
+               panic(err)
+       }
+}
diff --git a/vendor/github.com/lib/pq/ssl_go1.7.go b/vendor/github.com/lib/pq/ssl_go1.7.go
new file mode 100644 (file)
index 0000000..d7ba43b
--- /dev/null
@@ -0,0 +1,14 @@
+// +build go1.7
+
+package pq
+
+import "crypto/tls"
+
+// Accept renegotiation requests initiated by the backend.
+//
+// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
+// the default configuration of older versions has it enabled. Redshift
+// also initiates renegotiations and cannot be reconfigured.
+func sslRenegotiation(conf *tls.Config) {
+       conf.Renegotiation = tls.RenegotiateFreelyAsClient
+}
diff --git a/vendor/github.com/lib/pq/ssl_permissions.go b/vendor/github.com/lib/pq/ssl_permissions.go
new file mode 100644 (file)
index 0000000..3b7c3a2
--- /dev/null
@@ -0,0 +1,20 @@
+// +build !windows
+
+package pq
+
+import "os"
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(sslkey string) error {
+       info, err := os.Stat(sslkey)
+       if err != nil {
+               return err
+       }
+       if info.Mode().Perm()&0077 != 0 {
+               return ErrSSLKeyHasWorldPermissions
+       }
+       return nil
+}
diff --git a/vendor/github.com/lib/pq/ssl_renegotiation.go b/vendor/github.com/lib/pq/ssl_renegotiation.go
new file mode 100644 (file)
index 0000000..85ed5e4
--- /dev/null
@@ -0,0 +1,8 @@
+// +build !go1.7
+
+package pq
+
+import "crypto/tls"
+
+// Renegotiation is not supported by crypto/tls until Go 1.7.
+func sslRenegotiation(*tls.Config) {}
diff --git a/vendor/github.com/lib/pq/ssl_windows.go b/vendor/github.com/lib/pq/ssl_windows.go
new file mode 100644 (file)
index 0000000..5d2c763
--- /dev/null
@@ -0,0 +1,9 @@
+// +build windows
+
+package pq
+
+// sslKeyPermissions checks the permissions on user-supplied ssl key files.
+// The key file should have very little access.
+//
+// libpq does not check key file permissions on Windows.
+func sslKeyPermissions(string) error { return nil }
diff --git a/vendor/github.com/lib/pq/uuid.go b/vendor/github.com/lib/pq/uuid.go
new file mode 100644 (file)
index 0000000..9a1b9e0
--- /dev/null
@@ -0,0 +1,23 @@
+package pq
+
+import (
+       "encoding/hex"
+       "fmt"
+)
+
+// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format.
+func decodeUUIDBinary(src []byte) ([]byte, error) {
+       if len(src) != 16 {
+               return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src))
+       }
+
+       dst := make([]byte, 36)
+       dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-'
+       hex.Encode(dst[0:], src[0:4])
+       hex.Encode(dst[9:], src[4:6])
+       hex.Encode(dst[14:], src[6:8])
+       hex.Encode(dst[19:], src[8:10])
+       hex.Encode(dst[24:], src[10:16])
+
+       return dst, nil
+}
index ef595425949b249e6c1ca465175a9e3aee64ca23..04e2e8e11a98f8da153c8b5c6ae13b082a22044a 100644 (file)
                        "revisionTime": "2016-10-16T15:41:25Z"
                },
                {
-                       "checksumSHA1": "avqi4lkviHdrNJ92cXCwrw9x870=",
+                       "checksumSHA1": "QV4HZTfaXvhD+5PcGM2p+7aCYYI=",
                        "path": "github.com/lib/pq",
-                       "revision": "d8eeeb8bae8896dd8e1b7e514ab0d396c4f12a1b",
-                       "revisionTime": "2016-11-03T02:43:54Z"
+                       "revision": "456514e2defec52e0cd37f90ccf17ec8b28295e2",
+                       "revisionTime": "2017-10-19T22:30:07Z"
                },
                {
-                       "checksumSHA1": "xppHi82MLqVx1eyQmbhTesAEjx8=",
+                       "checksumSHA1": "AU3fA8Sm33Vj9PBoRPSeYfxLRuE=",
                        "path": "github.com/lib/pq/oid",
-                       "revision": "d8eeeb8bae8896dd8e1b7e514ab0d396c4f12a1b",
-                       "revisionTime": "2016-11-03T02:43:54Z"
+                       "revision": "456514e2defec52e0cd37f90ccf17ec8b28295e2",
+                       "revisionTime": "2017-10-19T22:30:07Z"
                },
                {
                        "checksumSHA1": "O3KUfEXQPfdQ+tCMpP2RAIRJJqY=",