mirror of
1
Fork 0

[chore]: Bump github.com/jackc/pgx/v5 from 5.5.0 to 5.5.1 (#2468)

Bumps [github.com/jackc/pgx/v5](https://github.com/jackc/pgx) from 5.5.0 to 5.5.1.
- [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jackc/pgx/compare/v5.5.0...v5.5.1)

---
updated-dependencies:
- dependency-name: github.com/jackc/pgx/v5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
dependabot[bot] 2024-01-03 10:03:16 +00:00 committed by GitHub
parent d685e86432
commit 3ab6214449
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 184 additions and 59 deletions

2
go.mod
View File

@ -34,7 +34,7 @@ require (
github.com/gorilla/feeds v1.1.2 github.com/gorilla/feeds v1.1.2
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.1
github.com/h2non/filetype v1.1.3 github.com/h2non/filetype v1.1.3
github.com/jackc/pgx/v5 v5.5.0 github.com/jackc/pgx/v5 v5.5.1
github.com/microcosm-cc/bluemonday v1.0.26 github.com/microcosm-cc/bluemonday v1.0.26
github.com/miekg/dns v1.1.57 github.com/miekg/dns v1.1.57
github.com/minio/minio-go/v7 v7.0.65 github.com/minio/minio-go/v7 v7.0.65

4
go.sum
View File

@ -346,8 +346,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.0 h1:NxstgwndsTRy7eq9/kqYc/BZh5w2hHJV86wjvO+1xPw= github.com/jackc/pgx/v5 v5.5.1 h1:5I9etrGkLrN+2XPCsi6XLlV5DITbSL/xBZdmAxFcXPI=
github.com/jackc/pgx/v5 v5.5.0/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= github.com/jackc/pgx/v5 v5.5.1/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=

View File

@ -1,3 +1,12 @@
# 5.5.1 (December 9, 2023)
* Add CopyFromFunc helper function. (robford)
* Add PgConn.Deallocate method that uses PostgreSQL protocol Close message.
* pgx uses new PgConn.Deallocate method. This allows deallocating statements to work in a failed transaction. This fixes a case where the prepared statement map could become invalid.
* Fix: Prefer driver.Valuer over json.Marshaler for json fields. (Jacopo)
* Fix: simple protocol SQL sanitizer previously panicked if an invalid $0 placeholder was used. This now returns an error instead. (maksymnevajdev)
* Add pgtype.Numeric.ScanScientific (Eshton Robateau)
# 5.5.0 (November 4, 2023) # 5.5.0 (November 4, 2023)
* Add CollectExactlyOneRow. (Julien GOTTELAND) * Add CollectExactlyOneRow. (Julien GOTTELAND)

View File

@ -92,7 +92,7 @@ See the presentation at Golang Estonia, [PGX Top to Bottom](https://www.youtube.
## Supported Go and PostgreSQL Versions ## Supported Go and PostgreSQL Versions
pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.20 and higher and PostgreSQL 11 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/). pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.20 and higher and PostgreSQL 12 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/).
## Version Policy ## Version Policy

View File

@ -61,6 +61,8 @@ type Batch struct {
} }
// Queue queues a query to batch b. query can be an SQL query or the name of a prepared statement. // Queue queues a query to batch b. query can be an SQL query or the name of a prepared statement.
// The only pgx option argument that is supported is QueryRewriter. Queries are executed using the
// connection's DefaultQueryExecMode.
func (b *Batch) Queue(query string, arguments ...any) *QueuedQuery { func (b *Batch) Queue(query string, arguments ...any) *QueuedQuery {
qq := &QueuedQuery{ qq := &QueuedQuery{
query: query, query: query,

View File

@ -338,17 +338,26 @@ func (c *Conn) Prepare(ctx context.Context, name, sql string) (sd *pgconn.Statem
return sd, nil return sd, nil
} }
// Deallocate releases a prepared statement. // Deallocate releases a prepared statement. Calling Deallocate on a non-existent prepared statement will succeed.
func (c *Conn) Deallocate(ctx context.Context, name string) error { func (c *Conn) Deallocate(ctx context.Context, name string) error {
var psName string var psName string
if sd, ok := c.preparedStatements[name]; ok { sd := c.preparedStatements[name]
delete(c.preparedStatements, name) if sd != nil {
psName = sd.Name psName = sd.Name
} else { } else {
psName = name psName = name
} }
_, err := c.pgConn.Exec(ctx, "deallocate "+quoteIdentifier(psName)).ReadAll()
return err err := c.pgConn.Deallocate(ctx, psName)
if err != nil {
return err
}
if sd != nil {
delete(c.preparedStatements, name)
}
return nil
} }
// DeallocateAll releases all previously prepared statements from the server and client, where it also resets the statement and description cache. // DeallocateAll releases all previously prepared statements from the server and client, where it also resets the statement and description cache.
@ -466,7 +475,7 @@ optionLoop:
if queryRewriter != nil { if queryRewriter != nil {
sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments) sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments)
if err != nil { if err != nil {
return pgconn.CommandTag{}, fmt.Errorf("rewrite query failed: %v", err) return pgconn.CommandTag{}, fmt.Errorf("rewrite query failed: %w", err)
} }
} }
@ -733,7 +742,7 @@ optionLoop:
sql, args, err = queryRewriter.RewriteQuery(ctx, c, sql, args) sql, args, err = queryRewriter.RewriteQuery(ctx, c, sql, args)
if err != nil { if err != nil {
rows := c.getRows(ctx, originalSQL, originalArgs) rows := c.getRows(ctx, originalSQL, originalArgs)
err = fmt.Errorf("rewrite query failed: %v", err) err = fmt.Errorf("rewrite query failed: %w", err)
rows.fatal(err) rows.fatal(err)
return rows, err return rows, err
} }
@ -893,8 +902,6 @@ func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
return &batchResults{ctx: ctx, conn: c, err: err} return &batchResults{ctx: ctx, conn: c, err: err}
} }
mode := c.config.DefaultQueryExecMode
for _, bi := range b.queuedQueries { for _, bi := range b.queuedQueries {
var queryRewriter QueryRewriter var queryRewriter QueryRewriter
sql := bi.query sql := bi.query
@ -902,6 +909,7 @@ func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
optionLoop: optionLoop:
for len(arguments) > 0 { for len(arguments) > 0 {
// Update Batch.Queue function comment when additional options are implemented
switch arg := arguments[0].(type) { switch arg := arguments[0].(type) {
case QueryRewriter: case QueryRewriter:
queryRewriter = arg queryRewriter = arg
@ -915,7 +923,7 @@ func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
var err error var err error
sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments) sql, arguments, err = queryRewriter.RewriteQuery(ctx, c, sql, arguments)
if err != nil { if err != nil {
return &batchResults{ctx: ctx, conn: c, err: fmt.Errorf("rewrite query failed: %v", err)} return &batchResults{ctx: ctx, conn: c, err: fmt.Errorf("rewrite query failed: %w", err)}
} }
} }
@ -923,6 +931,8 @@ func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
bi.arguments = arguments bi.arguments = arguments
} }
// TODO: changing mode per batch? Update Batch.Queue function comment when implemented
mode := c.config.DefaultQueryExecMode
if mode == QueryExecModeSimpleProtocol { if mode == QueryExecModeSimpleProtocol {
return c.sendBatchQueryExecModeSimpleProtocol(ctx, b) return c.sendBatchQueryExecModeSimpleProtocol(ctx, b)
} }

View File

@ -64,6 +64,33 @@ func (cts *copyFromSlice) Err() error {
return cts.err return cts.err
} }
// CopyFromFunc returns a CopyFromSource interface that relies on nxtf for values.
// nxtf returns rows until it either signals an 'end of data' by returning row=nil and err=nil,
// or it returns an error. If nxtf returns an error, the copy is aborted.
func CopyFromFunc(nxtf func() (row []any, err error)) CopyFromSource {
return &copyFromFunc{next: nxtf}
}
type copyFromFunc struct {
next func() ([]any, error)
valueRow []any
err error
}
func (g *copyFromFunc) Next() bool {
g.valueRow, g.err = g.next()
// only return true if valueRow exists and no error
return g.valueRow != nil && g.err == nil
}
func (g *copyFromFunc) Values() ([]any, error) {
return g.valueRow, g.err
}
func (g *copyFromFunc) Err() error {
return g.err
}
// CopyFromSource is the interface used by *Conn.CopyFrom as the source for copy data. // CopyFromSource is the interface used by *Conn.CopyFrom as the source for copy data.
type CopyFromSource interface { type CopyFromSource interface {
// Next returns true if there is another row and makes the next row data // Next returns true if there is another row and makes the next row data

View File

@ -36,7 +36,7 @@ func (eqb *ExtendedQueryBuilder) Build(m *pgtype.Map, sd *pgconn.StatementDescri
for i := range args { for i := range args {
err := eqb.appendParam(m, sd.ParamOIDs[i], -1, args[i]) err := eqb.appendParam(m, sd.ParamOIDs[i], -1, args[i])
if err != nil { if err != nil {
err = fmt.Errorf("failed to encode args[%d]: %v", i, err) err = fmt.Errorf("failed to encode args[%d]: %w", i, err)
return err return err
} }
} }

View File

@ -35,6 +35,11 @@ func (q *Query) Sanitize(args ...any) (string, error) {
str = part str = part
case int: case int:
argIdx := part - 1 argIdx := part - 1
if argIdx < 0 {
return "", fmt.Errorf("first sql argument must be > 0")
}
if argIdx >= len(args) { if argIdx >= len(args) {
return "", fmt.Errorf("insufficient arguments") return "", fmt.Errorf("insufficient arguments")
} }

View File

@ -813,6 +813,9 @@ type StatementDescription struct {
// Prepare creates a prepared statement. If the name is empty, the anonymous prepared statement will be used. This // Prepare creates a prepared statement. If the name is empty, the anonymous prepared statement will be used. This
// allows Prepare to also to describe statements without creating a server-side prepared statement. // allows Prepare to also to describe statements without creating a server-side prepared statement.
//
// Prepare does not send a PREPARE statement to the server. It uses the PostgreSQL Parse and Describe protocol messages
// directly.
func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs []uint32) (*StatementDescription, error) { func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs []uint32) (*StatementDescription, error) {
if err := pgConn.lock(); err != nil { if err := pgConn.lock(); err != nil {
return nil, err return nil, err
@ -869,6 +872,52 @@ readloop:
return psd, nil return psd, nil
} }
// Deallocate deallocates a prepared statement.
//
// Deallocate does not send a DEALLOCATE statement to the server. It uses the PostgreSQL Close protocol message
// directly. This has slightly different behavior than executing DEALLOCATE statement.
// - Deallocate can succeed in an aborted transaction.
// - Deallocating a non-existent prepared statement is not an error.
func (pgConn *PgConn) Deallocate(ctx context.Context, name string) error {
if err := pgConn.lock(); err != nil {
return err
}
defer pgConn.unlock()
if ctx != context.Background() {
select {
case <-ctx.Done():
return newContextAlreadyDoneError(ctx)
default:
}
pgConn.contextWatcher.Watch(ctx)
defer pgConn.contextWatcher.Unwatch()
}
pgConn.frontend.SendClose(&pgproto3.Close{ObjectType: 'S', Name: name})
pgConn.frontend.SendSync(&pgproto3.Sync{})
err := pgConn.flushWithPotentialWriteReadDeadlock()
if err != nil {
pgConn.asyncClose()
return err
}
for {
msg, err := pgConn.receiveMessage()
if err != nil {
pgConn.asyncClose()
return normalizeTimeoutError(ctx, err)
}
switch msg := msg.(type) {
case *pgproto3.ErrorResponse:
return ErrorResponseToPgError(msg)
case *pgproto3.ReadyForQuery:
return nil
}
}
}
// ErrorResponseToPgError converts a wire protocol error message to a *PgError. // ErrorResponseToPgError converts a wire protocol error message to a *PgError.
func ErrorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError { func ErrorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError {
return &PgError{ return &PgError{

View File

@ -110,7 +110,7 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
r, _, err := buf.ReadRune() r, _, err := buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
var explicitDimensions []ArrayDimension var explicitDimensions []ArrayDimension
@ -122,7 +122,7 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
for { for {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
if r == '=' { if r == '=' {
@ -133,12 +133,12 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
lower, err := arrayParseInteger(buf) lower, err := arrayParseInteger(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
if r != ':' { if r != ':' {
@ -147,12 +147,12 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
upper, err := arrayParseInteger(buf) upper, err := arrayParseInteger(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
if r != ']' { if r != ']' {
@ -164,12 +164,12 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
} }
if r != '{' { if r != '{' {
return nil, fmt.Errorf("invalid array, expected '{': %v", err) return nil, fmt.Errorf("invalid array, expected '{' got %v", r)
} }
implicitDimensions := []ArrayDimension{{LowerBound: 1, Length: 0}} implicitDimensions := []ArrayDimension{{LowerBound: 1, Length: 0}}
@ -178,7 +178,7 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
for { for {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
if r == '{' { if r == '{' {
@ -195,7 +195,7 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
for { for {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
switch r { switch r {
@ -214,7 +214,7 @@ func parseUntypedTextArray(src string) (*untypedTextArray, error) {
buf.UnreadRune() buf.UnreadRune()
value, quoted, err := arrayParseValue(buf) value, quoted, err := arrayParseValue(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array value: %v", err) return nil, fmt.Errorf("invalid array value: %w", err)
} }
if currentDim == counterDim { if currentDim == counterDim {
implicitDimensions[currentDim].Length++ implicitDimensions[currentDim].Length++

View File

@ -231,7 +231,7 @@ func (w *uint64Wrapper) ScanNumeric(v Numeric) error {
bi, err := v.toBigInt() bi, err := v.toBigInt()
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into *uint64: %v", err) return fmt.Errorf("cannot scan into *uint64: %w", err)
} }
if !bi.IsUint64() { if !bi.IsUint64() {
@ -284,7 +284,7 @@ func (w *uintWrapper) ScanNumeric(v Numeric) error {
bi, err := v.toBigInt() bi, err := v.toBigInt()
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into *uint: %v", err) return fmt.Errorf("cannot scan into *uint: %w", err)
} }
if !bi.IsUint64() { if !bi.IsUint64() {

View File

@ -282,17 +282,17 @@ func (scanPlanTextAnyToDateScanner) Scan(src []byte, dst any) error {
if match != nil { if match != nil {
year, err := strconv.ParseInt(match[1], 10, 32) year, err := strconv.ParseInt(match[1], 10, 32)
if err != nil { if err != nil {
return fmt.Errorf("BUG: cannot parse date that regexp matched (year): %v", err) return fmt.Errorf("BUG: cannot parse date that regexp matched (year): %w", err)
} }
month, err := strconv.ParseInt(match[2], 10, 32) month, err := strconv.ParseInt(match[2], 10, 32)
if err != nil { if err != nil {
return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %v", err) return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %w", err)
} }
day, err := strconv.ParseInt(match[3], 10, 32) day, err := strconv.ParseInt(match[3], 10, 32)
if err != nil { if err != nil {
return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %v", err) return fmt.Errorf("BUG: cannot parse date that regexp matched (month): %w", err)
} }
// BC matched // BC matched

View File

@ -25,18 +25,21 @@ func (c JSONCodec) PlanEncode(m *Map, oid uint32, format int16, value any) Encod
case []byte: case []byte:
return encodePlanJSONCodecEitherFormatByteSlice{} return encodePlanJSONCodecEitherFormatByteSlice{}
// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
//
// https://github.com/jackc/pgx/issues/1430
//
// Check for driver.Valuer must come before json.Marshaler so that it is guaranteed to beused
// when both are implemented https://github.com/jackc/pgx/issues/1805
case driver.Valuer:
return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
// Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be // Must come before trying wrap encode plans because a pointer to a struct may be unwrapped to a struct that can be
// marshalled. // marshalled.
// //
// https://github.com/jackc/pgx/issues/1681 // https://github.com/jackc/pgx/issues/1681
case json.Marshaler: case json.Marshaler:
return encodePlanJSONCodecEitherFormatMarshal{} return encodePlanJSONCodecEitherFormatMarshal{}
// Cannot rely on driver.Valuer being handled later because anything can be marshalled.
//
// https://github.com/jackc/pgx/issues/1430
case driver.Valuer:
return &encodePlanDriverValuer{m: m, oid: oid, formatCode: format}
} }
// Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the // Because anything can be marshalled the normal wrapping in Map.PlanScan doesn't get a chance to run. So try the

View File

@ -339,18 +339,18 @@ func parseUntypedTextMultirange(src []byte) ([]string, error) {
r, _, err := buf.ReadRune() r, _, err := buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid array: %v", err) return nil, fmt.Errorf("invalid array: %w", err)
} }
if r != '{' { if r != '{' {
return nil, fmt.Errorf("invalid multirange, expected '{': %v", err) return nil, fmt.Errorf("invalid multirange, expected '{' got %v", r)
} }
parseValueLoop: parseValueLoop:
for { for {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid multirange: %v", err) return nil, fmt.Errorf("invalid multirange: %w", err)
} }
switch r { switch r {
@ -361,7 +361,7 @@ parseValueLoop:
buf.UnreadRune() buf.UnreadRune()
value, err := parseRange(buf) value, err := parseRange(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid multirange value: %v", err) return nil, fmt.Errorf("invalid multirange value: %w", err)
} }
elements = append(elements, value) elements = append(elements, value)
} }

View File

@ -119,6 +119,26 @@ func (n Numeric) Int64Value() (Int8, error) {
return Int8{Int64: bi.Int64(), Valid: true}, nil return Int8{Int64: bi.Int64(), Valid: true}, nil
} }
func (n *Numeric) ScanScientific(src string) error {
if !strings.ContainsAny("eE", src) {
return scanPlanTextAnyToNumericScanner{}.Scan([]byte(src), n)
}
if bigF, ok := new(big.Float).SetString(string(src)); ok {
smallF, _ := bigF.Float64()
src = strconv.FormatFloat(smallF, 'f', -1, 64)
}
num, exp, err := parseNumericString(src)
if err != nil {
return err
}
*n = Numeric{Int: num, Exp: exp, Valid: true}
return nil
}
func (n *Numeric) toBigInt() (*big.Int, error) { func (n *Numeric) toBigInt() (*big.Int, error) {
if n.Exp == 0 { if n.Exp == 0 {
return n.Int, nil return n.Int, nil

View File

@ -40,7 +40,7 @@ func parseUntypedTextRange(src string) (*untypedTextRange, error) {
r, _, err := buf.ReadRune() r, _, err := buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid lower bound: %v", err) return nil, fmt.Errorf("invalid lower bound: %w", err)
} }
switch r { switch r {
case '(': case '(':
@ -53,7 +53,7 @@ func parseUntypedTextRange(src string) (*untypedTextRange, error) {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid lower value: %v", err) return nil, fmt.Errorf("invalid lower value: %w", err)
} }
buf.UnreadRune() buf.UnreadRune()
@ -62,13 +62,13 @@ func parseUntypedTextRange(src string) (*untypedTextRange, error) {
} else { } else {
utr.Lower, err = rangeParseValue(buf) utr.Lower, err = rangeParseValue(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid lower value: %v", err) return nil, fmt.Errorf("invalid lower value: %w", err)
} }
} }
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("missing range separator: %v", err) return nil, fmt.Errorf("missing range separator: %w", err)
} }
if r != ',' { if r != ',' {
return nil, fmt.Errorf("missing range separator: %v", r) return nil, fmt.Errorf("missing range separator: %v", r)
@ -76,7 +76,7 @@ func parseUntypedTextRange(src string) (*untypedTextRange, error) {
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid upper value: %v", err) return nil, fmt.Errorf("invalid upper value: %w", err)
} }
if r == ')' || r == ']' { if r == ')' || r == ']' {
@ -85,12 +85,12 @@ func parseUntypedTextRange(src string) (*untypedTextRange, error) {
buf.UnreadRune() buf.UnreadRune()
utr.Upper, err = rangeParseValue(buf) utr.Upper, err = rangeParseValue(buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid upper value: %v", err) return nil, fmt.Errorf("invalid upper value: %w", err)
} }
r, _, err = buf.ReadRune() r, _, err = buf.ReadRune()
if err != nil { if err != nil {
return nil, fmt.Errorf("missing upper bound: %v", err) return nil, fmt.Errorf("missing upper bound: %w", err)
} }
switch r { switch r {
case ')': case ')':

View File

@ -120,7 +120,7 @@ func (plan *encodePlanRangeCodecRangeValuerToBinary) Encode(value any, buf []byt
buf, err = lowerPlan.Encode(lower, buf) buf, err = lowerPlan.Encode(lower, buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to encode %v as element of range: %v", lower, err) return nil, fmt.Errorf("failed to encode %v as element of range: %w", lower, err)
} }
if buf == nil { if buf == nil {
return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded") return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
@ -144,7 +144,7 @@ func (plan *encodePlanRangeCodecRangeValuerToBinary) Encode(value any, buf []byt
buf, err = upperPlan.Encode(upper, buf) buf, err = upperPlan.Encode(upper, buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to encode %v as element of range: %v", upper, err) return nil, fmt.Errorf("failed to encode %v as element of range: %w", upper, err)
} }
if buf == nil { if buf == nil {
return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded") return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
@ -194,7 +194,7 @@ func (plan *encodePlanRangeCodecRangeValuerToText) Encode(value any, buf []byte)
buf, err = lowerPlan.Encode(lower, buf) buf, err = lowerPlan.Encode(lower, buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to encode %v as element of range: %v", lower, err) return nil, fmt.Errorf("failed to encode %v as element of range: %w", lower, err)
} }
if buf == nil { if buf == nil {
return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded") return nil, fmt.Errorf("Lower cannot be NULL unless LowerType is Unbounded")
@ -215,7 +215,7 @@ func (plan *encodePlanRangeCodecRangeValuerToText) Encode(value any, buf []byte)
buf, err = upperPlan.Encode(upper, buf) buf, err = upperPlan.Encode(upper, buf)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to encode %v as element of range: %v", upper, err) return nil, fmt.Errorf("failed to encode %v as element of range: %w", upper, err)
} }
if buf == nil { if buf == nil {
return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded") return nil, fmt.Errorf("Upper cannot be NULL unless UpperType is Unbounded")
@ -282,7 +282,7 @@ func (plan *scanPlanBinaryRangeToRangeScanner) Scan(src []byte, target any) erro
err = lowerPlan.Scan(ubr.Lower, lowerTarget) err = lowerPlan.Scan(ubr.Lower, lowerTarget)
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into %v from range element: %v", lowerTarget, err) return fmt.Errorf("cannot scan into %v from range element: %w", lowerTarget, err)
} }
} }
@ -294,7 +294,7 @@ func (plan *scanPlanBinaryRangeToRangeScanner) Scan(src []byte, target any) erro
err = upperPlan.Scan(ubr.Upper, upperTarget) err = upperPlan.Scan(ubr.Upper, upperTarget)
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into %v from range element: %v", upperTarget, err) return fmt.Errorf("cannot scan into %v from range element: %w", upperTarget, err)
} }
} }
@ -332,7 +332,7 @@ func (plan *scanPlanTextRangeToRangeScanner) Scan(src []byte, target any) error
err = lowerPlan.Scan([]byte(utr.Lower), lowerTarget) err = lowerPlan.Scan([]byte(utr.Lower), lowerTarget)
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into %v from range element: %v", lowerTarget, err) return fmt.Errorf("cannot scan into %v from range element: %w", lowerTarget, err)
} }
} }
@ -344,7 +344,7 @@ func (plan *scanPlanTextRangeToRangeScanner) Scan(src []byte, target any) error
err = upperPlan.Scan([]byte(utr.Upper), upperTarget) err = upperPlan.Scan([]byte(utr.Upper), upperTarget)
if err != nil { if err != nil {
return fmt.Errorf("cannot scan into %v from range element: %v", upperTarget, err) return fmt.Errorf("cannot scan into %v from range element: %w", upperTarget, err)
} }
} }

View File

@ -31,7 +31,7 @@
// with sql.Open. // with sql.Open.
// //
// connConfig, _ := pgx.ParseConfig(os.Getenv("DATABASE_URL")) // connConfig, _ := pgx.ParseConfig(os.Getenv("DATABASE_URL"))
// connConfig.Logger = myLogger // connConfig.Tracer = &tracelog.TraceLog{Logger: myLogger, LogLevel: tracelog.LogLevelInfo}
// connStr := stdlib.RegisterConnConfig(connConfig) // connStr := stdlib.RegisterConnConfig(connConfig)
// db, _ := sql.Open("pgx", connStr) // db, _ := sql.Open("pgx", connStr)
// //
@ -840,7 +840,7 @@ func (r *Rows) Next(dest []driver.Value) error {
var err error var err error
dest[i], err = r.valueFuncs[i](rv) dest[i], err = r.valueFuncs[i](rv)
if err != nil { if err != nil {
return fmt.Errorf("convert field %d failed: %v", i, err) return fmt.Errorf("convert field %d failed: %w", i, err)
} }
} else { } else {
dest[i] = nil dest[i] = nil

2
vendor/modules.txt vendored
View File

@ -322,7 +322,7 @@ github.com/jackc/pgpassfile
# github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a # github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a
## explicit; go 1.14 ## explicit; go 1.14
github.com/jackc/pgservicefile github.com/jackc/pgservicefile
# github.com/jackc/pgx/v5 v5.5.0 # github.com/jackc/pgx/v5 v5.5.1
## explicit; go 1.19 ## explicit; go 1.19
github.com/jackc/pgx/v5 github.com/jackc/pgx/v5
github.com/jackc/pgx/v5/internal/anynil github.com/jackc/pgx/v5/internal/anynil