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: common interface for query functions in sql.DB and sql.Tx #14468
Comments
I'm sorry, I don't entirely understand this proposal. Are you suggesting that we should add the type QueryAble to database/sql? How would that make the package easier to use than it is today? |
Yes, I want to add The reason is that: I want to be able to create functions that execute SQL query's and retrieve data regardless of if its inside a prepared statement (and preferably only use prepared statements when i really need to). This is not possible without a interface. To provide a transaction and non transaction solution today you have to do something like this: func SqlMathWrapper(db *sql.DB , a, b int)(int, error){
tx, _ := db.Begin()
defer tx.Commit()
return SqlMath(tx, a,b)
}
func SqlMath(tx *sql.Tx, a, b int)(num int, err error){
err = tx.QueryRow("SELECT ? + ?", a, b).Scan(&num)
return
} (This dose always use transaction) Using the interface the code would look like this func SqlMath(qa *sql.QueryAble, a, b int)(num int, err error){
err = qa.QueryRow("SELECT ? + ?", a, b).Scan(&num)
return
} (This would not use prepared statements if called with a sql.DB object) |
Just to be clear, you could define the interface yourself, right? |
@ianlancetaylor Yes, and that's what I will do until its implemented. |
Another discission at #14468 . |
The API for rollback / savepoint may also factor into this conversation: #7898. |
I am strongly in favor of the |
@vwochnik I'm not convinced such an interface needs to live in the std lib. |
Absolutely common issue it seems and I have the same case here. Of course we can all write an interface definition on our own but that would be done again and again causing much more work in the end (when summing up each individual time spent or working around that). |
Great @kPshi . Start using the interface defined in sqlexp and spread the word. Then when the tree opens in 3 months we can see how widely it is used. |
How can one use an |
Not at this level. Some drivers a not network based, others are cgo based.
Ask the driver for a connector with that capacity.
…On Fri, Feb 23, 2018, 23:10 Eyal Posener ***@***.***> wrote:
How can one create an http.RoundTripper-like interface for SQL queries?
The http library has really nice behaviors/abstractions/profiling hooks
around the http.Client, which we miss in the sql.DB client.
—
You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub
<#14468 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAuFsU431djKw8h-zTkBHusMMiOfWgLYks5tX7XLgaJpZM4HfybU>
.
|
Why? They all implement the Some use cases I thought of:
I could have a struct implementing the non-existent interface, that wrap a given database connection: type SQLLogger struct {
*sql.DB
}
func (s *SQLLogger) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
log.Printf("whatever")
defer log.Printf("finished!")
return s.DB.ExecContext(ctx, query, args...)
} The problem is that since this interface does not exists in the standard library, most libraries expect an |
I agree.
This is what makes Go so powerful IMHO: a well-defined set of shared libraries that can work together seamlessly, because most high-level concepts are expertly expressed in the STL. |
I have the same issue of the author, so 👍 Why don't you define a new interface like DbTx honoring tha pattern invented for the interface like |
I'm a 👍 on this one, it would be nice to be able to have a shared interface that you can pass a Txt or a normal db. We ended up creating our own interface which isn't too bad, it just may spook some people coming to the codebase that see I think |
This is the root of the problem. Makes it impossible to create wrapper DBs for use in shared libraries, for example The |
^ It turns out that you can easily accomplish this kind of instrumentation by implementing your own driver (or wrapping an existing driver). The issue with this is that telemetry instrumentation isn't necessarily specific to any given implementation of a DB, so the driver isn't the best place to do this. However, it seems to be our only option currently. |
It occurs to me that a There is precedent in I don’t see it mentioned here, but in #14674, it was pointed out that we probably want to implement |
In reading the previous comments I noticed mentions to the I realized that if such an intersection interface existed in |
This comment was marked as off-topic.
This comment was marked as off-topic.
+1 A common interface in the standard library would be very useful. For example, in pressly/goose (a migration tool) users are able to build their own goose binaries and "register" Go-based migrations alongside their SQL migrations. The goose package exposes the following types and registration functions: type GoMigration func(tx *sql.Tx) error
func AddMigration(up, down GoMigration) {
...
}
type GoMigrationNoTx func(db *sql.DB) error
func AddMigrationNoTx(up, down GoMigrationNoTx) {
...
} With these primitives, users can write Go migration files (e.g., func init() {
goose.AddMigration(Up00002, nil)
}
func Up00002(tx *sql.Tx) error {
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
return err
} We could define a common interface in goose, but then the caller would be stuck with a bespoke interface that doesn't interoperate with the rest of the ecosystem. In other words, popular frameworks would still accept Much like the lack of a Logger interface in the standard library (although there is some hope with slog), the lack of a common SQL interface makes various tools throughout the ecosystem less interoperable and more fragmented. It doesn't have to be like this, if the standard library defined the contract(s) we could have a much richer ecosystem where the end-users enjoy packages and frameworks that work cohesively. |
Hi,
I'm proposing a interface that implements all functions in
sql.DB
andsql.Tx
that takes aquery string
as one of its arguments. This could be useful when implementing "dumb" functions that retrieves information but in itself dose not need to be prepared however might be used to verify whether to commit or rollback.The interface I'm proposing is: (The name can of course be changed)
This is an example function
Get
that can be used with or without transactions.The text was updated successfully, but these errors were encountered: