How to set OracleCallableStatement.Regist… to use byte instead of char?

sharok das

Greenhorn

Posts: 5

posted 4 years ago

In the OracleCallableStatement function called registerOutParameter (shown below), how do I ensure that the maxLength is in bytes and not Chars??? (Java Chars are two bytes/char but I like to be specify 5 bytes. The explaination give below says it depends on OracleConnection.getDataSizeUnits(). But this function seem to be not working and nothing is found on google in regards to it. My database charset has char = 1 byte. And the size should be exactly 5 bytes. But java char has 2 bytes/char. The functionionality they are specifying in the spec "Depending on the value of OracleConnection.getDataSizeUnits(), maxLength will be measured in bytes or characters." does not seem to work.

------------------
void registerOutParameter(java.lang.String parameterName, int sqlType, int scale, int maxLength) throws java.sql.SQLException Special Oracle version of registerOutParameter for registering CHAR, VARCHAR, LONG, RAW and LONG RAW columns. Depending on the value of OracleConnection.getDataSizeUnits(), maxLength will be measured in bytes or characters.

Parameters:
parameterName - the name of the parameter
sqlType - SQL type code defined by java.sql.Types.
scale - the desired number of digits to the right of the decimal point. It must be greater than or equal to zero.
maxLength - maximum length of the column, specified in bytes or characters.

The link to the function:
docs.oracle.com/cd/E18283_01/appdev.112/e13995/oracle/jdbc/OracleCallableStatement.html#registerOutParameter_java_lang_String__int__int__int_

Thanks, Sharok

Ireneusz Kordal

Ranch Hand

Posts: 423

posted 4 years ago

Why do you need 5 bytes, could you explain what kind of data is stored in this field ?

sharok das

Greenhorn

Posts: 5

posted 4 years ago

The data is alphanumeric of exactly char(5). The existing stored procedure has an out variable that is exactly char(5). There is also a field on a table that is char(5) for this. The procedure inserts the generated value before passing it back to the java program. The same java program will need to run against different oracle databases. Some of these databases have a charsets where each char occupies 1 byte and in some others each char occupies 2 bytes. If the java program does not set the out parameter to the proper number of bytes, the stored procedure crashes since the same variable is used to do insert into the table from the stored procedure. The crash does not happen because the procedure is trying to return the value to java, it crashes (due to size mismatch) while doing the insert the generated value into the table. The size of the variable set by the registerOutParamet is automatically propagated into the stored procedure so it must have exact bytes depending on the charset, either 5 bytes or 10 bytes. In the java function registerOutParameter I specify 5 for the maxLength and CHAR for the sqlType. It should automatically detect the database charset (1 byte/char or 2 bytes/char) and set the byte size accordingly. The documentation does say that this is automatically detected:
"Depending on the value of OracleConnection.getDataSizeUnits(), maxLength will be measured in bytes or characters."
But that does not seem to be the case. When I test the java program against a database with a charset where i know it has 1 byte/char, it crashes saying there are 10 bytes instead of 5. So, the data size is not automatically detected by the so called "OracleConnection.getDataSizeUnits()" function as the documentation specifies. BTW, I could not find any trace of this "OracleConnection.getDataSizeUnits()" anywhere on google.

Run error:
java.sql.SQLException: ORA-12899: value too large for column "R13"."JOB"."ID" (actual: 10, maximum: 5)
ORA-06512: at "R13.ES_JOB", line 261
ORA-06512: at "R13.ES_JOB", line 339
ORA-06512: at line 1

The obvious solution would be to declare another variable as CHAR(5) in the stored procedure to hold the value of the ID and use it to put that value into a table, then, at the end of the procedure, copy this variable into the output parameter. This way you could completely avoid all this trickery and use JDBC's normal registerOutParameter without bothering about the output parameter's length.

Anyway, a much better design would certainly be to declare the job ID as a number and feed it from a sequence. That is the way these things should be done on Oracle and it is guaranteed to work on all versions since at least 8, regardless of their character sets. ID is just an ID, you should not try to store additional information into it. If you need an additional information, store it into a column of its own.