use crate::HashMap;
use crate::common::StatementCache;
use crate::connection::{sasl, stream::PgStream};
use crate::error::Error;
use crate::io::StatementId;
use crate::message::{
Authentication, BackendKeyData, BackendMessageFormat, Password, ReadyForQuery, Startup,
};
use crate::{PgConnectOptions, PgConnection};
use super::PgConnectionInner;
impl PgConnection {
pub(crate) async fn establish(options: &PgConnectOptions) -> Result<Self, Error> {
let mut stream = PgStream::connect(options).await?;
let mut params = vec![
("DateStyle", "ISO, MDY"),
("client_encoding", "UTF8"),
("TimeZone", "UTC"),
];
if let Some(ref extra_float_digits) = options.extra_float_digits {
params.push(("extra_float_digits", extra_float_digits));
}
if let Some(ref application_name) = options.application_name {
params.push(("application_name", application_name));
}
if let Some(ref options) = options.options {
params.push(("options", options));
}
stream.write(Startup {
username: Some(&options.username),
database: options.database.as_deref(),
params: ¶ms,
})?;
stream.flush().await?;
let mut process_id = 0;
let mut secret_key = 0;
let transaction_status;
loop {
let message = stream.recv().await?;
match message.format {
BackendMessageFormat::Authentication => match message.decode()? {
Authentication::Ok => {
}
Authentication::CleartextPassword => {
stream
.send(Password::Cleartext(
options.password.as_deref().unwrap_or_default(),
))
.await?;
}
Authentication::Md5Password(body) => {
stream
.send(Password::Md5 {
username: &options.username,
password: options.password.as_deref().unwrap_or_default(),
salt: body.salt,
})
.await?;
}
Authentication::Sasl(body) => {
sasl::authenticate(&mut stream, options, body).await?;
}
method => {
return Err(err_protocol!(
"unsupported authentication method: {:?}",
method
));
}
},
BackendMessageFormat::BackendKeyData => {
let data: BackendKeyData = message.decode()?;
process_id = data.process_id;
secret_key = data.secret_key;
}
BackendMessageFormat::ReadyForQuery => {
transaction_status = message.decode::<ReadyForQuery>()?.transaction_status;
break;
}
_ => {
return Err(err_protocol!(
"establish: unexpected message: {:?}",
message.format
))
}
}
}
Ok(PgConnection {
inner: Box::new(PgConnectionInner {
stream,
process_id,
secret_key,
transaction_status,
transaction_depth: 0,
pending_ready_for_query_count: 0,
next_statement_id: StatementId::NAMED_START,
cache_statement: StatementCache::new(options.statement_cache_capacity),
cache_type_oid: HashMap::new(),
cache_type_info: HashMap::new(),
cache_elem_type_to_array: HashMap::new(),
cache_table_data: HashMap::new(),
log_settings: options.log_settings.clone(),
}),
})
}
}