oracle-databaseutf-8character-encodingutl-file

Special Character not repeated not twice in Oracle


I have a column Value Méroné in my Oracle DB. We are writing it to a csv file using utl_file package.Since this value has a special character we have used convert function to change the character coding to remove the junk character while writing. So the convert function goes like this- convert(REC.DT25, 'WE8DEC'). But the problem now is that the value is coming as only Méron and the last character is missing. I have tried everything from changing it to different character encoding, but still no luck. Could you please help? The code is as follows CREATE OR REPLACE PROCEDURE SAMPLE_MERONE AS

CREATE OR REPLACE PROCEDURE SAMPLE_MERONE AS 

CURSOR C1 IS select * from gsal_mosaic_prf_output where CS46SIGFORMALNAME 
LIKE 'Lt. Jowens Méroné' AND ID_NUMBER='8-13678728';

MERONE_FILE UTL_FILE.FILE_TYPE;
V_MERONE_FILE VARCHAR2(300);

BEGIN
V_MERONE_FILE := 'MREONE_FILE.csv';
MERONE_FILE := UTL_FILE.FOPEN ( 'GSAL_PRF',V_MERONE_FILE,'w',32767) ;
IF UTL_FILE.IS_OPEN(MERONE_FILE) THEN
FOR REC IN C1
LOOP
UTL_FILE.PUT_LINE(MERONE_FILE,'"'||REC.ID_NUMBER||'","'||
REC.GROUP_ID||'","'||convert(REC.CS46LASTNAME,'WE8ISO8859P1', 
'UTF8')||'","'||
convert(REC.CS46SIGFORMALNAME,'WE8ISO8859P1', 
'UTF8')||'"',TRUE);
END LOOP;
UTL_FILE.FCLOSE ( MERONE_FILE ) ;
END IF;
END SAMPLE_MERONE;

Solution

  • Running the following script on a 12.2 AL32UTF8 database reproduces the issue.

    declare
    
       cursor c1 is
          select lastname
                ,convert(lastname, 'WE8ISO8859P1','UTF8') convertedname
                ,dump(convert(lastname, 'WE8ISO8859P1','UTF8')) dumpconvertedname
            from (select 'Lt. Jowens Méroné' as lastname
                    from dual);
    
       merone_file   utl_file.file_type;
       v_merone_file varchar2(300);
    
    begin
       merone_file := utl_file.fopen('NGM1_PAD_IN', 'test.csv', 'w', 32767);
       if utl_file.is_open(merone_file)
       then
          for rec in c1
          loop
             dbms_output.put_line(rec.lastname ||' - ' ||rec.convertedname);     
             dbms_output.put_line(rec.dumpconvertedname); 
             utl_file.put_line(merone_file
                              ,rec.lastname || '","' ||
                               rec.convertedname || '"'
                              ,true);
          end loop;
          utl_file.fclose(merone_file);
       end if;
    end;
    /
    

    Screen output:

    Lt. Jowens Méroné - Lt. Jowens Méron

    Typ=1 Len=17: 76,116,46,32,74,111,119,101,110,115,32,77,233,114,111,110,233

    File contents:

    Lt. Jowens Méroné","Lt. Jowens Méron"

    The conversion changes 195 169 into character 233. You can see it as the last character in the converted string. But somehow does not make it's way into the file.

    Exploring the file with a hex editor confirms this.

    As a workaround you can assemble all your data into a CLOB and write it as follows. This seems to convert your data correctly.

    declare
    
       l_clob   clob;
       l_string varchar2(32767);
    
       cursor c1 is
          select lastname
            from (select 'Lt. Jowens Méroné' as lastname
                    from dual);
    
    begin
    
       dbms_lob.createtemporary(lob_loc => l_clob, cache => true, dur => dbms_lob.call);
       dbms_lob.open(lob_loc => l_clob, open_mode => dbms_lob.lob_readwrite);
    
       for rec in c1
       loop
          l_string := rec.lastname || '","' || rec.lastname || '"' || chr(13) || chr(10);
          dbms_lob.writeappend(lob_loc => l_clob, amount => length(l_string), buffer => l_string);
    
       end loop;
    
       dbms_xslprocessor.clob2file(flocation => 'NGM1_PAD_IN'
                                  ,fname     => 'test2.csv'
                                  ,cl        => l_clob
                                  ,csid      => nls_charset_id('WE8ISO8859P1'));
    
    end;
    /