From 2508d3f740c8876e9802e44713504035cdbbc002 Mon Sep 17 00:00:00 2001 From: Emile Friot Date: Tue, 21 Jul 2026 15:47:14 +0200 Subject: [PATCH 1/5] backend/postgres: Handle canceled query while scrolling --- backend/postgres/db.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/postgres/db.go b/backend/postgres/db.go index 46412e3..967157c 100644 --- a/backend/postgres/db.go +++ b/backend/postgres/db.go @@ -116,6 +116,10 @@ func (c *cursor) Scan(vs ...any) error { return wrapErr(c.Cursor.Scan(vs...)) } +func (c *cursor) Err() error { + return wrapErr(c.Cursor.Err()) +} + func IsPostgresDB(d sql.DB) bool { _, ok := d.(*db) return ok From d92e0c440ef8ce3e42a1341eb7b94bc20656af66 Mon Sep 17 00:00:00 2001 From: Emile Friot Date: Tue, 21 Jul 2026 16:56:03 +0200 Subject: [PATCH 2/5] add test --- integration/error_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/integration/error_test.go b/integration/error_test.go index 63d4608..2cab48a 100644 --- a/integration/error_test.go +++ b/integration/error_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/upfluence/sql" "github.com/upfluence/sql/sqltest" @@ -40,6 +41,17 @@ func TestCanceled(t *testing.T) { err := db.QueryRow(ctx, "SELECT 1").Scan() assert.ErrorIs(t, err, context.Canceled) + + ctx, done = context.WithCancel(context.Background()) + cursor, err := db.Query(ctx, "SELECT 1") + + require.NoError(t, err) + + done() + cursor.Next() + + assert.ErrorIs(t, cursor.Err(), context.Canceled) + }) } From 7d7f85b99f8aa91dacfbbb94b36bd915f515b61a Mon Sep 17 00:00:00 2001 From: Emile Friot Date: Tue, 21 Jul 2026 17:00:55 +0200 Subject: [PATCH 3/5] fix test --- integration/error_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/integration/error_test.go b/integration/error_test.go index 2cab48a..5f4792b 100644 --- a/integration/error_test.go +++ b/integration/error_test.go @@ -51,7 +51,6 @@ func TestCanceled(t *testing.T) { cursor.Next() assert.ErrorIs(t, cursor.Err(), context.Canceled) - }) } From 97fab1c9686397404b92e6bb9c6683450c29dab4 Mon Sep 17 00:00:00 2001 From: Emile Friot Date: Tue, 21 Jul 2026 17:37:18 +0200 Subject: [PATCH 4/5] fix postgres test --- integration/error_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/integration/error_test.go b/integration/error_test.go index 5f4792b..9451082 100644 --- a/integration/error_test.go +++ b/integration/error_test.go @@ -43,12 +43,17 @@ func TestCanceled(t *testing.T) { assert.ErrorIs(t, err, context.Canceled) ctx, done = context.WithCancel(context.Background()) - cursor, err := db.Query(ctx, "SELECT 1") + cursor, err := db.Query(ctx, ` + WITH RECURSIVE numbers(n) AS ( + SELECT 1 UNION ALL SELECT n + 1 FROM numbers WHERE n < 5000 + ) SELECT n FROM numbers; + `) // postgres will cache the first few results in the first contact, we need more content require.NoError(t, err) done() - cursor.Next() + + for cursor.Next() {} // wait for error/exhaust assert.ErrorIs(t, cursor.Err(), context.Canceled) }) From 586262d887f58c9af12e0f2bee0bd94bb6c705fb Mon Sep 17 00:00:00 2001 From: Emile Friot Date: Tue, 21 Jul 2026 17:42:19 +0200 Subject: [PATCH 5/5] fix test fmt --- integration/error_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/integration/error_test.go b/integration/error_test.go index 9451082..8d2a2de 100644 --- a/integration/error_test.go +++ b/integration/error_test.go @@ -53,7 +53,8 @@ func TestCanceled(t *testing.T) { done() - for cursor.Next() {} // wait for error/exhaust + for cursor.Next() { // wait for error/exhaust + } assert.ErrorIs(t, cursor.Err(), context.Canceled) })