-
Notifications
You must be signed in to change notification settings - Fork 867
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Occasional prepared statement already exist errors when using statement timeout #2223
Comments
You are correct. Based on your example code I was able to build a reproduction case directly at the PostgreSQL protocol layer. I send a pgx and pgconn always send In theory, I know how to solve this, but in practice it's tricky / messy enough I'm not sure. package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgproto3"
)
func main() {
ctx := context.Background()
conn, err := pgx.Connect(ctx, os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
defer conn.Close(ctx)
_, err = conn.Exec(ctx, "SET statement_timeout TO 1")
if err != nil {
log.Fatal(err)
}
conn.PgConn().Frontend().SendParse(&pgproto3.Parse{Name: "ps1", Query: "select 1", ParameterOIDs: nil})
err = conn.PgConn().Frontend().Flush()
if err != nil {
log.Fatal(err)
}
time.Sleep(1 * time.Millisecond)
conn.PgConn().Frontend().SendDescribe(&pgproto3.Describe{ObjectType: 'S', Name: "ps1"})
time.Sleep(1 * time.Millisecond)
conn.PgConn().Frontend().SendSync(&pgproto3.Sync{})
err = conn.PgConn().Frontend().Flush()
if err != nil {
log.Fatal(err)
}
for range 3 {
msg, err := conn.PgConn().Frontend().Receive()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", msg)
}
conn.PgConn().Frontend().SendParse(&pgproto3.Parse{Name: "ps1", Query: "select 1", ParameterOIDs: nil})
err = conn.PgConn().Frontend().Flush()
if err != nil {
log.Fatal(err)
}
time.Sleep(1 * time.Millisecond)
conn.PgConn().Frontend().SendDescribe(&pgproto3.Describe{ObjectType: 'S', Name: "ps1"})
time.Sleep(1 * time.Millisecond)
conn.PgConn().Frontend().SendSync(&pgproto3.Sync{})
err = conn.PgConn().Frontend().Flush()
if err != nil {
log.Fatal(err)
}
for range 2 {
msg, err := conn.PgConn().Frontend().Receive()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", msg)
}
}
|
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:My hypothesis is that there is a statement timeout in the
PREPARE
but after Postgres has actually created the prepared statement. This causespgx
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.
Expected behavior
No prepared statement already exists error.
Actual behavior
Version
go version go1.23.4 linux/amd64
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
v5.7.2
The text was updated successfully, but these errors were encountered: