Home > Blockchain >  Concatenated field conversion error when executing a view in Oracle
Concatenated field conversion error when executing a view in Oracle

Time:12-16

I have a view (DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC) to be able to visualize the transactions in Oracle. This view makes use of those already existing in the system: v$sql, V$SQLSTATS, v$sqlarea and gv$process.

And the structure and type of columns was as follows:

enter image description here

I have a procedure that attempts to use such a view, format the output to a single HTML string under certain conditions, and send it via email. Here is a simple summary of that procedure:

DECLARE
    V_BODY_TEXT CLOB;
BEGIN
    select utl_i18n.unescape_reference(xmlagg(xmlelement(e,'
        <tr>
            <td>' || ltrim(rtrim(TO_CLOB(SID))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_ID))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(USERNAME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(ONAME))) || '</th> 
            <td>' || ltrim(rtrim(TO_CLOB(MACHINE))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(WAIT_CLASS))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(EVENT))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(MODULE))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(LOGON_TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(START_TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(TIME))) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_TEXT))) || '</th>
        </tr>
    ','').extract('//text()')).getclobval()) x
    INTO V_BODY_TEXT
    FROM DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC WHERE "TIME" > 300;
               
END;

The error presented by the execution of the above code is because the concatenated result only admits 4000 characters and it doesn't matter if I try to cast (TO_CLOB) field by field or the entire concatenated string, I still get the same error every time. result size is exceeded:

enter image description here

About the above code, the use of the TO_CLOB function, is my last attempt to try to solve the problem.

Said error does not allow any "substring" or "len" type action to be applied to it either.

I've also tried creating a table with all the fields of type CLOB, then inserting the result of the view, and using the above procedure now with the table, but I keep getting the same error every time the generated html code exceeds 4000 characters.

Therefore, I go to this community to see what other options they give me to get out of the problem.

CodePudding user response:

The xmlelement function only accepts up to 4000 characters if the initialization parameter MAX_STRING_SIZE = STANDARD, and 32767 characters if MAX_STRING_SIZE = EXTENDED, so there's no point in converting to CLOB that early in your process. See here.

Also, the utl_i18n.unescape_reference function only accepts VARCHAR2 input, not CLOB. See here. This is the most likely place your query is failing.

Try this, working exclusively with VARCHAR2, doing explicit conversions from NUMBER and DATE types, and saving the aggregation into the largest string to the very end:

DECLARE
    V_BODY_TEXT CLOB;
BEGIN
    select xmlagg(utl_i18n.unescape_reference(xmlelement(e,'
        <tr>
            <td>' || TO_CHAR(SID) || '</th>  
            <td>' || ltrim(rtrim(SQL_ID)) || '</th>  
            <td>' || ltrim(rtrim(USERNAME)) || '</th>  
            <td>' || ltrim(rtrim(ONAME)) || '</th> 
            <td>' || ltrim(rtrim(MACHINE)) || '</th>  
            <td>' || ltrim(rtrim(WAIT_CLASS)) || '</th>  
            <td>' || ltrim(rtrim(EVENT)) || '</th>  
            <td>' || ltrim(rtrim(MODULE)) || '</th>  
            <td>' || TO_CHAR(LOGON_TIME,'DD-MON-YYYY') || '</th>  
            <td>' || TO_CHAR(START_TIME,'DD-MON-YYYY') || '</th>  
            <td>' || TO_CHAR(TIME) || '</th>  
            <td>' || ltrim(rtrim(TO_CLOB(SQL_TEXT))) || '</th>
        </tr>
    ',''))) x
    INTO V_BODY_TEXT
    FROM DB_ADMIN.VW_DBA_MONITOR_CURRENTLYEXEC WHERE "TIME" > 300;
           
END;

CodePudding user response:

XMLType methods are deprecated since Oracle 11gr2, use modern (though, it's hard to tell about XML) SQL functions to access XML data without additional serialization/deserialization issues:

  • XMLQUERY for extraction.
  • XMLCAST for deserialization. It does decoding of HTML/XML stuff like &amp; etc to their text values.

Below is an example of three characters padded with zeroes up to 5000 bytes (so resulting in too large value for varchar2)

with t(col) as (
  select
    xmlelement(e,
      to_clob(rpad('<>&', 4000, '0'))
      || to_clob(rpad('0', 1000, '0'))
    )
  from dual
)
, deser as (
  select
    xmlcast(xmlquery(
      '//text()'
      passing col
      returning content
    ) as clob) as res
  from t
)
select
  length(res),
  trim(trailing '0' from res) as res
from deser
LENGTH(RES) RES
5000 <>&

fiddle

  • Related