Returning clob to varchar from a stored procedure

February 20, 2004 Jesse -- Thanks for the question regarding "Returning clob to varchar from a stored procedure", version Oracle8.0.5/Sun OS
You Asked
Hi Tom,
The issue is to return the text details stored in a table as 
clob(after
loaded into the table from a text file). Is there a limitation 
like
4000 for the size of an OUT parameter to passed into a stored 
procedure?

I have created the following stored procedure 
create or replace procedure test_proc(myid number, mydoc out 
varchar2) is
    c_lob        clob;
    myclob_text    varchar2(4000);
    len        number:=0;
    amount        number:=100;
    offset        number;
begin

    select theclob
    into c_lob
    from demo
    where id=myid;
    
    len := dbms_lob.getlength(c_lob);
    offset := 1;
    while (len > 0) loop
        myclob_text := dbms_lob.substr (c_lob, amount, offset);  
          
--        dbms_lob.read(c_lob, amt2, offset, myclob_text);
--        dbms_output.put_line (myclob_text);
        len := len - amount;
        offset := offset + amount;
        mydoc := mydoc || myclob_text;
    end loop;
end;
/

Testing using:
SQL> variable txt varchar2(4000);
SQL> exec test_proc(1, :txt);
Error: ORA-06502 PL/SQL: numeric or value error

Text in id 1 is loaded from a file size of 16K.
If I passed in the id=2 which contains 2 lines of text, it is 
OK.

If I would like to call this stored procedure using thin 
client JDBC calls, will it works for big clob? 

What is the solution if I were to return the clob->varchar2 from 

a stored procedure? 

Thank you in advance

Regards,
Hwee

and we said...
There is a 32k LIMIT on the size of an OUT parameter (or IN 
parameter or in fact all PLSQL variables).  The reason you are 
getting

SQL> variable txt varchar2(4000);
SQL> exec test_proc(1, :txt);
Error: ORA-06502 PL/SQL: numeric or value error


is due to the fact that you are trying to stuff 16k of data into 
4000 bytes of allocated space.  SQLPlus will not let you define 
a variable of greater them 4000 bytes (but you can in other 
languages).

Below shows that a plsql routine can in fact return 16k of data:


[email protected]> create table t ( x int, y clob );

Table created.

[email protected]> 
[email protected]> declare
  2          tmp     long;
  3          c       clob;
  4  begin
  5          tmp := rpad( '*', 16384, '*' );
  6          insert into t values ( 1, empty_clob() ) 
                      returning y into c;
  7          dbms_lob.writeappend( c, length(tmp), tmp );
  8  
  9          tmp := rpad( '*', 2048, '*' );
 10          insert into t values ( 2, empty_clob() ) 
                      returning y into c;
 11          dbms_lob.writeappend( c, length(tmp), tmp );
 12  end;
 13  /

PL/SQL procedure successfully completed.

[email protected]> select x, dbms_lob.getlength(y) from t
  2  /

         X DBMS_LOB.GETLENGTH(Y)
---------- ---------------------
         1                 16384
         2                  2048

[email protected]> create or replace procedure test_proc( 
myid number, mydoc OUT varchar2 )
  2  as
  3          l_clob  clob;
  4  begin
  5          select y into l_clob
  6            from T
  7           where x = myid;
  8  
  9          mydoc := dbms_lob.substr( l_clob, 32765, 1 );
 10  end;
 11  /

Procedure created.

[email protected]> declare
  2          test_bind_variable long;
  3  begin
  4          test_proc( 1, test_bind_variable );
  5          dbms_output.put_line( 'returned length is ' || 
length(test_bind_variable) );
  6  end;
  7  /
returned length is 16384

PL/SQL procedure successfully completed.

[email protected]>


In Java, using the 8.1.5 thin driver, I coded the following:

import java.io.*;
import java.sql.*;
import java.util.*;

class test
{

public static void main(String args[])
{
    Statement statement = null;

    try
    {
    DriverManager.registerDriver
        (new oracle.jdbc.driver.OracleDriver());

    Connection connection =
      DriverManager.getConnection
        ("jdbc:oracle:thin:@aria-dev:1521:ora8idev",
         "scott", "tiger");

    DatabaseMetaData conMD = connection.getMetaData();
    System.out.println("JDBC Driver Name        :\t" +
    conMD.getDriverName());
    System.out.println("JDBC Driver Version     :\t" +
    conMD.getDriverVersion());
    System.out.println("Database Product Name   :\t" +
    conMD.getDatabaseProductName());
    System.out.println("Database Product Version:\t" +
    conMD.getDatabaseProductVersion());
    System.out.println("Max Statements          :\t" +
    conMD.getMaxStatements());
    System.out.println();

    connection.setAutoCommit(false);

    statement = connection.createStatement();

    CallableStatement cstmt = connection.prepareCall(
        "begin test_proc( 1, ? ); end;" );

    cstmt.registerOutParameter( 1, java.sql.Types.CHAR );
    System.out.println( "prepared & registered" );
    cstmt.executeUpdate();

    String newVal = cstmt.getString( 1 );
    System.out.println
       ( newVal.length() + " bytes retrieved..." );

    }
    catch( Exception e )
    {
        e.printStackTrace();
    }

}

}

