Forums | Admin

Discussion Forums: help

Start New Thread Start New Thread

 

By: Kubo Takehiro
RE: char(1) causes 'negative string size' error [ reply ]  
2011-08-27 08:25
This issue is fixed by ruby-oci8 2.1, which will be release in a few weeks or months.

You need to set the following code just after "require 'oci8'."

OCI8.properties[:length_semantics] = :char

If it is :char, the length of Oracle strings is counted by characters. If :byte, it is by bytes.
The default setting is :byte because :char doesn't work well on Oracle 9i though it works fine on Oracle 10g.

By: Kubo Takehiro
RE: char(1) causes 'negative string size' error [ reply ]  
2010-03-14 23:44
Could you change the procedure as follows for a workaround?

From:
PROCEDURE GetLastProcessingDate(
poProcessingDateID OUT processing_dates.processing_date_id%TYPE,
poProcessingDate OUT processing_dates.processing_date%TYPE,
poStatus OUT processing_dates.status%TYPE )

To:
PROCEDURE GetLastProcessingDate(
poProcessingDateID OUT processing_dates.processing_date_id%TYPE,
poProcessingDate OUT processing_dates.processing_date%TYPE,
poStatus OUT VARCHAR2 )

By: Kubo Takehiro
RE: char(1) causes 'negative string size' error [ reply ]  
2010-03-03 12:16
Thank you for the test code. I can reproduce the problem on my linux box and Oracle 10g XE.
I doubt that it may be an Oracle bug. But I'll look for a workaround.

By: Ronald Roy
char(1) causes 'negative string size' error [ reply ]  
2010-03-02 01:22
I have a table processing_dates with a status column of char(1). I use a stored proc to get me the most recent processing_date. I can bind to all the out params of the stored proc, but when I get the value from the cursor it causes a "negative string size" ArgumentError to be raised. I actually hacked a solution by modifying bind_string_get within bind.c to convert all negative string lengths to 1. This works, but I don't think its a general solution.

Below is some slightly modified versions of the table, stored, proc, and the ruby code that failed.
------

CREATE TABLE "processing_dates"
( "processing_date_id" NUMBER NOT NULL ENABLE,
"processing_date" DATE DEFAULT SYSDATE NOT NULL ENABLE,
"status" CHAR(1 BYTE) DEFAULT '0' NOT NULL ENABLE);

PROCEDURE GetLastProcessingDate(
poProcessingDateID OUT processing_dates.processing_date_id%TYPE,
poProcessingDate OUT processing_dates.processing_date%TYPE,
poStatus OUT processing_dates.status%TYPE )
AS BEGIN
SELECT processing_date_id, processing_date, status
INTO poProcessingDateID, poProcessingDate, poStatus
FROM ( SELECT processing_date_id, processing_date, status
FROM processing_dates ORDER BY processing_date_id DESC)
WHERE rownum <= 1;
END GetLastProcessingDate;

---------
# @conn is the OCI8 to the database
cursor = @conn.parse('BEGIN GetLastProcessingDate( :id, :date, :status ); END;')
cursor.bind_param(':id', nil, Integer)
cursor.bind_param(':date', nil, Time)
cursor.bind_param(':status', '0', String, 1)
cursor.exec

@processing_date = cursor[':date']
@processing_date_id = cursor[':id']

# The next line raises an ArgumentException: negative string size
@status = cursor[':status']

-----
// The 100% hack I did was to add a 'sz' variable to the bind_string_get method.
// Below is the 100% hack from bind.c:

static VALUE bind_string_get(oci8_bind_t *obind, void *data, void *null_struct)
{
int sz;
oci8_vstr_t *vstr = (oci8_vstr_t *)data;
sz = vstr->size;
if (sz < 0) sz = 1;
return rb_external_str_new_with_enc(vstr->buf, sz, oci8_encoding);
}
-----

Please let me know if you need any more details.