Skip to main content

testlo64/
testlo64.rs

1/*!
2 * Test using large objects with libpq using 64-bit APIs
3 *
4 * <https://github.com/postgres/postgres/blob/REL_16_0/src/test/examples/testlo64.c>
5 */
6
7fn 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    /*
23     * set up the connection
24     */
25    let conn = libpq::Connection::set_db(None, None, None, None, Some(&database))?;
26
27    /* Set always-secure search path, so malicious users can't take control. */
28    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; /* no more data? */
84        }
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}