|
1 |
| -use crate::connection::{sasl, stream::PgStream}; |
| 1 | +use crate::connection::sasl; |
2 | 2 | use crate::error::Error;
|
3 | 3 | use crate::message::{Authentication, BackendKeyData, BackendMessageFormat, Password, Startup};
|
4 | 4 | use crate::{PgConnectOptions, PgConnection};
|
5 | 5 | use futures_channel::mpsc::unbounded;
|
| 6 | +use std::str::FromStr; |
6 | 7 |
|
7 |
| -use super::stream::parse_server_version; |
8 |
| -use super::worker::Worker; |
| 8 | +use super::worker::{Shared, Worker}; |
9 | 9 |
|
10 | 10 | // https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.3
|
11 | 11 | // https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.11
|
12 | 12 |
|
13 | 13 | impl PgConnection {
|
14 | 14 | pub(crate) async fn establish(options: &PgConnectOptions) -> Result<Self, Error> {
|
15 |
| - // Upgrade to TLS if we were asked to and the server supports it |
16 |
| - let stream = PgStream::connect(options).await?; |
17 |
| - |
18 | 15 | let (notif_tx, notif_rx) = unbounded();
|
| 16 | + let shared = Shared::new(); |
19 | 17 |
|
20 |
| - let (channel, shared) = Worker::spawn(stream.into_inner(), notif_tx); |
| 18 | + // Upgrade to TLS if we were asked to and the server supports it |
| 19 | + let channel = Worker::connect(options, notif_tx, shared.clone()).await?; |
21 | 20 |
|
22 | 21 | let mut conn = PgConnection::new(options, channel, notif_rx, shared);
|
23 | 22 |
|
@@ -143,3 +142,69 @@ impl PgConnection {
|
143 | 142 | Ok(conn)
|
144 | 143 | }
|
145 | 144 | }
|
| 145 | + |
| 146 | +// reference: |
| 147 | +// https://github.com/postgres/postgres/blob/6feebcb6b44631c3dc435e971bd80c2dd218a5ab/src/interfaces/libpq/fe-exec.c#L1030-L1065 |
| 148 | +fn parse_server_version(s: impl Into<String>) -> Option<u32> { |
| 149 | + let s = s.into(); |
| 150 | + let mut parts = Vec::<u32>::with_capacity(3); |
| 151 | + |
| 152 | + let mut from = 0; |
| 153 | + let mut chs = s.char_indices().peekable(); |
| 154 | + while let Some((i, ch)) = chs.next() { |
| 155 | + match ch { |
| 156 | + '.' => { |
| 157 | + if let Ok(num) = u32::from_str(&s[from..i]) { |
| 158 | + parts.push(num); |
| 159 | + from = i + 1; |
| 160 | + } else { |
| 161 | + break; |
| 162 | + } |
| 163 | + } |
| 164 | + _ if ch.is_ascii_digit() => { |
| 165 | + if chs.peek().is_none() { |
| 166 | + if let Ok(num) = u32::from_str(&s[from..]) { |
| 167 | + parts.push(num); |
| 168 | + } |
| 169 | + break; |
| 170 | + } |
| 171 | + } |
| 172 | + _ => { |
| 173 | + if let Ok(num) = u32::from_str(&s[from..i]) { |
| 174 | + parts.push(num); |
| 175 | + } |
| 176 | + break; |
| 177 | + } |
| 178 | + }; |
| 179 | + } |
| 180 | + |
| 181 | + let version_num = match parts.as_slice() { |
| 182 | + [major, minor, rev] => (100 * major + minor) * 100 + rev, |
| 183 | + [major, minor] if *major >= 10 => 100 * 100 * major + minor, |
| 184 | + [major, minor] => (100 * major + minor) * 100, |
| 185 | + [major] => 100 * 100 * major, |
| 186 | + _ => return None, |
| 187 | + }; |
| 188 | + |
| 189 | + Some(version_num) |
| 190 | +} |
| 191 | + |
| 192 | +#[cfg(test)] |
| 193 | +mod tests { |
| 194 | + use super::parse_server_version; |
| 195 | + |
| 196 | + #[test] |
| 197 | + fn test_parse_server_version_num() { |
| 198 | + // old style |
| 199 | + assert_eq!(parse_server_version("9.6.1"), Some(90601)); |
| 200 | + // new style |
| 201 | + assert_eq!(parse_server_version("10.1"), Some(100001)); |
| 202 | + // old style without minor version |
| 203 | + assert_eq!(parse_server_version("9.6devel"), Some(90600)); |
| 204 | + // new style without minor version, e.g. */ |
| 205 | + assert_eq!(parse_server_version("10devel"), Some(100000)); |
| 206 | + assert_eq!(parse_server_version("13devel87"), Some(130000)); |
| 207 | + // unknown |
| 208 | + assert_eq!(parse_server_version("unknown"), None); |
| 209 | + } |
| 210 | +} |
0 commit comments