From 76946fb5a39fb222724cbac50701b678ee6d53f6 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Thu, 7 Jul 2022 20:29:04 -0500 Subject: [PATCH] Replace QueryFunc with ForEachScannedRow --- CHANGELOG.md | 5 + batch.go | 34 --- batch_test.go | 3 +- conn.go | 65 +---- doc.go | 29 +- pgtype/bytea.go | 4 +- pgtype/integration_benchmark_test.go | 351 +++++++++-------------- pgtype/integration_benchmark_test.go.erb | 10 +- pgxpool/batch_results.go | 8 - pgxpool/conn.go | 4 - pgxpool/pool.go | 10 - pgxpool/tx.go | 4 - query_test.go | 99 ------- rows.go | 25 ++ rows_test.go | 100 +++++++ tx.go | 19 -- 16 files changed, 301 insertions(+), 469 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a51ef9bd..a0b95203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,6 +134,11 @@ allows arbitrary rewriting of query SQL and arguments. ## RowScanner Interface The `RowScanner` interface allows a single argument to Rows.Scan to scan the entire row. + +## QueryFunc Replaced + +`QueryFunc` has been replaced by using `ForEachScannedRow`. + ## 3rd Party Logger Integration All integrations with 3rd party loggers have been extracted to separate repositories. This trims the pgx dependency diff --git a/batch.go b/batch.go index 6fd61295..21830a1f 100644 --- a/batch.go +++ b/batch.go @@ -42,9 +42,6 @@ type BatchResults interface { // QueryRow reads the results from the next query in the batch as if the query has been sent with Conn.QueryRow. QueryRow() Row - // QueryFunc reads the results from the next query in the batch as if the query has been sent with Conn.QueryFunc. - QueryFunc(scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) - // Close closes the batch operation. This must be called before the underlying connection can be used again. Any error // that occurred during a batch operation may have made it impossible to resyncronize the connection with the server. // In this case the underlying connection will have been closed. Close is safe to call multiple times. @@ -148,37 +145,6 @@ func (br *batchResults) Query() (Rows, error) { return rows, nil } -// QueryFunc reads the results from the next query in the batch as if the query has been sent with Conn.QueryFunc. -func (br *batchResults) QueryFunc(scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) { - if br.closed { - return pgconn.CommandTag{}, fmt.Errorf("batch already closed") - } - - rows, err := br.Query() - if err != nil { - return pgconn.CommandTag{}, err - } - defer rows.Close() - - for rows.Next() { - err = rows.Scan(scans...) - if err != nil { - return pgconn.CommandTag{}, err - } - - err = f(rows) - if err != nil { - return pgconn.CommandTag{}, err - } - } - - if err := rows.Err(); err != nil { - return pgconn.CommandTag{}, err - } - - return rows.CommandTag(), nil -} - // QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow. func (br *batchResults) QueryRow() Row { rows, _ := br.Query() diff --git a/batch_test.go b/batch_test.go index 96cf61c2..abe9f915 100644 --- a/batch_test.go +++ b/batch_test.go @@ -108,7 +108,8 @@ func TestConnSendBatch(t *testing.T) { } rowCount = 0 - _, err = br.QueryFunc([]any{&id, &description, &amount}, func(pgx.QueryFuncRow) error { + rows, _ = br.Query() + _, err = pgx.ForEachScannedRow(rows, []any{&id, &description, &amount}, func() error { if id != selectFromLedgerExpectedRows[rowCount].id { t.Errorf("id => %v, want %v", id, selectFromLedgerExpectedRows[rowCount].id) } diff --git a/conn.go b/conn.go index ba2ba578..d8ab21d7 100644 --- a/conn.go +++ b/conn.go @@ -12,7 +12,6 @@ import ( "github.com/jackc/pgx/v5/internal/sanitize" "github.com/jackc/pgx/v5/internal/stmtcache" "github.com/jackc/pgx/v5/pgconn" - "github.com/jackc/pgx/v5/pgproto3" "github.com/jackc/pgx/v5/pgtype" ) @@ -764,48 +763,6 @@ func (c *Conn) QueryRow(ctx context.Context, sql string, args ...any) Row { return (*connRow)(rows.(*baseRows)) } -// QueryFuncRow is the argument to the QueryFunc callback function. -// -// QueryFuncRow is an interface instead of a struct to allow tests to mock QueryFunc. However, adding a method to an -// interface is technically a breaking change. Because of this the QueryFuncRow interface is partially excluded from -// semantic version requirements. Methods will not be removed or changed, but new methods may be added. -type QueryFuncRow interface { - FieldDescriptions() []pgproto3.FieldDescription - - // RawValues returns the unparsed bytes of the row values. The returned data is only valid during the current - // function call. - RawValues() [][]byte -} - -// QueryFunc executes sql with args. For each row returned by the query the values will scanned into the elements of -// scans and f will be called. If any row fails to scan or f returns an error the query will be aborted and the error -// will be returned. -func (c *Conn) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) { - rows, err := c.Query(ctx, sql, args...) - if err != nil { - return pgconn.CommandTag{}, err - } - defer rows.Close() - - for rows.Next() { - err = rows.Scan(scans...) - if err != nil { - return pgconn.CommandTag{}, err - } - - err = f(rows) - if err != nil { - return pgconn.CommandTag{}, err - } - } - - if err := rows.Err(); err != nil { - return pgconn.CommandTag{}, err - } - - return rows.CommandTag(), nil -} - // SendBatch sends all queued queries to the server at once. All queries are run in an implicit transaction unless // explicit transaction control statements are executed. The returned BatchResults must be closed before the connection // is used again. @@ -1038,20 +995,20 @@ func (c *Conn) getCompositeFields(ctx context.Context, oid uint32) ([]pgtype.Com var fields []pgtype.CompositeCodecField var fieldName string var fieldOID uint32 - _, err = c.QueryFunc(ctx, `select attname, atttypid + rows, _ := c.Query(ctx, `select attname, atttypid from pg_attribute where attrelid=$1 order by attnum`, - []any{typrelid}, - []any{&fieldName, &fieldOID}, - func(qfr QueryFuncRow) error { - dt, ok := c.TypeMap().TypeForOID(fieldOID) - if !ok { - return fmt.Errorf("unknown composite type field OID: %v", fieldOID) - } - fields = append(fields, pgtype.CompositeCodecField{Name: fieldName, Type: dt}) - return nil - }) + typrelid, + ) + _, err = ForEachScannedRow(rows, []any{&fieldName, &fieldOID}, func() error { + dt, ok := c.TypeMap().TypeForOID(fieldOID) + if !ok { + return fmt.Errorf("unknown composite type field OID: %v", fieldOID) + } + fields = append(fields, pgtype.CompositeCodecField{Name: fieldName, Type: dt}) + return nil + }) if err != nil { return nil, err } diff --git a/doc.go b/doc.go index 660cf5a3..2e779dbb 100644 --- a/doc.go +++ b/doc.go @@ -63,6 +63,18 @@ pgx implements Query and Scan in the familiar database/sql style. // No errors found - do something with sum +ForEachScannedRow can be used to execute a callback function for every row. This is often easier than iterating over rows directly. + + var sum, n int32 + rows, _ := conn.Query(context.Background(), "select generate_series(1,$1)", 10) + _, err := pgx.ForEachScannedRow(rows, []any{&n}, func(pgx.QueryFuncRow) error { + sum += n + return nil + }) + if err != nil { + return err + } + pgx also implements QueryRow in the same style as database/sql. var name string @@ -82,23 +94,6 @@ Use Exec to execute a query that does not return a result set. return errors.New("No row found to delete") } -QueryFunc can be used to execute a callback function for every row. This is often easier to use than Query. - - var sum, n int32 - _, err = conn.QueryFunc( - context.Background(), - "select generate_series(1,$1)", - []any{10}, - []any{&n}, - func(pgx.QueryFuncRow) error { - sum += n - return nil - }, - ) - if err != nil { - return err - } - Base Type Mapping pgx maps between all common base types directly between Go and PostgreSQL. In particular: diff --git a/pgtype/bytea.go b/pgtype/bytea.go index 51994005..2e067672 100644 --- a/pgtype/bytea.go +++ b/pgtype/bytea.go @@ -17,8 +17,8 @@ type BytesValuer interface { } // DriverBytes is a byte slice that holds a reference to memory owned by the driver. It is only valid from the time it -// is scanned until Rows.Next or Rows.Close is called. It is safe to use in a function passed to QueryFunc. It is never -// safe to use DriverBytes with QueryRow as Row.Scan internally calls Rows.Close before returning. +// is scanned until Rows.Next or Rows.Close is called. It is never safe to use DriverBytes with QueryRow as Row.Scan +// internally calls Rows.Close before returning. type DriverBytes []byte func (b *DriverBytes) ScanBytes(v []byte) error { diff --git a/pgtype/integration_benchmark_test.go b/pgtype/integration_benchmark_test.go index 624c29ea..4ba8b9b5 100644 --- a/pgtype/integration_benchmark_test.go +++ b/pgtype/integration_benchmark_test.go @@ -1,4 +1,3 @@ -// Do not edit. Generated from pgtype/integration_benchmark_test.go.erb package pgtype_test import ( @@ -14,13 +13,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int16_1_rows_1_columns(b *test b.ResetTimer() var v [1]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -33,13 +31,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int16_1_rows_1_columns(b *te b.ResetTimer() var v [1]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -52,13 +49,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int16_1_rows_10_columns(b *tes b.ResetTimer() var v [10]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -71,13 +67,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int16_1_rows_10_columns(b *t b.ResetTimer() var v [10]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -90,13 +85,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int16_10_rows_1_columns(b *tes b.ResetTimer() var v [1]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -109,13 +103,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int16_10_rows_1_columns(b *t b.ResetTimer() var v [1]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -128,13 +121,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int16_100_rows_10_columns(b *t b.ResetTimer() var v [10]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -147,13 +139,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int16_100_rows_10_columns(b b.ResetTimer() var v [10]int16 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -166,13 +157,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int32_1_rows_1_columns(b *test b.ResetTimer() var v [1]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -185,13 +175,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int32_1_rows_1_columns(b *te b.ResetTimer() var v [1]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -204,13 +193,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int32_1_rows_10_columns(b *tes b.ResetTimer() var v [10]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -223,13 +211,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int32_1_rows_10_columns(b *t b.ResetTimer() var v [10]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -242,13 +229,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int32_10_rows_1_columns(b *tes b.ResetTimer() var v [1]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -261,13 +247,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int32_10_rows_1_columns(b *t b.ResetTimer() var v [1]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -280,13 +265,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int32_100_rows_10_columns(b *t b.ResetTimer() var v [10]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -299,13 +283,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int32_100_rows_10_columns(b b.ResetTimer() var v [10]int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -318,13 +301,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int64_1_rows_1_columns(b *test b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -337,13 +319,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int64_1_rows_1_columns(b *te b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -356,13 +337,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int64_1_rows_10_columns(b *tes b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -375,13 +355,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int64_1_rows_10_columns(b *t b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -394,13 +373,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int64_10_rows_1_columns(b *tes b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -413,13 +391,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int64_10_rows_1_columns(b *t b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -432,13 +409,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_int64_100_rows_10_columns(b *t b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -451,13 +427,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_int64_100_rows_10_columns(b b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -470,13 +445,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_uint64_1_rows_1_columns(b *tes b.ResetTimer() var v [1]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -489,13 +463,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_uint64_1_rows_1_columns(b *t b.ResetTimer() var v [1]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -508,13 +481,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_uint64_1_rows_10_columns(b *te b.ResetTimer() var v [10]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -527,13 +499,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_uint64_1_rows_10_columns(b * b.ResetTimer() var v [10]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -546,13 +517,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_uint64_10_rows_1_columns(b *te b.ResetTimer() var v [1]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -565,13 +535,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_uint64_10_rows_1_columns(b * b.ResetTimer() var v [1]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -584,13 +553,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_uint64_100_rows_10_columns(b * b.ResetTimer() var v [10]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -603,13 +571,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_uint64_100_rows_10_columns(b b.ResetTimer() var v [10]uint64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -622,13 +589,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_pgtype_Int4_1_rows_1_columns(b b.ResetTimer() var v [1]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -641,13 +607,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_pgtype_Int4_1_rows_1_columns b.ResetTimer() var v [1]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -660,13 +625,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_pgtype_Int4_1_rows_10_columns( b.ResetTimer() var v [10]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -679,13 +643,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_pgtype_Int4_1_rows_10_column b.ResetTimer() var v [10]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -698,13 +661,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_pgtype_Int4_10_rows_1_columns( b.ResetTimer() var v [1]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -717,13 +679,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_pgtype_Int4_10_rows_1_column b.ResetTimer() var v [1]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -736,13 +697,12 @@ func BenchmarkQueryTextFormatDecode_PG_int4_to_Go_pgtype_Int4_100_rows_10_column b.ResetTimer() var v [10]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -755,13 +715,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_int4_to_Go_pgtype_Int4_100_rows_10_colu b.ResetTimer() var v [10]pgtype.Int4 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::int4 + 0, n::int4 + 1, n::int4 + 2, n::int4 + 3, n::int4 + 4, n::int4 + 5, n::int4 + 6, n::int4 + 7, n::int4 + 8, n::int4 + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -774,13 +733,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_int64_1_rows_1_columns(b *t b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -793,13 +751,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_int64_1_rows_1_columns(b b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -812,13 +769,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_int64_1_rows_10_columns(b * b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -831,13 +787,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_int64_1_rows_10_columns(b b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -850,13 +805,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_int64_10_rows_1_columns(b * b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -869,13 +823,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_int64_10_rows_1_columns(b b.ResetTimer() var v [1]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -888,13 +841,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_int64_100_rows_10_columns(b b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -907,13 +859,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_int64_100_rows_10_columns b.ResetTimer() var v [10]int64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -926,13 +877,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_float64_1_rows_1_columns(b b.ResetTimer() var v [1]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -945,13 +895,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_float64_1_rows_1_columns( b.ResetTimer() var v [1]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -964,13 +913,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_float64_1_rows_10_columns(b b.ResetTimer() var v [10]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -983,13 +931,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_float64_1_rows_10_columns b.ResetTimer() var v [10]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1002,13 +949,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_float64_10_rows_1_columns(b b.ResetTimer() var v [1]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1021,13 +967,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_float64_10_rows_1_columns b.ResetTimer() var v [1]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1040,13 +985,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_float64_100_rows_10_columns b.ResetTimer() var v [10]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1059,13 +1003,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_float64_100_rows_10_colum b.ResetTimer() var v [10]float64 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1078,13 +1021,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_pgtype_Numeric_1_rows_1_col b.ResetTimer() var v [1]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1097,13 +1039,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_pgtype_Numeric_1_rows_1_c b.ResetTimer() var v [1]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1116,13 +1057,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_pgtype_Numeric_1_rows_10_co b.ResetTimer() var v [10]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1135,13 +1075,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_pgtype_Numeric_1_rows_10_ b.ResetTimer() var v [10]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 1) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1154,13 +1093,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_pgtype_Numeric_10_rows_1_co b.ResetTimer() var v [1]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1173,13 +1111,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_pgtype_Numeric_10_rows_1_ b.ResetTimer() var v [1]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0 from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1192,13 +1129,12 @@ func BenchmarkQueryTextFormatDecode_PG_numeric_to_Go_pgtype_Numeric_100_rows_10_ b.ResetTimer() var v [10]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1211,13 +1147,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_numeric_to_Go_pgtype_Numeric_100_rows_1 b.ResetTimer() var v [10]pgtype.Numeric for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select n::numeric + 0, n::numeric + 1, n::numeric + 2, n::numeric + 3, n::numeric + 4, n::numeric + 5, n::numeric + 6, n::numeric + 7, n::numeric + 8, n::numeric + 9 from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8], &v[9]}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1230,13 +1165,12 @@ func BenchmarkQueryTextFormatDecode_PG_Int4Array_With_Go_Int4Array_10(b *testing b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1249,13 +1183,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_Int4Array_With_Go_Int4Array_10(b *testi b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 10) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1268,13 +1201,12 @@ func BenchmarkQueryTextFormatDecode_PG_Int4Array_With_Go_Int4Array_100(b *testin b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1287,13 +1219,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_Int4Array_With_Go_Int4Array_100(b *test b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 100) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1306,13 +1237,12 @@ func BenchmarkQueryTextFormatDecode_PG_Int4Array_With_Go_Int4Array_1000(b *testi b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 1000) n`, []any{pgx.QueryResultFormats{pgx.TextFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -1325,13 +1255,12 @@ func BenchmarkQueryBinaryFormatDecode_PG_Int4Array_With_Go_Int4Array_1000(b *tes b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, 1000) n`, []any{pgx.QueryResultFormats{pgx.BinaryFormatCode}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } diff --git a/pgtype/integration_benchmark_test.go.erb b/pgtype/integration_benchmark_test.go.erb index 3459f0cb..144d9dd7 100644 --- a/pgtype/integration_benchmark_test.go.erb +++ b/pgtype/integration_benchmark_test.go.erb @@ -22,13 +22,12 @@ func BenchmarkQuery<%= format_name %>FormatDecode_PG_<%= pg_type %>_to_Go_<%= go b.ResetTimer() var v [<%= columns %>]<%= go_type %> for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select <% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>n::<%= pg_type %> + <%= col_idx%><% end %> from generate_series(1, <%= rows %>) n`, []any{pgx.QueryResultFormats{<%= format_code %>}}, - []any{<% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>&v[<%= col_idx%>]<% end %>}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{<% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>&v[<%= col_idx%>]<% end %>}, func() error { return nil }) if err != nil { b.Fatal(err) } @@ -47,13 +46,12 @@ func BenchmarkQuery<%= format_name %>FormatDecode_PG_Int4Array_With_Go_Int4Array b.ResetTimer() var v []int32 for i := 0; i < b.N; i++ { - _, err := conn.QueryFunc( + rows, _ := conn.Query( ctx, `select array_agg(n) from generate_series(1, <%= array_size %>) n`, []any{pgx.QueryResultFormats{<%= format_code %>}}, - []any{&v}, - func(pgx.QueryFuncRow) error { return nil }, ) + _, err := pgx.ForEachScannedRow(rows, []any{&v}, func() error { return nil }) if err != nil { b.Fatal(err) } diff --git a/pgxpool/batch_results.go b/pgxpool/batch_results.go index fcd10b37..5d5c681d 100644 --- a/pgxpool/batch_results.go +++ b/pgxpool/batch_results.go @@ -17,10 +17,6 @@ func (br errBatchResults) Query() (pgx.Rows, error) { return errRows{err: br.err}, br.err } -func (br errBatchResults) QueryFunc(scans []any, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { - return pgconn.CommandTag{}, br.err -} - func (br errBatchResults) QueryRow() pgx.Row { return errRow{err: br.err} } @@ -42,10 +38,6 @@ func (br *poolBatchResults) Query() (pgx.Rows, error) { return br.br.Query() } -func (br *poolBatchResults) QueryFunc(scans []any, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { - return br.br.QueryFunc(scans, f) -} - func (br *poolBatchResults) QueryRow() pgx.Row { return br.br.QueryRow() } diff --git a/pgxpool/conn.go b/pgxpool/conn.go index 3ab8b375..b8711da9 100644 --- a/pgxpool/conn.go +++ b/pgxpool/conn.go @@ -74,10 +74,6 @@ func (c *Conn) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row { return c.Conn().QueryRow(ctx, sql, args...) } -func (c *Conn) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { - return c.Conn().QueryFunc(ctx, sql, args, scans, f) -} - func (c *Conn) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults { return c.Conn().SendBatch(ctx, b) } diff --git a/pgxpool/pool.go b/pgxpool/pool.go index de4e1066..d73b93fb 100644 --- a/pgxpool/pool.go +++ b/pgxpool/pool.go @@ -533,16 +533,6 @@ func (p *Pool) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row { return c.getPoolRow(row) } -func (p *Pool) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { - c, err := p.Acquire(ctx) - if err != nil { - return pgconn.CommandTag{}, err - } - defer c.Release() - - return c.QueryFunc(ctx, sql, args, scans, f) -} - func (p *Pool) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults { c, err := p.Acquire(ctx) if err != nil { diff --git a/pgxpool/tx.go b/pgxpool/tx.go index 79da567c..3ddb742c 100644 --- a/pgxpool/tx.go +++ b/pgxpool/tx.go @@ -81,10 +81,6 @@ func (tx *Tx) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row { return tx.t.QueryRow(ctx, sql, args...) } -func (tx *Tx) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { - return tx.t.QueryFunc(ctx, sql, args, scans, f) -} - func (tx *Tx) Conn() *pgx.Conn { return tx.t.Conn() } diff --git a/query_test.go b/query_test.go index 7fa507b0..0c8b5fab 100644 --- a/query_test.go +++ b/query_test.go @@ -1898,102 +1898,3 @@ func TestQueryWithQueryRewriter(t *testing.T) { require.NoError(t, rows.Err()) }) } - -func TestConnQueryFunc(t *testing.T) { - t.Parallel() - - pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { - var actualResults []any - - var a, b int - ct, err := conn.QueryFunc( - context.Background(), - "select n, n * 2 from generate_series(1, $1) n", - []any{3}, - []any{&a, &b}, - func(pgx.QueryFuncRow) error { - actualResults = append(actualResults, []any{a, b}) - return nil - }, - ) - require.NoError(t, err) - - expectedResults := []any{ - []any{1, 2}, - []any{2, 4}, - []any{3, 6}, - } - require.Equal(t, expectedResults, actualResults) - require.EqualValues(t, 3, ct.RowsAffected()) - }) -} - -func TestConnQueryFuncScanError(t *testing.T) { - t.Parallel() - - pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { - var actualResults []any - - var a, b int - ct, err := conn.QueryFunc( - context.Background(), - "select 'foo', 'bar' from generate_series(1, $1) n", - []any{3}, - []any{&a, &b}, - func(pgx.QueryFuncRow) error { - actualResults = append(actualResults, []any{a, b}) - return nil - }, - ) - require.EqualError(t, err, "can't scan into dest[0]: cannot scan OID 25 in text format into *int") - require.Equal(t, pgconn.CommandTag{}, ct) - }) -} - -func TestConnQueryFuncAbort(t *testing.T) { - t.Parallel() - - pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { - var a, b int - ct, err := conn.QueryFunc( - context.Background(), - "select n, n * 2 from generate_series(1, $1) n", - []any{3}, - []any{&a, &b}, - func(pgx.QueryFuncRow) error { - return errors.New("abort") - }, - ) - require.EqualError(t, err, "abort") - require.Equal(t, pgconn.CommandTag{}, ct) - }) -} - -func ExampleConn_QueryFunc() { - conn, err := pgx.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE")) - if err != nil { - fmt.Printf("Unable to establish connection: %v", err) - return - } - - var a, b int - _, err = conn.QueryFunc( - context.Background(), - "select n, n * 2 from generate_series(1, $1) n", - []any{3}, - []any{&a, &b}, - func(pgx.QueryFuncRow) error { - fmt.Printf("%v, %v\n", a, b) - return nil - }, - ) - if err != nil { - fmt.Printf("QueryFunc error: %v", err) - return - } - - // Output: - // 1, 2 - // 2, 4 - // 3, 6 -} diff --git a/rows.go b/rows.go index d9c0ba47..a1492c3e 100644 --- a/rows.go +++ b/rows.go @@ -361,3 +361,28 @@ func RowsFromResultReader(typeMap *pgtype.Map, resultReader *pgconn.ResultReader resultReader: resultReader, } } + +// ForEachScannedRow iterates through rows. For each row it scans into the elements of scans and calls fn. If any row +// fails to scan or fn returns an error the query will be aborted and the error will be returned. Rows will be closed +// when ForEachScannedRow returns. +func ForEachScannedRow(rows Rows, scans []any, fn func() error) (pgconn.CommandTag, error) { + defer rows.Close() + + for rows.Next() { + err := rows.Scan(scans...) + if err != nil { + return pgconn.CommandTag{}, err + } + + err = fn() + if err != nil { + return pgconn.CommandTag{}, err + } + } + + if err := rows.Err(); err != nil { + return pgconn.CommandTag{}, err + } + + return rows.CommandTag(), nil +} diff --git a/rows_test.go b/rows_test.go index 37f8e1de..63bb77d5 100644 --- a/rows_test.go +++ b/rows_test.go @@ -2,9 +2,14 @@ package pgx_test import ( "context" + "errors" + "fmt" + "os" "testing" "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgxtest" "github.com/stretchr/testify/require" ) @@ -28,3 +33,98 @@ func TestRowScanner(t *testing.T) { require.Equal(t, int32(72), s.age) }) } + +func TestForEachScannedRow(t *testing.T) { + t.Parallel() + + pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { + var actualResults []any + + rows, _ := conn.Query( + context.Background(), + "select n, n * 2 from generate_series(1, $1) n", + 3, + ) + var a, b int + ct, err := pgx.ForEachScannedRow(rows, []any{&a, &b}, func() error { + actualResults = append(actualResults, []any{a, b}) + return nil + }) + require.NoError(t, err) + + expectedResults := []any{ + []any{1, 2}, + []any{2, 4}, + []any{3, 6}, + } + require.Equal(t, expectedResults, actualResults) + require.EqualValues(t, 3, ct.RowsAffected()) + }) +} + +func TestForEachScannedRowScanError(t *testing.T) { + t.Parallel() + + pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { + var actualResults []any + + rows, _ := conn.Query( + context.Background(), + "select 'foo', 'bar' from generate_series(1, $1) n", + 3, + ) + var a, b int + ct, err := pgx.ForEachScannedRow(rows, []any{&a, &b}, func() error { + actualResults = append(actualResults, []any{a, b}) + return nil + }) + require.EqualError(t, err, "can't scan into dest[0]: cannot scan OID 25 in text format into *int") + require.Equal(t, pgconn.CommandTag{}, ct) + }) +} + +func TestForEachScannedRowAbort(t *testing.T) { + t.Parallel() + + pgxtest.RunWithQueryExecModes(context.Background(), t, defaultConnTestRunner, nil, func(ctx context.Context, t testing.TB, conn *pgx.Conn) { + rows, _ := conn.Query( + context.Background(), + "select n, n * 2 from generate_series(1, $1) n", + 3, + ) + var a, b int + ct, err := pgx.ForEachScannedRow(rows, []any{&a, &b}, func() error { + return errors.New("abort") + }) + require.EqualError(t, err, "abort") + require.Equal(t, pgconn.CommandTag{}, ct) + }) +} + +func ExampleForEachScannedRow() { + conn, err := pgx.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE")) + if err != nil { + fmt.Printf("Unable to establish connection: %v", err) + return + } + + rows, _ := conn.Query( + context.Background(), + "select n, n * 2 from generate_series(1, $1) n", + 3, + ) + var a, b int + _, err = pgx.ForEachScannedRow(rows, []any{&a, &b}, func() error { + fmt.Printf("%v, %v\n", a, b) + return nil + }) + if err != nil { + fmt.Printf("ForEachScannedRow error: %v", err) + return + } + + // Output: + // 1, 2 + // 2, 4 + // 3, 6 +} diff --git a/tx.go b/tx.go index 76b1768c..2a05b70d 100644 --- a/tx.go +++ b/tx.go @@ -163,7 +163,6 @@ type Tx interface { Exec(ctx context.Context, sql string, arguments ...any) (commandTag pgconn.CommandTag, err error) Query(ctx context.Context, sql string, args ...any) (Rows, error) QueryRow(ctx context.Context, sql string, args ...any) Row - QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) // Conn returns the underlying *Conn that on which this transaction is executing. Conn() *Conn @@ -293,15 +292,6 @@ func (tx *dbTx) QueryRow(ctx context.Context, sql string, args ...any) Row { return (*connRow)(rows.(*baseRows)) } -// QueryFunc delegates to the underlying *Conn. -func (tx *dbTx) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) { - if tx.closed { - return pgconn.CommandTag{}, ErrTxClosed - } - - return tx.conn.QueryFunc(ctx, sql, args, scans, f) -} - // CopyFrom delegates to the underlying *Conn func (tx *dbTx) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) { if tx.closed { @@ -412,15 +402,6 @@ func (sp *dbSimulatedNestedTx) QueryRow(ctx context.Context, sql string, args .. return (*connRow)(rows.(*baseRows)) } -// QueryFunc delegates to the underlying Tx. -func (sp *dbSimulatedNestedTx) QueryFunc(ctx context.Context, sql string, args []any, scans []any, f func(QueryFuncRow) error) (pgconn.CommandTag, error) { - if sp.closed { - return pgconn.CommandTag{}, ErrTxClosed - } - - return sp.tx.QueryFunc(ctx, sql, args, scans, f) -} - // CopyFrom delegates to the underlying *Conn func (sp *dbSimulatedNestedTx) CopyFrom(ctx context.Context, tableName Identifier, columnNames []string, rowSrc CopyFromSource) (int64, error) { if sp.closed {