and it returns:


$ java test
JDBC Driver Name        :       Oracle JDBC driver
JDBC Driver Version     :       8.1.5.0.0
Database Product Name   :       Oracle
Database Product Version:       Oracle8i Enterprise Edition 
Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production
Max Statements          :       0

prepared & registered
16384 bytes retrieved...


So, you should be able to use this method to retrieve UPTO 32k 
of text.  Beyond that you would have to use streams on the clobs.
Review & Followup

Rating: 5
Is there a 4k limit when returning a portion of a clob in a function?  August 28, 2003
Reviewer:  Anthony  from ny

Tom, 
 I am trying to create a function to return a portion of a clob. The size is 
greater than 4k but less than 10k.
I'm having some trouble understanding what's going on here:

create table t( a int, b date, c clob );

insert into t values( 1, sysdate, rpad('*',400,'*') );
commit;

create or replace function get_clob( p_ptr clob )
return varchar2
is
begin 
    return dbms_lob.substr( p_ptr, dbms_lob.getlength(p_ptr), 1 );
end;
/

  /* test it out */
SQL> col text form a50
SQL> select a,b,get_clob(c) text from t;
         A B         TEXT
---------- --------- --------------------------------------------------
         1 28-AUG-03 **************************************************
                     **************************************************
                     **************************************************
                     **************************************************
                     ...

so far so good. The return val is less than or equal to the SQL limit of 4k.


/* putting in a bigger clob */
declare
 l_ptr clob;
begin
    insert into t values( 2, sysdate, empty_clob() ) returning c into l_ptr;
    dbms_lob.write( l_ptr, 32767, 1, rpad( '*',32767,'*' ) );
    commit;
end;
/

SQL> select dbms_lob.getlength(c) from t;

DBMS_LOB.GETLENGTH(C)
---------------------
                 4000
                32767

/* the following error is expected */
SQL> select a,b,get_clob(c) from t where a=2;
ERROR:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "SCOTT.GET_CLOB", line 5


/* but, this doesn't work.... */
SQL> declare
         x varchar2(32767);
     begin
         select get_clob( c ) into x from t where a=2;
         dbms_output.put_line(length(x));
     end;
  /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character string buffer too small
ORA-06512: at "SCOTT.GET_CLOB", line 5
ORA-06512: at line 4


/* ...while this does */
SQL> declare
        x varchar2(32767);
        y clob;
     begin 
        select c into y from t where a=2;
        x := get_clob( y );
        dbms_output.put_line( x );
     end;
32767

PL/SQL procedure successfully completed.

Why does the last anonymous block succeed?
Is this first block doing it in SQL (even though it's in a pl/sql block), 
therefore restricted to 4k as well?

 Thanks in advance,
  -Ant  

Followup:
sql is limited to 4000 bytes unless you just return the CLOB/BLOB itself.

plsql is limited to 32k unless you return the clob/blob itself 


Rating: 4
excellent  February 20, 2004
Reviewer:  vj  from in

Hi,

The below is the version of oracle we are using

Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
PL/SQL Release 9.2.0.1.0 - Production
CORE 9.2.0.1.0 Production
TNS for 32-bit Windows: Version 9.2.0.1.0 - Production
NLSRTL Version 9.2.0.1.0 - Production

We have an SP that return (out param )the CLOB datatype to the calling 
program.The calling program is an JSP and we use oracle thin driver. My size of 
CLOB is around 32KB and sometimes little more than 32KB. If we send below 30kb 
it is working, but if it is more than 30 KB it is not
working. Any other alternate as we built the programs around the same logic.

Rgds
 

Followup:
you'd really have to provide a teeny tiny code snippet for you can use clobs of 
unlimited size in java/jdbc (well, upto the current 4gig limit in 9i).  You 
would interface to them as "streams" -- perhaps you are using "strings"?

small
concise
yet complete

is the best test case.  it won't need a jsp to reproduce your issue -- a tiny 
"main" with a tiny bit of code. 



February 20, 2004 Ramasubbu -- Thanks for the question regarding "Cuncurrent execution of procedures", version Oracle8i Enterprise Edition Release 8.1.6.3.0 - Production

你可能感兴趣的:(procedure)