From 1d55eafc6e72c12ef089eff2c4f4b40d2f0f9f5f Mon Sep 17 00:00:00 2001 From: Brandur Date: Fri, 8 May 2026 09:57:51 -0500 Subject: [PATCH] Fix bug in `sqltemplate` cache path around args order Related to #1242. Activating caching everywhere revealed a bug in that we were adding named args using `maputil.Values`. The problem with this is that `maputil.Values` returns values in an arbitrary order, resulting in all kinds of odd things potentially happening during a query as args are switched around. Here, fix the problem by appending args in the same order as incoming map keys. --- CHANGELOG.md | 1 + rivershared/sqlctemplate/sqlc_template.go | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 048c1aa5..9fe80d63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix unsafe concurrent producer map access in client. [PR #1236](https://github.com/riverqueue/river/pull/1236). +- Fix bug in `sqltemplate` cached path in order in which named args are passed to a query (previously, the order was unstable). [PR #1243](https://github.com/riverqueue/river/pull/1243). ## [0.35.1] - 2026-04-26 diff --git a/rivershared/sqlctemplate/sqlc_template.go b/rivershared/sqlctemplate/sqlc_template.go index 88c02edb..1151b7d1 100644 --- a/rivershared/sqlctemplate/sqlc_template.go +++ b/rivershared/sqlctemplate/sqlc_template.go @@ -156,7 +156,14 @@ func (r *Replacer) RunSafely(ctx context.Context, argPlaceholder, sql string, ar // If all input templates were stable, the finished SQL will have been cached. if cachedSQLOK { if len(container.NamedArgs) > 0 { - args = append(args, maputil.Values(container.NamedArgs)...) + // Named args must be appended in sorted order to match the + // placeholder positions baked into the cached SQL during + // RunSafely's cache miss path. + sortedNamedArgs := maputil.Keys(container.NamedArgs) + slices.Sort(sortedNamedArgs) + for _, name := range sortedNamedArgs { + args = append(args, container.NamedArgs[name]) + } } return cachedSQL, args, nil }