What changed, and why it matters
This commit fixes a design-level mismatch in a new database helper package (sqldb/v2). The TransactionExecutor type was advertised as satisfying the BatchedTx interface, but it was missing a Backend() method, so any code that actually tried to use it through that interface would fail to compile. The patch adds the missing method, moves the Backend() requirement onto a lower-level interface, and adds a compile-time check plus a small test so the problem cannot silently recur. There is no runtime security vulnerability here; it is a compile-time contract repair in unreleased/internal code.
No security action required. Treat as normal code-quality/maintenance review. Ensure downstream callers that rely on BatchedTx recompile cleanly.
Security signals we found
No security-relevant runtime behavior change
Compile-time interface conformance fix only
No input parsing, cryptography, network, or privilege changes
Adds regression test and compile-time assertion
Evidence from the diff
The change is in sqldb/v2/interfaces.go. Previously BatchedTx[Q BaseQuerier] required Q to embed BaseQuerier (which had Backend()), but TransactionExecutor did not itself implement Backend(), so it did not satisfy BatchedTx[TransactionExecutor’s Query]. The patch removes BaseQuerier, adds Backend() to BatchedQuerier, changes TransactionExecutor’s generic constraint to any, implements Backend() on TransactionExecutor by delegating to its embedded BatchedQuerier, and adds var _ BatchedTx[any] = (*TransactionExecutor[any])(nil) for compile-time conformance. A new test verifies backend forwarding. This is a latent compile-time contract bug, not an exploitable runtime flaw.
Changed components
sqldb/v2/interfaces.gosqldb/v2/interfaces_test.goTransactionExecutorBatchedTxBatchedQuerierInspect captured patch +63 / −11
diff --git a/sqldb/v2/interfaces.go b/sqldb/v2/interfaces.go
index caec453..adce4e5 100644
--- a/sqldb/v2/interfaces.go
+++ b/sqldb/v2/interfaces.go
@@ -84,20 +84,12 @@ func ReadTxOpt() TxOptions {
}
}
-// BaseQuerier is a generic interface that represents the base methods that any
-// database backend implementation which uses a Querier for its operations must
-// implement.
-type BaseQuerier interface {
- // Backend returns the type of the database backend used.
- Backend() BackendType
-}
-
// BatchedTx is a generic interface that represents the ability to execute
// several operations to a given storage interface in a single atomic
// transaction. Typically, Q here will be some subset of the main sqlc.Querier
// interface allowing it to only depend on the routines it needs to implement
// any additional business logic.
-type BatchedTx[Q BaseQuerier] interface {
+type BatchedTx[Q any] interface {
// ExecTx will execute the passed txBody, operating upon generic
// parameter Q (usually a storage interface) in a single transaction.
//
@@ -137,6 +129,9 @@ type BatchedQuerier interface {
// BeginTx creates a new database transaction given the set of
// transaction options.
BeginTx(ctx context.Context, options TxOptions) (*sql.Tx, error)
+
+ // Backend returns the type of the database backend used.
+ Backend() BackendType
}
// txExecutorOptions is a struct that holds the options for the transaction
@@ -188,7 +183,7 @@ func WithTxRetryDelay(delay time.Duration) TxExecutorOption {
// query a type needs to run under a database transaction, and also the set of
// options for that transaction. The QueryCreator is used to create a query
// given a database transaction created by the BatchedQuerier.
-type TransactionExecutor[Query BaseQuerier] struct {
+type TransactionExecutor[Query any] struct {
BatchedQuerier
createQuery QueryCreator[Query]
@@ -196,10 +191,14 @@ type TransactionExecutor[Query BaseQuerier] struct {
opts *txExecutorOptions
}
+// A compile-time assertion to ensure TransactionExecutor satisfies the
+// batched transaction interface.
+var _ BatchedTx[any] = (*TransactionExecutor[any])(nil)
+
// NewTransactionExecutor creates a new instance of a TransactionExecutor given
// a Querier query object and a concrete type for the type of transactions the
// Querier understands.
-func NewTransactionExecutor[Querier BaseQuerier](db BatchedQuerier,
+func NewTransactionExecutor[Querier any](db BatchedQuerier,
createQuery QueryCreator[Querier],
opts ...TxExecutorOption) *TransactionExecutor[Querier] {
@@ -215,6 +214,11 @@ func NewTransactionExecutor[Querier BaseQuerier](db BatchedQuerier,
}
}
+// Backend returns the type of database backend used by the executor.
+func (t *TransactionExecutor[Q]) Backend() BackendType {
+ return t.BatchedQuerier.Backend()
+}
+
// randRetryDelay returns a random retry delay between -50% and +50% of the
// configured delay that is doubled for each attempt and capped at a max value.
func randRetryDelay(initialRetryDelay, maxRetryDelay time.Duration,
diff --git a/sqldb/v2/interfaces_test.go b/sqldb/v2/interfaces_test.go
new file mode 100644
index 0000000..024b367
--- /dev/null
+++ b/sqldb/v2/interfaces_test.go
@@ -0,0 +1,48 @@
+package sqldb
+
+import (
+ "context"
+ "database/sql"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+// testQuerier is a minimal query wrapper used to instantiate the generic
+// transaction executor in tests.
+type testQuerier struct {
+}
+
+// testBatchedQuerier is a minimal BatchedQuerier implementation used to verify
+// that TransactionExecutor forwards backend identity.
+type testBatchedQuerier struct {
+ backend BackendType
+}
+
+// BeginTx is a stub implementation used to satisfy the BatchedQuerier
+// interface in tests.
+func (t testBatchedQuerier) BeginTx(context.Context,
+ TxOptions) (*sql.Tx, error) {
+
+ return nil, nil
+}
+
+// Backend returns the backend type used by the test batched querier.
+func (t testBatchedQuerier) Backend() BackendType {
+ return t.backend
+}
+
+// TestTransactionExecutorBackend verifies that the executor forwards the
+// backend type from its batched querier.
+func TestTransactionExecutorBackend(t *testing.T) {
+ t.Parallel()
+
+ executor := NewTransactionExecutor[testQuerier](
+ testBatchedQuerier{backend: BackendTypePostgres},
+ func(*sql.Tx) testQuerier {
+ return testQuerier{}
+ },
+ )
+
+ require.Equal(t, BackendTypePostgres, executor.Backend())
+}
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.