Oracle RawToHex function - what happens if return value exceeds varchar2 limit? - oracle

The RawToHex function in Oracle 11g returns a hexadecimal representation of any raw value.
This function returns the Hex Value as a varchar2.
What happens if I pass a BLOB into the RawToHex() function that will result in a hex representation that exceeds the varchar2 limit of 4000?
Is there any way to convert very big BLOBs into a Hex representation?
UPDATE:
I did some investigation and found an answer for the first part of my question.
I can pass a BLOB into the RawToHex function and this one will execute successfully as long as you won't hit the boundaries of the Raw DataType. Oracle seems to convert from BLOB to Raw implicitly.
DECLARE
a varchar2(32767);
b blob;
BEGIN
select blob_column into b from a_table where a_table_id = 1;
dbms_output.put_line(dbms_lob.getlength(b)); --> output: 216
dbms_output.put_line(rawtohex(empty_blob())); --> converted blob
select blob_column into b from a_table where a_table_id = 2;
dbms_output.put_line(dbms_lob.getlength(b)); --> output: 140000
dbms_output.put_line(rawtohex(empty_blob())); --> ORA-06502: PL/SQL: numeric or value error
END;
Description of this error according to ora-code.com
ORA-06502: PL/SQL: numeric or value error string
Cause: An arithmetic, numeric, string, conversion, or constraint error occurred. For example, this error occurs if an attempt is made to assign the value NULL to a variable declared NOT NULL, or if an attempt is made to assign an integer larger than 99 to a variable declared NUMBER(2).
Action: Change the data, how it is manipulated, or how it is declared so that values do not violate constraints.
UPDATE 2:
I've got a solution for this issue. Splitting the blob into smaller blocks and converting them step by step. It delivers the correct result. Is this a correct approach or could this solution fall over at some point?
function BlobToHex(data in blob) return clob
is
v_clob clob;
v_start pls_integer := 1;
v_buffer pls_integer := 4000;
begin
if data is null
then
return '""';
end if;
dbms_lob.createtemporary(v_clob, true);
dbms_lob.append(v_clob, '0x');
for i in 1..ceil(dbms_lob.getlength(data) / v_buffer)
loop
dbms_lob.append(v_clob, rawtohex(DBMS_LOB.SUBSTR(data, v_buffer, v_start)));
v_start := v_start + v_buffer;
end loop;
return v_clob;
end;

You'll get ORA-00932
SQL> select rawtohex(empty_blob()) from dual;
select rawtohex(empty_blob()) from dual
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected - got BLOB
SQL>
because
As a SQL built-in function, RAWTOHEX accepts an argument of any scalar data type other than LONG, LONG RAW, CLOB, BLOB, or BFILE.
As stated by the documentation.

Related

VARCHAR2(32767) not able to handle strings in stored procedure

