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
Related
I have a procedure
create or replace PROCEDURE PROC_PROJPREL_TEMPL_SERV_MAT(
P_TABELA IN VARCHAR2,
P_COLUNAS IN VARCHAR2,
P_DADOS IN CLOB,
O_CODIGO OUT NUMBER,
O_MENSAGEM OUT VARCHAR2
) IS
BEGIN
o_codigo := 0;
o_mensagem := '';
-- no implementation coded yet
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20101, 'erro ao executar procedure ');
END PROC_PROJPREL_TEMPL_SERV_MAT;
And I need to execute this in SQL Developer.
I tried using anonymous block
declare
i_tabela varchar2(30);
i_colunas varchar2(4000);
i_dados clob;
o_codigo number;
o_mensagem varchar2(4000);
begin
i_tabela := 'table_name'; -- max 30 characters
i_colunas := 'columns_names'; -- less 4000 characters
i_dados := '45000 characters';
proc_projprel_templ_serv_mat(i_tabela, i_colunas, i_dados, o_codigo, o_mensagem);
end;
But it returns an error "string literal too long"
and I tried using "call" command too.
call proc_projprel_templ_serv_mat('table_name', 'columns_names', &DATAS);
But it returns an error ORA-00972 identifier is too long, Cause: An identifier with more than 30 characters was specified, Action: Specify at most 30 characters.
Somebody can help me?
The maximum length of a string literal in PL/SQL is 32,767 characters. As the error "string literal too long" is saying, you're blowing out this limit here:
i_dados := '45000 characters';
You have to break up that string into sections up to 32,767 characters long and concatenate them together, e.g.:
i_dados := 'first 32767 characters' ||
'remaining 12233 characters';
Trying to get the size of a defined variable in Oracle. I may need to use a number when declaring the size of a varchar2 but would rather not have to keep track of an extra variable or number.
example pseudo code:
declare
myvar varchar(42) := 'a';
begin
/* I know the length is length(myvar) = 1. */
/* but how do I get 42? */
/* What is the max defined size of this variable */
declared_size_of(myvar);
end
The reason I need this is to lpad the length of the string to the declared size so it doesn't generate an exception.
As #Justin said in his comments, you don't have to explicitly blank pad the string if you use CHAR data type. Oracle would blank-pad the value to it's maximum size.
From documentation,
If the data type of the receiver is CHAR, PL/SQL blank-pads the value
to the maximum size. Information about trailing blanks in the original
value is lost.
For example,
SQL> SET serveroutput ON
SQL> DECLARE
2 myvar CHAR(42);
3 BEGIN
4 myvar:='a';
5 dbms_output.put_line(LENGTH(myvar));
6 END;
7 /
42
PL/SQL procedure successfully completed.
SQL>
Brute Force technique using exception handling which is probably very inefficient:
DECLARE
myvar varchar2(42) := 'a'; /* using varchar */
v_size number := null;
x varchar(4000) := '';
v_length number := 0;
BEGIN
begin
v_length := length(myvar);
x := myvar;
FOR i in v_length..8001 LOOP
myvar := myvar || ' '; /* add one space at a time until it causes an exception */
End Loop;
EXCEPTION
-- WHEN NO_DATA_FOUND THEN
WHEN OTHERS THEN
v_length := length(myvar);
end;
dbms_output.put_line('Declared size is varchar('||v_length
||') and length(myvar) is '||length(trim(myvar)));
END;
To fetch the max. of a column input, you simply could do:
SELECT MAX(LENGTH(Column))
FROM TableA;
I have This Oracle 12c Procedure
CREATE OR REPLACE PROCEDURE LOGINCHECK(SQLQRY IN CLOB)
AS
C INTEGER;
N INTEGER;
RC SYS_REFCURSOR;
stmt clob:= To_Clob('begin ' || sqlqry || '; end;');
BEGIN
C := SYS.DBMS_SQL.OPEN_CURSOR;
SYS.DBMS_SQL.PARSE(C,stmt ,DBMS_SQL.native);
N := SYS.DBMS_SQL.EXECUTE(C);
SYS.DBMS_SQL.GET_NEXT_RESULT(C,RC);
SYS.DBMS_SQL.RETURN_RESULT(RC);
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
when OTHERS then
RAISE;
END LOGINCHECK;
I Call This Procedure in Anonymous Block Like This (Download XML Data from here: Link)
declare stmt clob := 'INWARDPKG.MACHINEINWARD_VALIDATING(XMLDOC => XMLTYPE.CREATEXML(paste xml from link))'; --The parameter value is a xml you can download it from above link
begin
LOGINCHECK(SQLQRY => STMT);
end;
But I am getting Error PLS-00172: string literal too long.
If i reduce xml size to 40-50 elements like remove some elements. this works fine.
In your first line declare stmt clob := 'INWARDPKG.MACHINEINWARD_VALIDATING... you are defining your CLOB. Since you are using a string literal to define your CLOB, you are facing the limits of string literals (see Oracle 12c Documenation).
To solve your problem you have to build your CLOB step by step, using the DBMS_LOB package and appending strings not longer than 4000 bytes until your CLOB is complete.
The basic idea:
DECLARE
C CLOB := TO_CLOB('First 4000 bytes');
V VARCHAR2(4000);
BEGIN
V := 'Next 4000 bytes';
DBMS_LOB.WRITEAPPEND(C, LENGTH(V), V);
-- more WRITEAPPEND calls until C is complete
DBMS_OUTPUT.PUT_LINE('CLOB-Length: ' || DBMS_LOB.GETLENGTH(C));
END;
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.
I'm trying to compose a function to obtain MD5 hashes from bits I've gathered here and there. I want to obtain the lower-case hexadecimal representation of the hash. I have this so far:
CREATE OR REPLACE FUNCTION MD5 (
CADENA IN VARCHAR2
) RETURN DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM
AS
BEGIN
RETURN LOWER(
RAWTOHEX(
UTL_RAW.CAST_TO_RAW(
DBMS_OBFUSCATION_TOOLKIT.MD5(INPUT_STRING => CADENA)
)
)
);
END;
I'm not sure about the return type of the function. DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM looks like the appropriate choice and as far as I can tell it works as expected but the package definition for dbms_obfuscation_toolkit as displayed by SQL Developer shows this:
SUBTYPE varchar2_checksum IS VARCHAR2(16);
The output has 32 characters so I must be doing something wrong. My questions:
What's the correct type for the RETURN statement?
Am I doing unnecessary conversions to calculate the hash?
Here you go:
create or replace function getMD5(
in_string in varchar2)
return varchar2
as
cln_md5raw raw(2000);
out_raw raw(16);
begin
cln_md5raw := utl_raw.cast_to_raw(in_string);
dbms_obfuscation_toolkit.md5(input=>cln_md5raw,checksum=>out_raw);
-- return hex version (32 length)
return rawtohex(out_raw);
end;
The 32 length is because it is a hex representation of the raw(16) value. Or, modify above to output the raw version and store the raw in a RAW column (less space used, but you'll be doing future rawtohex and hextoraw conversions, believe me).
Cheers
It's a peculiarity of Oracle PL/SQL that stored procedure parameters and function return types cannot be limited. That is, we cannot have a procedure with a signature like this:
SQL> create or replace procedure my_proc (p1 in varchar2(30))
2 is
3 begin
4 null;
5 end;
6 /
Warning: Procedure created with compilation errors.
SQL> show error
Errors for PROCEDURE MY_PROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
1/34 PLS-00103: Encountered the symbol "(" when expecting one of the
following:
:= . ) , # % default character
The symbol ":=" was substituted for "(" to continue.
SQL> create or replace procedure my_proc (p1 in varchar2)
2 is
3 begin
4 null;
5 end;
6 /
Procedure created.
SQL>
Sure we can define the procedure's parameter using a SUBTYPE but Oracle will ignore it. Same goes for function return types...
SQL> create or replace package my_subtypes as
2 subtype ltd_string is varchar2(30);
3 end;
4 /
Package created.
SQL> create or replace function my_func return my_subtypes.ltd_string
2 is
3 begin
4 return lpad('a', 4000, 'a');
5 end;
6 /
Function created.
SQL> select length(my_func) from dual
2 /
LENGTH(MY_FUNC)
---------------
4000
SQL>
The only way of limiting parameters and return types is to declare variables using subtypes within the stored procedure. Use the variables within the package, and assign them to the OUT paramters (or RETURN the variable for functions).
Which is a long-winded way of saying, you can use DBMS_OBFUSCATION_TOOLKIT.VARCHAR2_CHECKSUM in your code confident that it won't prevent your function returning 32 characters.
However, it will confuse developers who will lookup the SUBTYPE declaration. In the worst case these people will use the subtype to declare their own working variables with the following tragic result:
SQL> declare
2 v my_subtypes.ltd_string;
3 begin
4 v := my_func;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at line 4
SQL>
So, it is better not to use an inappropriate subtype. Instead declare your own.