1fn main() -> libpq::errors::Result {
8 let mut args = std::env::args();
9
10 if args.len() < 5 {
11 panic!(
12 "usage: {} database_name in_filename out_filename out_filename2",
13 args.next().unwrap()
14 );
15 }
16
17 let database = args.nth(1).unwrap();
18 let in_filename = args.next().unwrap();
19 let out_filename = args.next().unwrap();
20 let out_filename2 = args.next().unwrap();
21
22 let conn = libpq::Connection::set_db(None, None, None, None, Some(&database))?;
26
27 let res = conn.exec("SELECT pg_catalog.set_config('search_path', '', false)");
29 if res.status() != libpq::Status::TuplesOk {
30 panic!("SET failed: {:?}", conn.error_message());
31 }
32
33 conn.exec("begin");
34
35 println!("importing file \"{in_filename}\" ...");
36 let lobj_oid = libpq::lo::import(&conn, &in_filename);
37
38 println!("\tas large object {lobj_oid}.");
39
40 println!("picking out bytes 4294967000-4294968000 of the large object");
41 pickout(&conn, lobj_oid, 4_294_967_000, 1_000)?;
42
43 println!("overwriting bytes 4294967000-4294968000 of the large object with X's");
44 overwrite(&conn, lobj_oid, 4_294_967_000, 1_000)?;
45
46 println!("exporting large object to file \"{out_filename}\" ...");
47 libpq::lo::export(&conn, &out_filename, lobj_oid)?;
48
49 println!("truncating to 3294968000 bytes");
50 my_truncate(&conn, lobj_oid, 3_294_968_000)?;
51
52 println!("exporting truncated large object to file \"{out_filename2}\" ...");
53 libpq::lo::export(&conn, &out_filename2, lobj_oid)?;
54
55 conn.exec("end");
56
57 Ok(())
58}
59
60fn pickout(
61 conn: &libpq::Connection,
62 lobj_id: libpq::Oid,
63 start: i64,
64 len: usize,
65) -> libpq::errors::Result {
66 let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::READ)?;
67
68 lobj.lseek64(start, libpq::lo::Seek::Set)?;
69
70 if lobj.tell64()? != start {
71 panic!("error in lo_tell64: {:?}", conn.error_message());
72 }
73
74 let mut nread = 0;
75
76 while len - nread > 0 {
77 let mut buf = lobj.read(len - nread)?;
78 let nbytes = buf.len();
79 buf.insert(nbytes, '\0');
80 eprint!(">>> {buf}");
81 nread += nbytes;
82 if nbytes == 0 {
83 break; }
85 }
86 eprintln!();
87
88 Ok(())
89}
90
91fn overwrite(
92 conn: &libpq::Connection,
93 lobj_id: libpq::Oid,
94 start: i64,
95 len: usize,
96) -> libpq::errors::Result {
97 let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::WRITE)?;
98
99 lobj.lseek64(start, libpq::lo::Seek::Set)?;
100 let mut buf = "X".repeat(len);
101 buf.insert(len - 1, '\0');
102
103 let mut nwritten = 0;
104 while len - nwritten > 0 {
105 let nbytes = lobj.write(&buf[nwritten..len - nwritten])?;
106 nwritten += nbytes;
107 }
108 eprintln!();
109
110 Ok(())
111}
112
113fn my_truncate(conn: &libpq::Connection, lobj_id: libpq::Oid, len: i64) -> libpq::errors::Result {
114 let lobj = libpq::lo::open(conn, lobj_id, libpq::lo::Inv::WRITE)?;
115
116 lobj.truncate64(len)
117}