Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with loading large clob values via returning clauses #64

Open
weiznich opened this issue Sep 26, 2022 · 2 comments
Open

Problems with loading large clob values via returning clauses #64

weiznich opened this issue Sep 26, 2022 · 2 comments

Comments

@weiznich
Copy link
Contributor

I've tried the following code:

use oracle::*; // oracle = "0.5.6"

const CREATE_TEST_TABLE: &str = "CREATE TABLE test_table (\
        text clob
    )";

fn repro(conn: Connection) {
    let _ = conn.execute("DROP TABLE test_table", &[]);
    conn.execute(CREATE_TEST_TABLE, &[]).unwrap();
    let mut stmt = conn
        .statement("INSERT INTO test_table(text) VALUES (:in1) RETURNING text INTO :out1")
        .build()
        .unwrap();
    let long_text = std::iter::repeat('a').take(4000).collect::<String>();
    stmt.execute_named(&[("in1", &long_text), ("out1", &None::<String>)])
        .unwrap();
    let s: &String = &stmt.returned_values("out1").unwrap()[0];
    assert_eq!(s, &long_text);
}

I expect that this code passes without an error for a valid connection. Instead of that I get the following error message:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: OciError(DbError { code: 22835, offset: 53, message: "ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion (actual: 4000, maximum: 2000)", fn_name: "dpiStmt_execute", action: "execute" })', src/main.rs:16:10

(where line main.rs:16 refers to the unwrap after the execute_named)

@kubo
Copy link
Owner

kubo commented Sep 26, 2022

There are three ways. The second and third ones are usually unacceptable.

  1. Use OracleType::CLOB in place of None::<String> and get the CLOB value as Clob.
  2. Use OracleType::Varchar2(4000) in place of None::<String> if the maximum size of CLOB data is 4000.
  3. Use OracleType::Varchar2(32767) in place of None::<String> and change the Oracle initialization parameter MAX_STRING_SIZE to EXTENDED if the maximum size of CLOB data is 32767. (I have not tested this...)
use oracle::sql_type::{Clob, OracleType};
use oracle::Connection;
use std::io::Read; // for clob.read_to_string

const CREATE_TEST_TABLE: &str = "CREATE TABLE test_table (\
        text clob
    )";

fn repro(conn: Connection) {
    let _ = conn.execute("DROP TABLE test_table", &[]);
    conn.execute(CREATE_TEST_TABLE, &[]).unwrap();
    let mut stmt = conn
        .statement("INSERT INTO test_table(text) VALUES (:in1) RETURNING text INTO :out1")
        .build()
        .unwrap();
    let long_text = std::iter::repeat('a').take(4000).collect::<String>();
    stmt.execute_named(&[("in1", &long_text), ("out1", &OracleType::CLOB)])
        .unwrap();
    // https://docs.rs/oracle/latest/oracle/sql_type/struct.Clob.html
    let mut clob: Clob = stmt.returned_values("out1").unwrap().remove(0);
    let mut s = String::new();
    clob.read_to_string(&mut s).unwrap();
    assert_eq!(&s, &long_text);
}

@weiznich
Copy link
Contributor Author

Thanks for the fast answer. For context the real code casing this is coming from diesel-oci, so it's much more generic and cannot assume much about the actual fields. Solution 2 will not work there. Solution 1 works for CLOB columns, but won't work if the user tries to load a VARCHAR column (diesel-oci does currently not differentiate between these two types). Using the maximal-size variant sounds like it has some negative implications, is that correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants