fix(postgres): propagate `persistent` to intermediary queries
In some situations (e.g.: when using enums), sqlx will fire additional queries to fetch data from the database. Currently, these queries use persistent=true, regardless of whether the parent query did. Unfortunately, this means that sqlx can't be used with connection poolers that don't support named prepared statements.
In this patch, I try to propagate the persistent attribute from the parent query to the other queries.
Additionally, this requires a potential re-send of Parse/Describe, as the additional queries will replace the existing one Postgres-side. For example, this is a sequence that could happen (after propagating persistent):
Parse("", "SELECT * FROM mytable")
Describe("")
Sync()
Parse("", "SELECT enumlabel FROM pg_catalog.pg_enum WHERE enumtypid = $1 ORDER BY enumsortorder") Describe("")
Sync()
Bind(...)
Execute(..)
Sync()
Bind(...)
Execute(..)
Sync()
This obviously won't work, as the second Parse message overwrote the unnamed prepared statement. Hence I added a re-preparation of the original query:
Parse("", "SELECT * FROM mytable")
Describe("")
Sync()
Parse("", "SELECT enumlabel FROM pg_catalog.pg_enum WHERE enumtypid = $1 ORDER BY enumsortorder") Describe("")
Sync()
Bind(...)
Execute(..)
Sync()
Parse("", "SELECT * FROM mytable")
Describe("")
Bind(...)
Execute(..)
Sync()
Let me know if I missed any place where this should be done, or if you disagree in the concept.
Is this a breaking change?
I don't believe so.
This kind of situation is likely better handled by disabling prepared statement caching at the connection level, which can be done by setting the statement cache capacity to zero: https://docs.rs/sqlx/latest/sqlx/postgres/struct.PgConnectOptions.html#method.statement_cache_capacity
That might have the same problem of needing to re-prepare the query, though.
It might be better to use the raw_sql interface to fetch this information so we don't have to prepare the user's query twice.
Hi, @abonander, thanks for the review.
I tried setting statement_cache_capacity to zero but sqlx continues using named prepared statements, at least on 0.8.6.
I feel like statement_cache_capacity could set persistent=false at execution time if it's 0, so alongside this PR it would ensure that named prepared statements aren't used ever if statement_cache_capacity == 0
Yeah, sorry if I was a little ambiguous there. I meant to say that statement_cache_capacity=0 should force these statements to be prepared with the unnamed statement but it does not right now. We should fix that.
Admittedly, it's also hard to discover. Maybe we should add an explicit connect option like PgConnectOptions::named_prepared_statements(enabled: bool) to force the use of only unnamed prepared statements when it's disabled.
I see. I'll give it a stab :)