mod common;
use common::pgwire_harness::TestServer;
#[tokio::test]
async fn oid_stable_across_drop_and_recreate() {
let srv = TestServer::start().await;
let read_oid = async |label: &str| -> String {
let rows = srv
.query_text("SELECT oid FROM pg_class WHERE relname = 'oid_stable_test'")
.await
.unwrap_or_else(|e| panic!("query pg_class {label}: {e}"));
assert_eq!(rows.len(), 1, "expected one pg_class row {label}");
rows.into_iter().next().unwrap()
};
srv.exec("CREATE COLLECTION oid_stable_test (id INTEGER PRIMARY KEY, val TEXT)")
.await
.expect("create collection");
let oid_first = read_oid("after first create").await;
srv.exec("DROP COLLECTION oid_stable_test")
.await
.expect("drop 1");
srv.exec("CREATE COLLECTION oid_stable_test (id INTEGER PRIMARY KEY, val TEXT)")
.await
.expect("recreate 1");
let oid_second = read_oid("after recreate 1").await;
srv.exec("DROP COLLECTION oid_stable_test")
.await
.expect("drop 2");
srv.exec("CREATE COLLECTION oid_stable_test (id INTEGER PRIMARY KEY, val TEXT)")
.await
.expect("recreate 2");
let oid_third = read_oid("after recreate 2").await;
assert_eq!(oid_first, oid_second, "OID drifted on first recreate");
assert_eq!(oid_second, oid_third, "OID drifted on second recreate");
}
#[tokio::test]
async fn oid_distinct_for_different_names() {
let srv = TestServer::start().await;
srv.exec("CREATE COLLECTION oid_distinct_alpha (id INTEGER PRIMARY KEY)")
.await
.expect("create alpha");
srv.exec("CREATE COLLECTION oid_distinct_beta (id INTEGER PRIMARY KEY)")
.await
.expect("create beta");
let all_rows = srv
.query_rows("SELECT oid, relname FROM pg_class")
.await
.expect("query pg_class");
let alpha_oid = all_rows
.iter()
.find(|row| row.len() >= 2 && row[1] == "oid_distinct_alpha")
.map(|row| row[0].clone())
.expect("expected a pg_class row for oid_distinct_alpha");
let beta_oid = all_rows
.iter()
.find(|row| row.len() >= 2 && row[1] == "oid_distinct_beta")
.map(|row| row[0].clone())
.expect("expected a pg_class row for oid_distinct_beta");
assert_ne!(
alpha_oid, beta_oid,
"different collection names produced the same OID: {}",
alpha_oid
);
}
#[tokio::test]
async fn pg_index_unique_index_visible() {
let srv = TestServer::start().await;
srv.exec("CREATE COLLECTION idx_unique_test (id INTEGER PRIMARY KEY, email TEXT)")
.await
.expect("create collection");
srv.exec("CREATE UNIQUE INDEX idx_unique_email ON idx_unique_test (email)")
.await
.expect("create unique index");
let class_oids = srv
.query_text("SELECT oid FROM pg_class WHERE relname = 'idx_unique_test'")
.await
.expect("query pg_class");
assert_eq!(class_oids.len(), 1, "expected one pg_class row");
let class_oid = &class_oids[0];
let index_rows = srv
.query_rows("SELECT indexrelid, indrelid, indisunique, indisprimary FROM pg_index")
.await
.expect("query pg_index");
let matching: Vec<_> = index_rows
.iter()
.filter(|row| row.len() >= 4 && &row[1] == class_oid)
.collect();
assert!(
!matching.is_empty(),
"no pg_index row found with indrelid={class_oid}"
);
let unique_row = matching
.iter()
.find(|row| row[2] == "t")
.expect("expected at least one row with indisunique=true");
assert_eq!(
unique_row[3], "f",
"indisprimary should be false, got: {}",
unique_row[3]
);
}
#[tokio::test]
async fn pg_index_non_unique_index_visible() {
let srv = TestServer::start().await;
srv.exec("CREATE COLLECTION idx_nonunique_test (id INTEGER PRIMARY KEY, status TEXT)")
.await
.expect("create collection");
srv.exec("CREATE INDEX idx_status ON idx_nonunique_test (status)")
.await
.expect("create non-unique index");
let class_oids = srv
.query_text("SELECT oid FROM pg_class WHERE relname = 'idx_nonunique_test'")
.await
.expect("query pg_class");
assert_eq!(class_oids.len(), 1, "expected one pg_class row");
let class_oid = &class_oids[0];
let index_rows = srv
.query_rows("SELECT indexrelid, indrelid, indisunique, indisprimary FROM pg_index")
.await
.expect("query pg_index");
let matching: Vec<_> = index_rows
.iter()
.filter(|row| row.len() >= 4 && &row[1] == class_oid)
.collect();
assert!(
!matching.is_empty(),
"no pg_index row found with indrelid={class_oid}"
);
let non_unique_row = matching
.iter()
.find(|row| row[2] == "f")
.expect("expected at least one row with indisunique=false");
assert_eq!(
non_unique_row[3], "f",
"indisprimary should be false, got: {}",
non_unique_row[3]
);
}
#[tokio::test]
async fn pg_index_empty_for_collection_without_indexes() {
let srv = TestServer::start().await;
srv.exec("CREATE COLLECTION idx_empty_test (id INTEGER PRIMARY KEY, name TEXT)")
.await
.expect("create collection");
let class_oids = srv
.query_text("SELECT oid FROM pg_class WHERE relname = 'idx_empty_test'")
.await
.expect("query pg_class");
assert_eq!(class_oids.len(), 1, "expected one pg_class row");
let class_oid = &class_oids[0];
let index_rows = srv
.query_rows("SELECT indexrelid, indrelid, indisunique, indisprimary FROM pg_index")
.await
.expect("query pg_index");
let matching: Vec<_> = index_rows
.iter()
.filter(|row| row.len() >= 4 && &row[1] == class_oid)
.collect();
assert!(
matching.is_empty(),
"expected no pg_index rows for a collection without indexes, found {} rows",
matching.len()
);
}
#[tokio::test]
async fn pg_index_indrelid_matches_pg_class_oid() {
let srv = TestServer::start().await;
srv.exec("CREATE COLLECTION idx_fk_test (id INTEGER PRIMARY KEY, code TEXT)")
.await
.expect("create collection");
srv.exec("CREATE UNIQUE INDEX idx_code ON idx_fk_test (code)")
.await
.expect("create index");
let class_rows = srv
.query_rows("SELECT oid, relname FROM pg_class")
.await
.expect("query pg_class");
let expected_indrelid = class_rows
.iter()
.find(|row| row.len() >= 2 && row[1] == "idx_fk_test")
.map(|row| row[0].clone())
.expect("expected a pg_class row for idx_fk_test");
let index_rows = srv
.query_rows("SELECT indexrelid, indrelid, indisunique, indisprimary FROM pg_index")
.await
.expect("query pg_index");
let found = index_rows
.iter()
.any(|row| row.len() >= 2 && row[1] == expected_indrelid);
assert!(
found,
"pg_index.indrelid={expected_indrelid} not found in pg_index rows: {index_rows:?}"
);
}