-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Support initsql statements for new connections #263
Comments
let pool = PgPool::builder()
.max_size(1)
// .on_acquire() - called when a connection is checked out from the pool
// .on_release() - called when a connection is returned to the pool
// .on_close() - called when a connection is dropped
.on_connect(|conn| async move {
conn.execute("
SET timezone('UTC');
SET statement_timeout TO 120;
SET application_name TO 'logwriter';
").await
})
.build(" ... ").await?; The most robust way here is probably just a series of cc @danielakhterov @abonander |
I fix this problem on my computer temporary, edit my local source code. It's work well. let application_name = url
.param(&"application_name")
.unwrap_or(std::borrow::Cow::Borrowed("")); // https://www.postgresql.org/docs/12/protocol-flow.html#id-1.10.5.7.3
async fn startup(stream: &mut PgStream, url: &Url) -> crate::Result<BackendKeyData> {
// Defaults to postgres@.../postgres
let username = url.username().unwrap_or(Cow::Borrowed("postgres"));
let database = url.database().unwrap_or("postgres");
let application_name = url
.param(&"application_name")
.unwrap_or(std::borrow::Cow::Borrowed(""));
// See this doc for more runtime parameters
// https://www.postgresql.org/docs/12/runtime-config-client.html
let params = &[
("user", username.as_ref()),
("database", database),
// Sets the display format for date and time values,
// as well as the rules for interpreting ambiguous date input values.
("DateStyle", "ISO, MDY"),
// Sets the time zone for displaying and interpreting time stamps.
("TimeZone", "UTC"),
// Adjust postgres to return percise values for floats
// NOTE: This is default in postgres 12+
("extra_float_digits", "3"),
// Sets the client-side encoding (character set).
("client_encoding", "UTF-8"),
("application_name", &application_name),
];
stream.write(StartupMessage { params });
stream.flush().await?; |
@mehcode Do we want
is going to get pretty redundant quickly. This does also beg the question if we should even support users doing anything else but executing statements in the |
That's a pretty compelling point to me. However, that might also be necessary in some cases. For instance, maybe you need to use some secret or the query is based on some feature-toggle that can be changed at runtime? I'm not actually advocating for a hook here, I think these edge cases are pretty exceptional, but they do come to mind! |
Callback is more flexible in the general case. We can always use a trait that would accept just a string to make that case simple as an enhancement. |
The annoying part with using a trait is that the closure would need to give the argument types for the trait resolution to work, e.g. |conn: &mut PgConnection| async move {
} We encountered this already with the |
@mehcode Callbacks are definitely more flexible, but I'm just thinking what can a user possibly want to do other than call some initialization queries. This arbitrary code would run on every single connection startup, not just a pool startup which is why it seems so weird. |
This is too context-specific. I am hypothesising reasons one might need a closure, not citing a need I have. If I were in a situation like that, I'd probably make sure I killed the pool and re-established it or relied on |
Having two separate methods doesn't seem overly onerous to me, and there's plenty of precedent in |
So we thinking like: impl<DB: Database> Builder<DB> {
pub fn init_sql(&mut self, sql: Into<String>) -> &mut Self { ... }
pub fn on_connect<F, Fut>(&mut self, on_connect: F) -> &mut Self
where
F: Send + Sync + 'static + Fn(&mut DB::Connection) -> Fut,
Fut: Future<Output = sqlx::Result<()>> + Send
{ ... }
} |
With #430 we might also want an |
I think a first, minimal implementation that would help a lot of people is just: impl<DB: Database> Builder<DB> {
pub fn on_connect<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Send + Sync + 'static + Fn(&mut DB::Connection) -> Fut,
Fut: Future<Output = Result<(), Box<dyn Error + Send + Sync + 'static>>> + Send
{ ... }
pub fn on_close<F, Fut>(&mut self, f: F) -> &mut Self
where
F: Send + Sync + 'static + Fn(&mut DB::Connection) -> Fut,
Fut: Future<Output = Result<(), Box<dyn Error + Send + Sync + 'static>>> + Send
{ ... }
} Most else is written fairly trivially in this. For example, given #430: let pool = Pool::builder()
.on_connect(|conn| async move {
unsafe {
sqlite3_do_something(conn.as_raw_handle());
}
Ok(())
})
.build().await?;
let pool = Pool::builder()
.on_connect(|conn| conn.execute(r#"
SQL
GOES
HERE
"#))
.build().await?; |
If the error type is |
That sounds right. The issue with using |
@mehcode Now that |
Yep this is now supported on master. |
I'd like to run a number of statements only once after establishing a connection to the database.
(I'm using PostgreSQL, but I guess this may be generically useful).
Issue #180 for example, would be relatively simple once this is .
Things I may wish to execute are:
Not sure what the interface should be, but something like allowing a Vec of statements to be executed, when building a connection with the builder?
A comparable feature is https://tomcat.apache.org/tomcat-7.0-doc/jdbc-pool.html (search for initsql).
The text was updated successfully, but these errors were encountered: