Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/fmt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ jobs:
- name: Format
run: cargo fmt --all -- --check
- name: Clippy
run: cargo clippy --all-targets
run: cargo clippy --all-targets -- -D warnings
219 changes: 150 additions & 69 deletions pgdog-postgres-types/src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,79 +431,160 @@ mod tests {

// ── Text decode ──────────────────────────────────────────────────

struct TextDecodeCase {
name: &'static str,
input: &'static str,
oid: i32,
expected_elements: Vec<Option<&'static str>>,
expected_lb: i32,
}

#[test]
fn test_text_decode_table() {
let cases: Vec<(&str, &str, i32, Vec<Option<&str>>, i32)> = vec![
("empty", "{}", 23, vec![], 1),
("single int", "{1}", 23, vec![Some("1")], 1),
(
"three ints",
"{1,2,3}",
23,
vec![Some("1"), Some("2"), Some("3")],
1,
),
("negative int", "{-1}", 23, vec![Some("-1")], 1),
("single NULL", "{NULL}", 23, vec![None], 1),
("NULL mixed case", "{null}", 23, vec![None], 1),
(
"NULL start",
"{NULL,1,2}",
23,
vec![None, Some("1"), Some("2")],
1,
),
("all NULLs", "{NULL,NULL}", 23, vec![None, None], 1),
(
"text elements",
"{hello,world}",
25,
vec![Some("hello"), Some("world")],
1,
),
("quoted comma", r#"{"a,b"}"#, 25, vec![Some("a,b")], 1),
("quoted quote", r#"{"a\"b"}"#, 25, vec![Some("a\"b")], 1),
("quoted backslash", r#"{"a\\b"}"#, 25, vec![Some("a\\b")], 1),
("empty string", r#"{""}"#, 25, vec![Some("")], 1),
(
"quoted NULL literal",
r#"{"NULL"}"#,
25,
vec![Some("NULL")],
1,
),
(
"whitespace around",
"{ 1 , 2 }",
23,
vec![Some("1"), Some("2")],
1,
),
("escaped comma", r#"{a\,b}"#, 25, vec![Some("a,b")], 1),
(
"escaped trailing space",
r#"{a\ }"#,
25,
vec![Some("a ")],
1,
),
(
"escaped null literal",
r#"{\N\U\L\L}"#,
25,
vec![Some("NULL")],
1,
),
(
"custom lower bound",
"[0:2]={1,2,3}",
23,
vec![Some("1"), Some("2"), Some("3")],
0,
),
let cases = vec![
TextDecodeCase {
name: "empty",
input: "{}",
oid: 23,
expected_elements: vec![],
expected_lb: 1,
},
TextDecodeCase {
name: "single int",
input: "{1}",
oid: 23,
expected_elements: vec![Some("1")],
expected_lb: 1,
},
TextDecodeCase {
name: "three ints",
input: "{1,2,3}",
oid: 23,
expected_elements: vec![Some("1"), Some("2"), Some("3")],
expected_lb: 1,
},
TextDecodeCase {
name: "negative int",
input: "{-1}",
oid: 23,
expected_elements: vec![Some("-1")],
expected_lb: 1,
},
TextDecodeCase {
name: "single NULL",
input: "{NULL}",
oid: 23,
expected_elements: vec![None],
expected_lb: 1,
},
TextDecodeCase {
name: "NULL mixed case",
input: "{null}",
oid: 23,
expected_elements: vec![None],
expected_lb: 1,
},
TextDecodeCase {
name: "NULL start",
input: "{NULL,1,2}",
oid: 23,
expected_elements: vec![None, Some("1"), Some("2")],
expected_lb: 1,
},
TextDecodeCase {
name: "all NULLs",
input: "{NULL,NULL}",
oid: 23,
expected_elements: vec![None, None],
expected_lb: 1,
},
TextDecodeCase {
name: "text elements",
input: "{hello,world}",
oid: 25,
expected_elements: vec![Some("hello"), Some("world")],
expected_lb: 1,
},
TextDecodeCase {
name: "quoted comma",
input: r#"{"a,b"}"#,
oid: 25,
expected_elements: vec![Some("a,b")],
expected_lb: 1,
},
TextDecodeCase {
name: "quoted quote",
input: r#"{"a\"b"}"#,
oid: 25,
expected_elements: vec![Some("a\"b")],
expected_lb: 1,
},
TextDecodeCase {
name: "quoted backslash",
input: r#"{"a\\b"}"#,
oid: 25,
expected_elements: vec![Some("a\\b")],
expected_lb: 1,
},
TextDecodeCase {
name: "empty string",
input: r#"{""}"#,
oid: 25,
expected_elements: vec![Some("")],
expected_lb: 1,
},
TextDecodeCase {
name: "quoted NULL literal",
input: r#"{"NULL"}"#,
oid: 25,
expected_elements: vec![Some("NULL")],
expected_lb: 1,
},
TextDecodeCase {
name: "whitespace around",
input: "{ 1 , 2 }",
oid: 23,
expected_elements: vec![Some("1"), Some("2")],
expected_lb: 1,
},
TextDecodeCase {
name: "escaped comma",
input: r#"{a\,b}"#,
oid: 25,
expected_elements: vec![Some("a,b")],
expected_lb: 1,
},
TextDecodeCase {
name: "escaped trailing space",
input: r#"{a\ }"#,
oid: 25,
expected_elements: vec![Some("a ")],
expected_lb: 1,
},
TextDecodeCase {
name: "escaped null literal",
input: r#"{\N\U\L\L}"#,
oid: 25,
expected_elements: vec![Some("NULL")],
expected_lb: 1,
},
TextDecodeCase {
name: "custom lower bound",
input: "[0:2]={1,2,3}",
oid: 23,
expected_elements: vec![Some("1"), Some("2"), Some("3")],
expected_lb: 0,
},
];

for (name, input, oid, expected_elements, expected_lb) in cases {
for TextDecodeCase {
name,
input,
oid,
expected_elements,
expected_lb,
} in cases
{
let array = Array::decode_typed(input.as_bytes(), Format::Text, oid).expect(name);
assert_eq!(array.dim.lower_bound, expected_lb, "lower_bound: {name}");
assert_eq!(
Expand Down
6 changes: 5 additions & 1 deletion pgdog/src/admin/show_servers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ impl Command for ShowServers {
.add("remote_pid", server.stats.id.pid as i64)
.add(
"client_id",
server.stats.client_id.map(|client| client.pid as i64),
server
.stats
.client_id
.as_ref()
.map(|client| client.pid as i64),
)
.add("transactions", server.stats.total.transactions)
.add("queries", server.stats.total.queries)
Expand Down
2 changes: 1 addition & 1 deletion pgdog/src/backend/pool/cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1097,7 +1097,7 @@ mod test {

// Trigger schema_not_needed on each shard after a short delay so the
// waiter wakes up via the per-shard schema_waiter notification.
let shards: Vec<_> = cluster.shards.iter().cloned().collect();
let shards = cluster.shards.to_vec();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_millis(10)).await;
for shard in &shards {
Expand Down
8 changes: 4 additions & 4 deletions pgdog/src/backend/pool/connection/multi_shard/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ fn test_rd_before_dr() {
let result = multi_shard.message();
let id = BackendKeyData::default();
assert_eq!(
result.map(|m| m.backend(id)),
result.map(|m| m.backend(id.clone())),
Some(dr.message().unwrap().backend(id))
);
}
Expand Down Expand Up @@ -236,18 +236,18 @@ fn test_omni_data_rows_only_from_first_server() {
// Setup: send RowDescription from both shards
let rd = RowDescription::new(&[Field::bigint("id")]);
multi_shard
.forward(rd.message().unwrap().backend(backend1))
.forward(rd.message().unwrap().backend(backend1.clone()))
.unwrap();
let rd_result = multi_shard
.forward(rd.message().unwrap().backend(backend2))
.forward(rd.message().unwrap().backend(backend2.clone()))
.unwrap();
assert!(rd_result.is_some()); // RowDescription forwarded after all shards

// DataRow from first shard (backend1) - should be forwarded
let mut dr1 = DataRow::new();
dr1.add(100_i64);
let result = multi_shard
.forward(dr1.message().unwrap().backend(backend1))
.forward(dr1.message().unwrap().backend(backend1.clone()))
.unwrap();
assert!(result.is_some()); // Should be forwarded

Expand Down
6 changes: 2 additions & 4 deletions pgdog/src/backend/pool/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Connection pool errors.
use thiserror::Error;

use crate::net::BackendKeyData;

#[derive(Debug, Error, PartialEq, Clone, Copy)]
pub enum Error {
#[error("checkout timeout")]
Expand Down Expand Up @@ -68,8 +66,8 @@ pub enum Error {
#[error("pool is not healthy")]
PoolUnhealthy,

#[error("checked in untracked connection: {0}")]
UntrackedConnCheckin(BackendKeyData),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine if we don't need it, but I really don't think it'd be a problem to do Box<BackendKeyData> either

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was probably to preserve the Copy derive on the Error struct.

#[error("checked in untracked connection: pid={0}")]
UntrackedConnCheckin(i32),

#[error("mapping missing: {0}")]
MappingMissing(usize),
Expand Down
Loading
Loading