From aabe5538a830c862ee07e2f2ea02731431403811 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 9 May 2020 23:57:20 -0500 Subject: [PATCH] Optimize large result sets --- go.mod | 2 +- go.sum | 2 ++ rows.go | 42 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 17804c68..ef6e1568 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/jackc/pgconn v1.5.0 github.com/jackc/pgio v1.0.0 github.com/jackc/pgproto3/v2 v2.0.1 - github.com/jackc/pgtype v1.3.1-0.20200508211315-97bbe6ae20e2 + github.com/jackc/pgtype v1.3.1-0.20200510045248-7e66ab1e146c github.com/jackc/puddle v1.1.1 github.com/rs/zerolog v1.15.0 github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc diff --git a/go.sum b/go.sum index 6cdc2fe3..84abfb55 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/jackc/pgtype v1.3.1-0.20200505182314-3b7c47a2a7da h1:ZbfsOjqJ1nHsryU0 github.com/jackc/pgtype v1.3.1-0.20200505182314-3b7c47a2a7da/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200508211315-97bbe6ae20e2 h1:Y6cErz3hUojOwnjUEWoZPRCBQcB7avM9ntGiYkB0wJo= github.com/jackc/pgtype v1.3.1-0.20200508211315-97bbe6ae20e2/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= +github.com/jackc/pgtype v1.3.1-0.20200510045248-7e66ab1e146c h1:id5j6vOwHhbR7BYdGyb0sDMQjNsKTO+mXWaJxiwKu5M= +github.com/jackc/pgtype v1.3.1-0.20200510045248-7e66ab1e146c/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= diff --git a/rows.go b/rows.go index c16a64bd..91e231e3 100644 --- a/rows.go +++ b/rows.go @@ -109,6 +109,9 @@ type connRows struct { resultReader *pgconn.ResultReader multiResultReader *pgconn.MultiResultReader + + scanPlans []pgtype.ScanPlan + dstValues []interface{} } func (rows *connRows) FieldDescriptions() []pgproto3.FieldDescription { @@ -184,11 +187,43 @@ func (rows *connRows) Next() bool { } func (rows *connRows) Scan(dest ...interface{}) error { - err := ScanRow(rows.connInfo, rows.FieldDescriptions(), rows.values, dest...) - if err != nil { + ci := rows.connInfo + fieldDescriptions := rows.FieldDescriptions() + values := rows.values + + if len(fieldDescriptions) != len(values) { + err := errors.Errorf("number of field descriptions must equal number of values, got %d and %d", len(fieldDescriptions), len(values)) rows.fatal(err) return err } + if len(fieldDescriptions) != len(dest) { + err := errors.Errorf("number of field descriptions must equal number of destinations, got %d and %d", len(fieldDescriptions), len(dest)) + rows.fatal(err) + return err + } + + if rows.scanPlans == nil { + rows.scanPlans = make([]pgtype.ScanPlan, len(values)) + rows.dstValues = make([]interface{}, len(values)) + } + + for i, dst := range dest { + if dst == nil { + continue + } + + if dst != rows.dstValues[i] { + rows.scanPlans[i] = ci.PlanScan(fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], dest[i]) + rows.dstValues[i] = dst + } + + err := rows.scanPlans[i].Scan(ci, fieldDescriptions[i].DataTypeOID, fieldDescriptions[i].Format, values[i], dst) + if err != nil { + err = scanArgError{col: i, err: err} + rows.fatal(err) + return err + } + } return nil } @@ -278,8 +313,7 @@ func (e scanArgError) Error() string { return fmt.Sprintf("can't scan into dest[%d]: %v", e.col, e.err) } -// ScanRow decodes raw row data into dest. This is a low level function used internally to to implement the Rows -// interface Scan method. It can be used to scan rows read from the lower level pgconn interface. +// ScanRow decodes raw row data into dest. It can be used to scan rows read from the lower level pgconn interface. // // connInfo - OID to Go type mapping. // fieldDescriptions - OID and format of values