Describe the bug
We have a web service where we set a statement_timeout on our connections to ensure that queries do not run for an extended period of time. As part of this web service, we have a large, generated query. We occasionally see errors such as the following:
ERROR: prepared statement "stmtcache_2b7087dc2ab6296b87fa5baa7f329541c23d17376faa03b7" already exists (SQLSTATE 42P05)
My hypothesis is that there is a statement timeout in the PREPARE but after Postgres has actually created the prepared statement. This causes pgx to end up in a state where the prepared statement isn't added to the statement cache but does exist for the connection in Postgres. I was able to reproduce this with the code below.
To Reproduce
The following sample code reliably produces the error with a local Postgres server for me. This probably could be simplified a bit further.
package main
import (
"context"
"database/sql"
"errors"
"fmt"
"log"
"math/rand"
"os"
"github.com/jackc/pgx/v5/pgconn"
_ "github.com/jackc/pgx/v5/stdlib"
)
func main() {
db, err := sql.Open("pgx", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
conn, err := db.Conn(ctx)
if err != nil {
log.Fatal(err)
}
_, err = conn.ExecContext(ctx, "SET statement_timeout TO 1")
if err != nil {
log.Fatal(err)
}
p := "s"
for {
var v uint
q := fmt.Sprintf("SELECT 1 AS %s", p)
err := conn.QueryRowContext(
ctx,
q,
).Scan(&v)
if err != nil && !errors.Is(err, context.Canceled) {
var pgErr *pgconn.PgError
if errors.As(err, &pgErr) && pgErr.Code == "57014" {
continue
}
log.Fatal(err)
}
p = randString(100000)
}
}
var letterRunes = []rune("abAB")
func randString(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}
Expected behavior
No prepared statement already exists error.
Actual behavior
ERROR: prepared statement "stmtcache_087f9f36620ff21723cd288c17d7806ba6fdd9b160f73186" already exists (SQLSTATE 42P05)
Version
- Go:
go version go1.23.4 linux/amd64
- PostgreSQL:
PostgreSQL 16.6 (Ubuntu 16.6-1.pgdg24.10+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 14.2.0-4ubuntu2) 14.2.0, 64-bit
- pgx:
v5.7.2
Describe the bug
We have a web service where we set a
statement_timeouton our connections to ensure that queries do not run for an extended period of time. As part of this web service, we have a large, generated query. We occasionally see errors such as the following:My hypothesis is that there is a statement timeout in the
PREPAREbut after Postgres has actually created the prepared statement. This causespgxto end up in a state where the prepared statement isn't added to the statement cache but does exist for the connection in Postgres. I was able to reproduce this with the code below.To Reproduce
The following sample code reliably produces the error with a local Postgres server for me. This probably could be simplified a bit further.
Expected behavior
No prepared statement already exists error.
Actual behavior
Version
go version go1.23.4 linux/amd64PostgreSQL 16.6 (Ubuntu 16.6-1.pgdg24.10+1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 14.2.0-4ubuntu2) 14.2.0, 64-bitv5.7.2