fn main() -> libpq::errors::Result {
let mut args = std::env::args();
if args.len() < 5 {
panic!(
"usage: {} database_name in_filename out_filename out_filename2",
args.next().unwrap()
);
}
let database = args.nth(1).unwrap();
let in_filename = args.next().unwrap();
let out_filename = args.next().unwrap();
let out_filename2 = args.next().unwrap();
let conn = libpq::Connection::set_db(None, None, None, None, Some(&database))?;
let res = conn.exec("SELECT pg_catalog.set_config('search_path', '', false)");
if res.status() != libpq::Status::TuplesOk {
panic!("SET failed: {:?}", conn.error_message());
}
conn.exec("begin");
println!("importing file \"{in_filename}\" ...");
let lobj_oid = libpq::lo::import(&conn, &in_filename);
println!("\tas large object {lobj_oid}.");
println!("picking out bytes 4294967000-4294968000 of the large object");
pickout(&conn, lobj_oid, 4_294_967_000, 1_000)?;
println!("overwriting bytes 4294967000-4294968000 of the large object with X's");
overwrite(&conn, lobj_oid, 4_294_967_000, 1_000)?;
println!("exporting large object to file \"{out_filename}\" ...");
libpq::lo::export(&conn, &out_filename, lobj_oid)?;
println!("truncating to 3294968000 bytes");
my_truncate(&conn, lobj_oid, 3_294_968_000)?;
println!("exporting truncated large object to file \"{out_filename2}\" ...");
libpq::lo::export(&conn, &out_filename2, lobj_oid)?;
conn.exec("end");
Ok(())
}
fn pickout(
conn: &libpq::Connection,
lobj_id: libpq::Oid,
start: i64,
len: usize,
) -> libpq::errors::Result {
let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::READ)?;
lobj.lseek64(start, libpq::lo::Seek::Set)?;
if lobj.tell64()? != start {
panic!("error in lo_tell64: {:?}", conn.error_message());
}
let mut nread = 0;
while len - nread > 0 {
let mut buf = lobj.read(len - nread)?;
let nbytes = buf.len();
buf.insert(nbytes, '\0');
eprint!(">>> {buf}");
nread += nbytes;
if nbytes == 0 {
break;
}
}
eprintln!();
Ok(())
}
fn overwrite(
conn: &libpq::Connection,
lobj_id: libpq::Oid,
start: i64,
len: usize,
) -> libpq::errors::Result {
let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::WRITE)?;
lobj.lseek64(start, libpq::lo::Seek::Set)?;
let mut buf = "X".repeat(len);
buf.insert(len - 1, '\0');
let mut nwritten = 0;
while len - nwritten > 0 {
let nbytes = lobj.write(&buf[nwritten..len - nwritten])?;
nwritten += nbytes;
}
eprintln!();
Ok(())
}
fn my_truncate(conn: &libpq::Connection, lobj_id: libpq::Oid, len: i64) -> libpq::errors::Result {
let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::WRITE)?;
lobj.truncate64(len)
}