Skip to content
This repository was archived by the owner on Sep 27, 2024. It is now read-only.

Commit 39fae54

Browse files
committed
Add DBConn.ExecContext
Context allows queries to be cancelled. This can be used when we expect a SIGINT/SIGTERM could occur during a query that could block (e.g. trying to SELECT from a table but some other session explicitly grabbed an AccessExclusiveLock and will not be giving it up anytime soon). Without the ability to cancel queries, exiting Go programs could lead to SQL session leaks. Simply closing the SQL connection DOES NOT cancel the query for you.
1 parent f202136 commit 39fae54

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

dbconn/dbconn.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package dbconn
66
*/
77

88
import (
9+
"context"
910
"database/sql"
1011
"fmt"
1112
"strconv"
@@ -257,6 +258,19 @@ func (dbconn *DBConn) MustExec(query string, whichConn ...int) {
257258
gplog.FatalOnError(err)
258259
}
259260

261+
func (dbconn *DBConn) ExecContext(queryContext context.Context, query string, whichConn ...int) (sql.Result, error) {
262+
connNum := dbconn.ValidateConnNum(whichConn...)
263+
if dbconn.Tx[connNum] != nil {
264+
return dbconn.Tx[connNum].ExecContext(queryContext, query)
265+
}
266+
return dbconn.ConnPool[connNum].ExecContext(queryContext, query)
267+
}
268+
269+
func (dbconn *DBConn) MustExecContext(queryContext context.Context, query string, whichConn ...int) {
270+
_, err := dbconn.ExecContext(queryContext, query, whichConn...)
271+
gplog.FatalOnError(err)
272+
}
273+
260274
func (dbconn *DBConn) GetWithArgs(destination interface{}, query string, args ...interface{}) error {
261275
if dbconn.Tx[0] != nil {
262276
return dbconn.Tx[0].Get(destination, query, args...)

dbconn/dbconn_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package dbconn_test
22

33
import (
4+
"context"
45
"database/sql/driver"
56
"fmt"
67
"os"
@@ -183,6 +184,36 @@ var _ = Describe("dbconn/dbconn tests", func() {
183184
Expect(rowsReturned).To(Equal(int64(1)))
184185
})
185186
})
187+
Describe("DBConn.ExecContext", func() {
188+
It("executes an INSERT outside of a transaction", func() {
189+
ctx, cancel := context.WithCancel(context.Background())
190+
defer cancel()
191+
192+
fakeResult := testhelper.TestResult{Rows: 1}
193+
mock.ExpectExec("INSERT (.*)").WillReturnResult(fakeResult)
194+
195+
res, err := connection.ExecContext(ctx, "INSERT INTO pg_tables VALUES ('schema', 'table')")
196+
Expect(err).ToNot(HaveOccurred())
197+
rowsReturned, err := res.RowsAffected()
198+
Expect(rowsReturned).To(Equal(int64(1)))
199+
})
200+
It("executes an INSERT in a transaction", func() {
201+
ctx, cancel := context.WithCancel(context.Background())
202+
defer cancel()
203+
204+
fakeResult := testhelper.TestResult{Rows: 1}
205+
ExpectBegin(mock)
206+
mock.ExpectExec("INSERT (.*)").WillReturnResult(fakeResult)
207+
mock.ExpectCommit()
208+
209+
connection.MustBegin()
210+
res, err := connection.ExecContext(ctx, "INSERT INTO pg_tables VALUES ('schema', 'table')")
211+
connection.MustCommit()
212+
Expect(err).ToNot(HaveOccurred())
213+
rowsReturned, err := res.RowsAffected()
214+
Expect(rowsReturned).To(Equal(int64(1)))
215+
})
216+
})
186217
Describe("DBConn.Get", func() {
187218
It("executes a GET outside of a transaction", func() {
188219
two_col_single_row := sqlmock.NewRows([]string{"schemaname", "tablename"}).

0 commit comments

Comments
 (0)