use spg_engine::{Engine, QueryResult};
use spg_storage::Value;
fn one(e: &mut Engine, sql: &str) -> Value<'static> {
match e
.execute(sql)
.unwrap_or_else(|err| panic!("{sql}: {err:?}"))
{
QueryResult::Rows { rows, .. } => rows[0].values[0].clone(),
other => panic!("expected rows, got {other:?}"),
}
}
fn text(e: &mut Engine, sql: &str) -> String {
match one(e, sql) {
Value::Text(s) => s.to_string(),
other => panic!("expected text, got {other:?}"),
}
}
fn bigint(e: &mut Engine, sql: &str) -> i64 {
match one(e, sql) {
Value::BigInt(n) => n,
other => panic!("expected bigint, got {other:?}"),
}
}
#[test]
fn txid_current_is_a_real_id_not_a_stub() {
let mut e = Engine::new();
assert!(bigint(&mut e, "SELECT txid_current()") > 1);
assert_eq!(
one(&mut e, "SELECT txid_current() = txid_current()"),
Value::Bool(true)
);
assert!(bigint(&mut e, "SELECT pg_current_xact_id()") > 1);
}
#[test]
fn if_assigned_is_null_without_an_assigned_id() {
let mut e = Engine::new();
assert_eq!(
one(&mut e, "SELECT pg_current_xact_id_if_assigned()"),
Value::Null
);
assert_eq!(
one(&mut e, "SELECT txid_current_if_assigned()"),
Value::Null
);
}
#[test]
fn txid_is_stable_across_statements_of_a_transaction() {
let mut e = Engine::new();
e.execute("BEGIN").unwrap();
let a = bigint(&mut e, "SELECT txid_current()");
let b = bigint(&mut e, "SELECT txid_current()");
assert_eq!(a, b, "a transaction keeps one id across its statements");
assert_eq!(
one(&mut e, "SELECT pg_current_xact_id_if_assigned()"),
Value::BigInt(a)
);
e.execute("COMMIT").unwrap();
}
#[test]
fn xact_status_reports_all_three_states() {
let mut e = Engine::new();
e.execute("BEGIN").unwrap();
let live = bigint(&mut e, "SELECT txid_current()");
assert_eq!(
text(&mut e, "SELECT txid_status(txid_current())"),
"in progress"
);
e.execute("COMMIT").unwrap();
assert_eq!(
text(&mut e, &format!("SELECT txid_status({live})")),
"committed"
);
e.execute("BEGIN").unwrap();
let dead = bigint(&mut e, "SELECT txid_current()");
e.execute("ROLLBACK").unwrap();
assert_eq!(
text(&mut e, &format!("SELECT txid_status({dead})")),
"aborted"
);
assert_eq!(
text(&mut e, &format!("SELECT pg_xact_status({live})")),
"committed"
);
}
#[test]
fn xact_status_rejects_an_id_never_handed_out() {
let mut e = Engine::new();
let err = e
.execute("SELECT txid_status(txid_current() + 1000)")
.unwrap_err();
let msg = format!("{err:?}");
assert!(msg.contains("in the future"), "unexpected error: {msg}");
assert_eq!(one(&mut e, "SELECT txid_status(NULL)"), Value::Null);
}