I am concatenating string using cursor (to form query to execute later). Here, the query that will be formed is going to be way bigger that what VARCHAR2(32767) can handle. There fore, I am getting error on proc execution - ORA-06502: PL/SQL: numeric or value error: character string buffer too small.
I used CLOB data type as well bu got error ORA-06502: PL/SQL: numeric or value error.
My code is here below:
CREATE OR REPLACE PROCEDURE sp_Market
IS
Names VARCHAR2(32767);
BEGIN
DECLARE CURSOR cur IS ('Select ID, Order_of, field_name
FROM pld_medicare_config');
BEGIN
FOR i IN cur
LOOP
Names := Names || i.sqql;
END LOOP;
dbms_output.put_line(Names);
END;
END sp_Market;
How can I handle my string of queries and what data type is there to accomplish the task?
CLOB is OK (as far as I can tell); I doubt queries you store in there are that big.
Remove dbms_output.put_line call from the procedure; I suspect it is the one that raises the error.
I'm not sure how you got any runtime error, as your procedure won't compile.
The valid PL/SQL version would look something like this:
create or replace procedure sp_market is
names varchar2(32767);
begin
for r in (
select id, order_of, field_name
from pld_medicare_config
)
loop
names := names || ' ' || r.field_name;
end loop;
names := ltrim(names);
dbms_output.put_line(names);
end sp_market;
If names needs to be longer, change the datatype to clob.
Use the CLOB datatype and append data using the dbms_lob.writeappend procedure. This is the reference (Oracle 18c).
The error probably origins with the dbms_output.put_line call. The procedure is defined for varchar2 arguments only which means that an implicit conversion takes place during the call. It will fail for clob contents longer than 32767 chars/bytes.
Alternatively you may declare a collection over varchar2(4000) and fill the collection elements sequentially:
CREATE OR REPLACE PROCEDURE sp_Market
IS
TYPE tLongString IS TABLE OF VARCHAR2(4000) INDEX BY BINARY_INTEGER;
cNames tLongString;
BEGIN
DECLARE CURSOR cur IS Select ID, Order_of, field_name, sqql FROM pld_medicare_config;
BEGIN
FOR i IN cur
LOOP
cNames(cNames.COUNT+1) := i.sqql;
END LOOP;
END;
END sp_Market;
Note
Rectified code, will compile now.

numeric or value error: raw variable length too long ORA-06512: at "SYS.UTL_RAW"

I am facing raw variable length too long issue when select the BLOB(Stored JSON string) filed value from the table.
Query:
select utl_raw.cast_to_varchar2(dbms_lob.substr(TRANSACTION_DATA)) from PS_ISA_INB_PAYLOAD_LOG;
This is my SP i have used to insert the JSON object into BLOB Field:
create or replace PROCEDURE SDIX_TICK_LOG
(
ORGANIZATIONNAME IN VARCHAR2
, TRANSACTION_TYPE IN VARCHAR2
, TRANSACTION_DATA IN BLOB
, TRANSACTION_STATUS IN VARCHAR2
) AS
l_r RAW(32767);
l_blob blob;
l_clob clob :='"ItemMasterTransfer":[{"ORACLE_UNIQUE_REC_ID":"123assd4434","CUSTOMER_ID":"PMC","ORGANIZATION_CODE":"BMftrdsM","ITEM":"696738","INVENTORY_ITEM_ID":"0000000000000000000000000000546","ORGANIZATION_ID":" ","SUBINVENTORY_CODE":"000000000000000000","LOCATOR_ID":" ","ISA_MATERIAL_GROUP":" ","TAX_GROUP":" ","CATEGORY_ID":"1956","NOUN":" ","MODIFIER":" ","MANUFACTURER_ID":" ","MFG_ITEM_ID":" ","UNIT_OF_MEASURE":"BOX","ITEM_TYPE":"P","STOCK_ENABLED_FLAG":"Y","INVENTORY_ITEM_STATUS_CODE":"A","LIST_PRICE_PER_UNIT":"0","FULL_LEAD_TIME":"0","MAX_MINMAX_QUANTITY":"10","MIN_MINMAX_QUANTITY":"10","SAFETY_LEVEL":"0","REPLENISH_TO_ORDER_FLAG":"N","UTILIZ_CD":"","CURRENCY_CD":"USD","DESCRIPTION":"","ATTRIBUTE1":" ","ATTRIBUTE2":" ","ATTRIBUTE3":" ","ATTRIBUTE4":" ","ATTRIBUTE5":" ","ATTRIBUTE6":" ","ATTRIBUTE7":" ","ATTRIBUTE8":" ","ATTRIBUTE9":" ","ATTRIBUTE10":" ","TRANSACTION_STATUS":" ","TRANS_STATUS_DESCRIPTION":" "},{"ORACLE_UNIQUE_REC_ID":"123assd4434","CUSTOMER_ID":"PMC","ORGANIZATION_CODE":"BMftrdsM","ITEM":"696738","INVENTORY_ITEM_ID":"0000000000000000000000000000546","ORGANIZATION_ID":" ","SUBINVENTORY_CODE":"000000000000000000","LOCATOR_ID":" ","ISA_MATERIAL_GROUP":" ","TAX_GROUP":" ","CATEGORY_ID":"1956","NOUN":" ","MODIFIER":" ","MANUFACTURER_ID":" ","MFG_ITEM_ID":" ","UNIT_OF_MEASURE":"BOX","ITEM_TYPE":"P","STOCK_ENABLED_FLAG":"Y","INVENTORY_ITEM_STATUS_CODE":"A","LIST_PRICE_PER_UNIT":"0","FULL_LEAD_TIME":"0","MAX_MINMAX_QUANTITY":"10","MIN_MINMAX_QUANTITY":"10","SAFETY_LEVEL":"0","REPLENISH_TO_ORDER_FLAG":"N","UTILIZ_CD":"","CURRENCY_CD":"USD","DESCRIPTION":"","ATTRIBUTE1":" ","ATTRIBUTE2":" ","ATTRIBUTE3":" ","ATTRIBUTE4":" ","ATTRIBUTE5":" ","ATTRIBUTE6":" ","ATTRIBUTE7":" ","ATTRIBUTE8":" ","ATTRIBUTE9":" ","ATTRIBUTE10":" ","TRANSACTION_STATUS":" ","TRANS_STATUS_DESCRIPTION":" "},{"ORACLE_UNIQUE_REC_ID":"123assd4434","CUSTOMER_ID":"PMC","ORGANIZATION_CODE":"BMftrdsM","ITEM":"696738","INVENTORY_ITEM_ID":"0000000000000000000000000000546","ORGANIZATION_ID":" ","SUBINVENTORY_CODE":"000000000000000000","LOCATOR_ID":" ","ISA_MATERIAL_GROUP":" ","TAX_GROUP":" ","CATEGORY_ID":"1956","NOUN":" ","MODIFIER":" ","MANUFACTURER_ID":" ","MFG_ITEM_ID":" ","UNIT_OF_MEASURE":"BOX","ITEM_TYPE":"P","STOCK_ENABLED_FLAG":"Y","INVENTORY_ITEM_STATUS_CODE":"A","LIST_PRICE_PER_UNIT":"0","FULL_LEAD_TIME":"0","MAX_MINMAX_QUANTITY":"10","MIN_MINMAX_QUANTITY":"10","SAFETY_LEVEL":"0","REPLENISH_TO_ORDER_FLAG":"N","UTILIZ_CD":"","CURRENCY_CD":"USD","DESCRIPTION":"","ATTRIBUTE1":" ","ATTRIBUTE2":" ","ATTRIBUTE3":" ","ATTRIBUTE4":" ","ATTRIBUTE5":" ","ATTRIBUTE6":" ","ATTRIBUTE7":" ","ATTRIBUTE8":" ","ATTRIBUTE9":" ","ATTRIBUTE10":" ","TRANSACTION_STATUS":" ","TRANS_STATUS_DESCRIPTION":" "}],"Organization":"PMC Biogenix","SharedSecret":"sTc1QowIu5Iy1Qt8iilnmQ==","TimeStamp":"09/28/2018 00:19:21","RowsSent":"1"}';
l_amt integer := dbms_lob.lobmaxsize;
l_dest_offset integer := 1;
l_src_offset integer := 1;
l_csid integer := dbms_lob.default_csid;
l_ctx integer := dbms_lob.default_lang_ctx;
l_warn integer;
BEGIN
dbms_lob.createTemporary( l_blob, false );
dbms_lob.convertToBlob( l_blob,
l_clob,
l_amt,
l_dest_offset,
l_src_offset,
l_csid,
l_ctx,
l_warn );
INSERT INTO PS_ISA_INB_PAYLOAD_LOG Values(ORGANIZATIONNAME,TRANSACTION_TYPE,l_blob,SYSDATE,TRANSACTION_STATUS);
END SDIX_TICK_LOG;
Your problem lies here: DBMS_LOB.SUBSTR()
DBMS_LOB is using VARCHAR2 internally, and VARCHAR2 has limit of 2000 chars. Your blob has the size of 2829 chars, therefore it is too long to be processed by DBMS_LOB.SUBSTR() at once.
You can test this by these commands:
Take only first 2000 chars from BLOB:
select utl_raw.cast_to_varchar2(dbms_lob.substr(TRANSACTION_DATA), 2000, 1) from PS_ISA_INB_PAYLOAD_LOG;
OK.
Take 2001 chars from BLOB:
select utl_raw.cast_to_varchar2(dbms_lob.substr(TRANSACTION_DATA, 2001, 1)) from PS_ISA_INB_PAYLOAD_LOG;
Error report -
SQL Error:
ORA-06502: PL/SQL: numeric or value error: raw variable length too long
ORA-06512: at line 1
06502.00000 - "PL/SQL: numeric or value error%s"
Is that possible to select entire BLOB Field value?
Basically, no. You'll need a PL/SQL function similar to the one you've already described, except this time, it will go BLOB-to-CLOB. You can call that from SQL, if it returns a CLOB or a VARCHAR2(4000).
As a side note, I question why you're taking JSON, which is character data, and storing it as a BLOB, then wanting to get character data back. Why not just store it as a CLOB in the first place?

pl-sql clob data issue

Hi getting below error
06502. 00000 - "PL/SQL: numeric or value error%s"
*Cause: An arithmetic, numeric, string, conversion, or constraint error
occurred. For example, this error occurs if an attempt is made to
assign the value NULL to a variable declared NOT NULL, or if an
attempt is made to assign an integer larger than 99 to a variable
declared NUMBER(2).
*Action: Change the data, how it is manipulated, or how it is declared so
that values do not violate constraints.
when i run the following pl-sql code
DECLARE
type c_list is varray (6000) of varchar2(50);
name_list c_list := c_list();
counter integer :=0;
n number;
ADDHDR VARCHAR2(5000);
new_envelope clob:=NULL;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
FOR n in 1..1000 LOOP
counter := counter + 1;
name_list.extend;
name_list(counter) := 'ABCNDFHDDJJ';
dbms_output.put_line('Customer('||counter ||'):'||name_list(counter));
END LOOP;
for i in name_list.first .. name_list.last loop
ADDHDR := CONCAT(ADDHDR,'<ADDITIONAL_START>');
ADDHDR := CONCAT(ADDHDR, CONCAT('<START>', CONCAT('ADDR-KYC-ABCD-PRD-LDB-SMS-OR-START', '</START>')));
ADDHDR := CONCAT(ADDHDR, CONCAT('<ENDED>', CONCAT(name_list(i), '</ENDED>')));
ADDHDR := CONCAT(ADDHDR, '</ADDITIONAL_START>');
dbms_output.put_line('PROCESSING');
new_envelope := new_envelope || ADDHDR;
ADDHDR:=''
end loop;
dbms_output.put_line(new_envelope);
END;
/
please help me to concat string(value greater than 4000 characters) to a clob data
Thanks in advance
Problem is this line dbms_output.put_line(new_envelope);
You cannot output such large strings. I assume this is just for debugging, i.e. actually not needed.
If you really need dbms_output.put_line then do it line by line.

PL/SQL DBMS_XMLQUERY max size

My oracle version is 11g release 2
Our system is using DBMS_XMLQUERY to transform sql result into xml, but recently the data is becoming large and we get this error: ORA-06502: PL/SQL: numeric or value error
The reason seems to be DBMS_XMLQUERY cannot handle too many records, but oracle's official document doesn't show the limitation. So maybe I have done something wrong. You can reproduce the problem in the following steps:
step1:
create table XMLDATA ( data_id int primary key, data_str
VARCHAR2(100) );
step2:
INSERT INTO XMLDATA values(1, 'test0123456789');
INSERT INTO XMLDATA values(2, 'test0123456789');
INSERT INTO XMLDATA values(3, 'test0123456789');
....
INSERT INTO XMLDATA values(500, 'test0123456789');
step3:
CREATE OR REPLACE
function test(total in int) return clob is
i int;
vn_ctx DBMS_XMLQUERY.ctxHandle;
BEGIN
vn_ctx := DBMS_XMLQUERY.NEWCONTEXT('select data_id, data_str from XMLDATA where rownum <= ' || total);
DBMS_XMLQuery.propagateOriginalException(vn_ctx,true);
DBMS_XMLQUERY.useNullAttributeIndicator(vn_ctx,true);
DBMS_XMLQUERY.SETROWTAG(vn_ctx, 'ITEM');
DBMS_XMLQUERY.SETROWSETTAG(vn_ctx, 'PODATA');
return DBMS_XMLQUERY.GETXML(vn_ctx);
END;
step4:
execute function test with a number greater than 400. Then you'll get 'ORA-06502: PL/SQL: numeric or value error'
thanks in advance
EDIT
Really sorry... I got the old code, someone adds a log statement without noticing me. The log statement can only accept a maximum of 32767 characters in one line, so the error is raised. The above function is executed by a debug tool, which gives the same error, so it's the tool's problem, not oracle.
Thanks for your answering and sorry for my naive mistakes...
I get no errors if the variable to hold the return value is big enough.
declare
rv1 clob;
rv2 varchar2(32000);
begin
rv1 := test(400); -- No error
rv2 := test(200); -- No error - returned XML is < 32000 in length.
rv2 := test(400); -- ORA-06502: PL/SQL: numeric or value error'
end;

Not able to pass CLOB in Oracle function

I'm trying to pass CLOB as input parameter in oracle function. The function is created successfully, but when I try to pass a lengthy string, it gives
ora-01704 string literal too long
error.
Below is my function:
CREATE OR REPLACE FUNCTION mySchema.TESTFUNCTION(myData IN CLOB)
RETURN INT
AS
BEGIN
DBMS_OUTPUT.PUT_LINE(myData);
RETURN 1;
END;
When I try to call this function by passing lengthy string more than 5000 characters, it gives the error.
Can anybody help please
yes, I pass as a string only. Eg: select TESTFUNCTION('more than 5000 chars') from dual;
No, it cannot be done like that. That error is the expected one, simply because SQL(Oracle versions prior to 12c) cannot handle character literals that are more than 4000 bytes in length.
If you need to test your function use PL/SQL, where character literal can be up to 32767 characters(single byte character set) in length:
Here is our function:
Note: Starting from Oracle 10g R2 dbms_output.put_line() line limit is 32767 bytes, in versions prior to 10g R2 the line limit is 255 bytes.
create or replace function f1(
p_clob in clob
) return number is
begin
dbms_output.put_line(p_clob);
return 1;
end;
Here is our anonymous PL/SQL block to test that function:
clear screen;
set serveroutput on;
declare
l_var clob;
l_res number;
begin
l_var := 'aaaaaaaaaaaaaaaaaa.. more than 5000 characters';
l_res := f1(l_var);
end;
Result:
anonymous block completed
aaaaaaaaaaaaaaaaaa.. more than 5000 characters

Resources