fn main() -> Result<(), Box<dyn std::error::Error>> {
let conninfo = std::env::args()
.nth(1)
.unwrap_or_else(|| "dbname = postgres".to_string());
let conn = libpq::Connection::new(&conninfo)?;
let res = conn.exec("SET search_path = testlibpq3");
if res.status() != libpq::Status::CommandOk {
panic!("SET failed: {:?}", conn.error_message());
}
let param_values = [Some("joe's place\0".as_bytes())];
let res = conn.exec_params(
"SELECT * FROM test1 WHERE t = $1",
&[],
param_values.as_slice(),
&[],
libpq::Format::Binary,
);
if res.status() != libpq::Status::TuplesOk {
panic!("SELECT failed: {:?}", conn.error_message());
}
show_binary_results(&res)?;
let binary_int_val = htonl(2);
let param_values = [Some(binary_int_val.as_slice())];
let param_formats = vec![libpq::Format::Binary];
let res = conn.exec_params(
"SELECT * FROM test1 WHERE i = $1::int4",
&[],
¶m_values,
¶m_formats,
libpq::Format::Binary,
);
if res.status() != libpq::Status::TuplesOk {
panic!("SELECT failed: {:?}", conn.error_message());
}
show_binary_results(&res)?;
Ok(())
}
fn show_binary_results(res: &libpq::Result) -> Result<(), Box<dyn std::error::Error>> {
let i_fnum = res.field_number("i").unwrap();
let t_fnum = res.field_number("t").unwrap();
let b_fnum = res.field_number("b").unwrap();
for i in 0..res.ntuples() {
let iptr = res.value(i, i_fnum).unwrap();
let tptr = res.value(i, t_fnum).unwrap();
let bptr = res.value(i, b_fnum).unwrap();
let ival = ntohl(iptr)?;
let blen = res.length(i, b_fnum);
println!("tuple {i}: got");
println!(" i = ({} bytes) {ival}", res.length(i, i_fnum));
println!(
" t = ({} bytes) '{}'",
res.length(i, t_fnum),
String::from_utf8(tptr.to_vec())?
);
print!(" b = ({blen} bytes) ");
for item in bptr.iter().take(blen) {
print!("\\{item:03o}");
}
println!("\n");
}
Ok(())
}
fn ntohl(netlong: &[u8]) -> Result<i32, std::array::TryFromSliceError> {
netlong[..4].try_into().map(i32::from_be_bytes)
}
fn htonl(hostlong: i32) -> Vec<u8> {
hostlong.to_be_bytes().to_vec()
}