From 2ca99ced539134d7613bb9b48ac6a817d2b6e5c0 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 25 May 2024 09:00:44 -0500 Subject: [PATCH 1/2] database/sql: Add RowsColumnScanner interface Implementing RowsColumnScanner allows the driver to completely control how values are scanned. Fixes #67546 --- src/database/sql/driver/driver.go | 10 ++++++++++ src/database/sql/sql.go | 11 ++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index da310bfb12a0b..f70cdcb44e12d 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -515,6 +515,16 @@ type RowsColumnTypePrecisionScale interface { ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) } +// RowsColumnScanner may be implemented by [Rows]. It allows the driver to control +// how values or scanned. +type RowsColumnScanner interface { + Rows + + // ScanColumn copies the column in the current row into the value pointed at by + // dest. It returns [ErrSkip] to fall back to the normal [database/sql] scanning path. + ScanColumn(index int, dest any) error +} + // Tx is a transaction. type Tx interface { Commit() error diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index de774a051093d..8d15e065b9136 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -3389,7 +3389,16 @@ func (rs *Rows) Scan(dest ...any) error { } for i, sv := range rs.lastcols { - err := convertAssignRows(dest[i], sv, rs) + err := driver.ErrSkip + + if rowsColumnScanner, ok := rs.rowsi.(driver.RowsColumnScanner); ok { + err = rowsColumnScanner.ScanColumn(i, dest[i]) + } + + if err == driver.ErrSkip { + err = convertAssignRows(dest[i], sv, rs) + } + if err != nil { rs.closemuRUnlockIfHeldByScan() return fmt.Errorf(`sql: Scan error on column index %d, name %q: %w`, i, rs.rowsi.Columns()[i], err) From 45049970986abeb66b059d548336dad70c1b0023 Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Mon, 24 Jun 2024 20:17:09 -0500 Subject: [PATCH 2/2] Expand RowsColumnScanner documentation --- src/database/sql/driver/driver.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go index f70cdcb44e12d..d3fa1f6778eff 100644 --- a/src/database/sql/driver/driver.go +++ b/src/database/sql/driver/driver.go @@ -515,8 +515,10 @@ type RowsColumnTypePrecisionScale interface { ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) } -// RowsColumnScanner may be implemented by [Rows]. It allows the driver to control -// how values or scanned. +// RowsColumnScanner may be implemented by [Rows]. It allows the driver to completely +// take responsibility for how values are scanned and replace the normal [database/sql]. +// scanning path. This allows drivers to directly support types that do not implement +// [database/sql.Scanner]. type RowsColumnScanner interface { Rows