mod common;
use common::pgwire_harness::TestServer;
async fn is_session_param_fallback(server: &TestServer, sql: &str, param: &str) -> bool {
let rows = match server.query_named_rows(sql).await {
Ok(r) => r,
Err(_) => return false,
};
if rows.len() != 1 {
return false;
}
let row = &rows[0];
if row.len() != 1 {
return false;
}
row.iter()
.any(|(k, v)| k.eq_ignore_ascii_case(param) && v.is_empty())
}
#[tokio::test]
async fn show_databases_lists_created_database() {
let server = TestServer::start().await;
server
.exec("CREATE DATABASE show_dispatch_alpha")
.await
.expect("CREATE DATABASE must succeed");
let rows = server
.query_named_rows("SHOW DATABASES")
.await
.expect("SHOW DATABASES must not error");
assert!(
rows.len() >= 2,
"SHOW DATABASES must list both `default` and the created database; got {} row(s): {:?}",
rows.len(),
rows
);
assert!(
rows[0].contains_key("name"),
"SHOW DATABASES must expose a `name` column (got columns: {:?})",
rows[0].keys().collect::<Vec<_>>()
);
assert!(
rows.iter().any(|r| r
.get("name")
.map(|n| n == "show_dispatch_alpha")
.unwrap_or(false)),
"SHOW DATABASES must include the row created by CREATE DATABASE: {rows:?}"
);
assert!(
!is_session_param_fallback(&server, "SHOW DATABASES", "databases").await,
"SHOW DATABASES must not be routed to the session-parameter fallback"
);
}
#[tokio::test]
async fn show_roles_lists_created_role() {
let server = TestServer::start().await;
server
.exec("CREATE ROLE show_dispatch_role")
.await
.expect("CREATE ROLE must succeed");
let rows = server
.query_named_rows("SHOW ROLES")
.await
.expect("SHOW ROLES must not error");
assert!(
!rows.is_empty(),
"SHOW ROLES must return at least one row; got empty result"
);
assert!(
rows[0].len() >= 2 || !rows[0].contains_key("roles"),
"SHOW ROLES must use a typed multi-column schema, not the single \
`roles` column session-parameter fallback (got columns: {:?})",
rows[0].keys().collect::<Vec<_>>()
);
assert!(
rows.iter()
.any(|r| r.values().any(|v| v == "show_dispatch_role")),
"SHOW ROLES must include the created role: {rows:?}"
);
assert!(
!is_session_param_fallback(&server, "SHOW ROLES", "roles").await,
"SHOW ROLES must not be routed to the session-parameter fallback"
);
}
#[tokio::test]
async fn show_stats_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW STATS", "stats").await,
"SHOW STATS must not be routed to the session-parameter fallback \
(single-column `stats` with empty value)"
);
}
#[tokio::test]
async fn show_server_stats_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW SERVER STATS", "server stats").await,
"SHOW SERVER STATS must not be routed to the session-parameter fallback"
);
}
#[tokio::test]
async fn show_metrics_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW METRICS", "metrics").await,
"SHOW METRICS must not be routed to the session-parameter fallback"
);
}
#[tokio::test]
async fn show_memory_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW MEMORY", "memory").await,
"SHOW MEMORY must not be routed to the session-parameter fallback"
);
}
#[tokio::test]
async fn show_schedules_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW SCHEDULES", "schedules").await,
"SHOW SCHEDULES must reach its admin-router handler, not the \
session-parameter fallback"
);
}
#[tokio::test]
async fn show_sequences_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW SEQUENCES", "sequences").await,
"SHOW SEQUENCES must reach its admin-router handler, not the \
session-parameter fallback"
);
}
#[tokio::test]
async fn show_alerts_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW ALERTS", "alerts").await,
"SHOW ALERTS must reach its admin-router handler, not the \
session-parameter fallback"
);
}
#[tokio::test]
async fn show_materialized_views_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW MATERIALIZED VIEWS", "materialized views",).await,
"SHOW MATERIALIZED VIEWS must reach its admin-router handler, \
not the session-parameter fallback"
);
}
#[tokio::test]
async fn show_blacklist_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW BLACKLIST", "blacklist").await,
"SHOW BLACKLIST must reach its admin-router handler, not the \
session-parameter fallback"
);
}
#[tokio::test]
async fn show_orgs_is_not_session_param_fallback() {
let server = TestServer::start().await;
assert!(
!is_session_param_fallback(&server, "SHOW ORGS", "orgs").await,
"SHOW ORGS must reach its admin-router handler, not the \
session-parameter fallback"
);
}
#[tokio::test]
async fn show_unknown_parameter_returns_42704() {
let server = TestServer::start().await;
match server
.client
.simple_query("SHOW totally_made_up_parameter_xyz")
.await
{
Ok(msgs) => panic!(
"SHOW on an unknown parameter must error with 42704, got success: \
{msgs:?}"
),
Err(e) => {
let code = e.code().map(|c| c.code().to_string()).unwrap_or_default();
let msg = e
.as_db_error()
.map(|d| d.message().to_string())
.unwrap_or_else(|| e.to_string());
assert!(
code == "42704" || msg.contains("unrecognized configuration"),
"expected 42704 / unrecognized configuration parameter, got \
code={code:?} msg={msg:?}"
);
}
}
}
#[tokio::test]
async fn show_builtin_pg_runtime_parameters_still_work() {
let server = TestServer::start().await;
let version = server
.query_text("SHOW server_version")
.await
.expect("SHOW server_version must succeed");
assert_eq!(version.len(), 1, "SHOW server_version must return one row");
assert!(
version[0].contains("NodeDB"),
"SHOW server_version must report a NodeDB version string, got: {:?}",
version[0]
);
let encoding = server
.query_text("SHOW server_encoding")
.await
.expect("SHOW server_encoding must succeed");
assert_eq!(encoding, vec!["UTF8".to_string()]);
let all = server
.query_rows("SHOW ALL")
.await
.expect("SHOW ALL must succeed");
let _ = all;
}
#[tokio::test]
async fn show_session_set_parameter_round_trips() {
let server = TestServer::start().await;
server
.exec("SET application_name = 'mae8_bootstrap'")
.await
.expect("SET application_name must succeed");
let rows = server
.query_text("SHOW application_name")
.await
.expect("SHOW application_name must succeed");
assert_eq!(rows, vec!["mae8_bootstrap".to_string()]);
}