Skip to Main Content

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Tyler.

Asked: May 19, 2021 - 2:23 pm UTC

Last updated: June 01, 2021 - 1:43 am UTC

Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production

Viewed 10K+ times! This question is

You Asked

Hey guys, first off thanks a ton for all the support you provide, it's top notch and much appreciated :)

Have a situation where some columns got prematurely converted to CLOB from LONG via
alter table <table_name> modify <column_name> CLOB;

And they need to get converted back (for a short time) to LONGs. Some of the CLOBS exceed 32k in length but not many and I was wondering what the best method would be to get the column definition back to LONG. Hoping there's some magic I'm not familiar with but assuming this data type has been deprecated for so long I'm fearful there is not.

Thanks a bunch!

drop table READY_FIRE_AIM ;
create table READY_FIRE_AIM (col1 number, LONG_COLUMN clob);

declare
    l_large_value_1   clob    :=  rpad ('1',32750, '2');
    l_large_value_2   clob    :=  rpad ('2',32750, '2');
begin
    insert into READY_FIRE_AIM values (1, l_large_value_1 );
    insert into READY_FIRE_AIM values (2, l_large_value_1 || l_large_value_2 );
    commit;
end;
/

select col1, dbms_lob.getlength(long_column) from READY_FIRE_AIM;


and Chris said...

Restore the table from backup.

You... do have a backup you can restore from, right?

If this isn't an option for whatever reason, I think you may be out of luck for the strings > 32k. You can copy the data from CLOB -> LONG for values shorter than this, but the longer ones will hit ORA-22835: Buffer too small for CLOB to CHAR or BLOB to RAW conversion. (The limit is 4,000 if you've not enabled extended data types)

I don't know of another way around this.

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

A solution (if desperate :P )

Tyler, May 28, 2021 - 5:49 pm UTC

Thanks Chris,

Yes a backup existed, however the system was released before the issue was spotted (this is the point I got brought in) so that wasn't a viable option unfortunately.

In the end put together some java (compiled in the database) to accomplish this which I'll post in case anyone ever comes across this and has the same issue. Java isn't my wheelhouse so please don't poke too much fun at this :)

Cheers,

drop table Clob_to_Long_Test  purge;

create table Clob_to_Long_Test (col1 number, clob_column clob, long_column long, log_date date);
declare 
  l_biggie_1  varchar2(32767) :=  rpad('a', 32766, 'b');
  l_biggie_2  varchar2(32767) :=  rpad('1', 32766, '2');
  l_clob      clob            :=  l_biggie_1 || l_biggie_2;
begin 
  insert into Clob_to_Long_Test values (1, l_clob, null, null);
  commit;
end;
/

create or replace and compile java source named "ClobConverter" 
as

import java.lang.*;
import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.driver.*;
import org.apache.*;
import java.reader.*;
import java.io.*;

public class ClobConverter
{
  public static void UpdateClob (int in_column_id) throws SQLException
  {
  
    Connection con = null;
    OracleDriver ora = new OracleDriver(); 
    con = ora.defaultConnection(); 

    Clob myClob = null;
    String sql1 = "select clob_column, dbms_lob.getlength(clob_column) as the_length from Clob_to_Long_Test where COL1 = ?";
    int theclobsize=-1;
    
    PreparedStatement pstmt = con.prepareStatement(sql1);
    pstmt.setInt(1, in_column_id);
    ResultSet rs = pstmt.executeQuery();
    if (rs.next()) 
    {
        myClob = rs.getClob("clob_column");    
        theclobsize = rs.getInt("the_length");
    }
    pstmt.close();
    
    final StringBuilder builder = new StringBuilder(theclobsize);
    final BufferedReader reader = new BufferedReader(myClob.getCharacterStream());

    try 
    {
        for (String line = null; (line = reader.readLine()) != null; ) 
        {
            builder.append(line);
        }
    } 
    catch (IOException e) 
    {
        e.printStackTrace();
    }
  
    String sql2 = "update Clob_to_Long_Test  set long_column = ? , log_date= sysdate where COL1 = ?";
    try
    {
      PreparedStatement pstmt2 = con.prepareStatement(sql2);
      pstmt2.setString(1, builder.toString());
      pstmt2.setInt(2, in_column_id);
      pstmt2.executeUpdate();
      pstmt2.close();
    }
    catch (SQLException e)
    {
      System.err.println(e.getMessage());
    }
  }   
}
/


create or replace procedure p_call_ClobConverter (p_column_vlaue in number)
as 
language java name 'ClobConverter.UpdateClob(int)'; 
/

exec p_call_ClobConverter(1);

select *
from Clob_to_Long_Test;


Connor McDonald
June 01, 2021 - 1:43 am UTC

Great work. I was unaware Java in the db would be able to do that.

Thanks for posting this.

More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library