-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
database/sql: allow driver to entirely override Scan #67546
Comments
CC @kardianos |
Given the design of database/sql, I see no issue with this interface. |
Implementing RowsColumnScanner allows the driver to completely control how values are scanned. Fixes golang#67546
Change https://go.dev/cl/588435 mentions this issue: |
@kardianos I implemented the change in #67648. I also made a PR for pgx that implements this interface (jackc/pgx#2029). With both of those PRs applied, the queries like the following work in pgx through database/sql: var names []string
err := db.QueryRow("select array['John', 'Jane']::text[]").Scan(&names) I observed a few things while making the change: It's possible for a driver to inadvertently change the way some of the scanning edge cases work. For example, database/sql defines the behavior for scanning a time into a There is a fair amount of work involved in creating the slice of driver.Valuer for |
This proposal has been added to the active column of the proposals project |
@jackc This is pending the proposal review group. But a reply to your observations:
Nice. Being able scan arrays directly is useful.
I'm personally okay with that.
So long as the new driver interface can return an ErrSkip, because Next is called first, and thus the driver value array is created per returned data set, I don't see a reasonable way to work around that. You could work around that, but the API change would be much larger. I'm not terribly interested in single row benchmarks on a local machine; in most real situations, if you need more performance, you will coalesce many single row queries into a one many row query. For example, yesterday I was annoyed at a slowly performing function, inspected it, and found the cause to be a single row query in a loop. I pulled it out, allocated an array, then encoded a JSON parameter and did a single query at the end and I went from multiple seconds to a single millisecond operation. I'm not concerned about saving a single allocation in Next per result set. If the driver "knows" it will call the new interface on Scan, then on Next, it can just ignore that work (stub it out, "cheat"), which I think is fine, but that would be up to the driver to do. |
It could potentially remove significantly more overhead than just the allocation of a For example, I created a quick benchmark of a query that selects 1,000 rows, each of which has a single 10 element integer array. This is through pgx directly, not
If pgx knew that it would never have to produce a valid
Sounds good. |
Can someone post the proposal in the form of a complete definition and doc comment of driver.RowsColumnScanner? I looked at the CL but the doc comment there is quite minimal. It seems like more needs to be said. |
I just pushed a commit that expands on the docs for |
Proposal: allow specific driver, not
|
Have all remaining concerns about this proposal been addressed? The proposal is:
|
Based on the discussion above, this proposal seems like a likely accept. The proposal is:
|
No change in consensus, so accepted. 🎉 The proposal is:
|
Hi @jackc . |
@bitpossum Apparently it needed some additional doc files in api/next and doc/next. I think it should be resolved now. |
Is the order of the arguments to ScanColumn significant? @bitpossum just let me know that my original implementation had the order one way, but the accepted CL reversed it. I can change the code but I wanted to first check that it was intentional. |
In the Go standard library the destination usually comes first, as with |
@ianlancetaylor No reason to use the other order. I can change it. The original implementation predated the accepted proposal and I had not noticed that it had been changed in the proposal. Just wanted to make sure it was intentional before I made the change. |
Implementing RowsColumnScanner allows the driver to completely control how values are scanned. Fixes golang#67546
Proposal Details
I am the creator of the https://github.com/jackc/pgx/ PostgreSQL driver.
pgx implements a very flexible and convenient type system for its native interface. Most types "just work" without needing to add any pgx or database/sql interfaces. Slices like
[]int64
can be used directly as query arguments and scan targets. Amap[string]string
can be used as a PostgreSQLjson
orhstore
value even though the encoding formats are different. This can only work because the encoding and decoding logic has access to connection specific information (e.g. registered Codecs for each type), the PostgreSQL type (OID), the value format (text or binary), and the Go type.I've been trying with very limited success to expose the this functionality and the relevant types to the database/sql interface. The problem is that an implementer of the
sql.Scanner
ordriver.Valuer
interfaces does not have any way of accessing the connection information, the PostgreSQL value type, or the value format.For query arguments, this can be overridden by implementing
NamedValueChecker
and simply passing all values through unmodified. So at this point, all of pgx's advanced type handling is available for query arguments.However, there does not seem to be the same for
Scan
. I propose adding adriver.RowsColumnScanner
interface.If this interface is implemented it could completely replace the existing database/sql scan logic. Drivers could implement arbitrary type support and it could significantly improve performance.
ErrSkip
could be returned to fallback to the existing database/sql logic.See #22544 for a related proposal. However, I prefer this proposal as the scanning interface is on the row not the connection or driver. This allows the decoding logic to know what the underlying database type and value format are.
As far as I know this would be an entirely backwards compatible change. The only subtlety I am aware of is a
RowsColumnScanner
would have to supportScanColumn
being called multiple times on the same column to preserve support for callingrows.Scan
multiple times on a single row.The text was updated successfully, but these errors were encountered: