Skip to Main Content

Database Software

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

XQuery Update Facility : replacing value of multiple nodes gives ORA-01427

odie_63Mar 3 2012 — edited Mar 13 2012
I'm experimenting with XQUF on 11.2.0.3 and found the following issue with Object-Relational storage (and binary XML too) :

Test case :
set echo on
set long 10000
select * from v$version;

begin
 dbms_xmlschema.deleteSchema('workbook.xsd', dbms_xmlschema.DELETE_CASCADE);
end;
/

begin
 dbms_xmlschema.registerSchema(
   schemaURL => 'workbook.xsd'
 , schemaDoc => '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb">
  <xs:complexType name="worksheetType" xdb:SQLType="T_WORKSHEET">
    <xs:attribute name="sheetName" type="xs:string"/>
    <xs:attribute name="sheetId" type="xs:integer"/>
  </xs:complexType>
  <xs:complexType name="workbookType" xdb:SQLType="T_WORKBOOK" xdb:maintainDOM="false">
    <xs:sequence>
      <xs:element name="worksheet" type="worksheetType" minOccurs="1" maxOccurs="unbounded" xdb:SQLCollType="T_WORKSHEET_COLL"/>
    </xs:sequence>
  </xs:complexType>
  <xs:element name="workbook" type="workbookType" xdb:defaultTable="WORKBOOK_XML"/>
</xs:schema>'
 , local => true
 , genTypes => true
 , genTables => true
 , enableHierarchy => dbms_xmlschema.ENABLE_HIERARCHY_NONE
 );
end;
/

begin
 dbms_xmlstorage_manage.renameCollectionTable(
   tab_name => 'WORKBOOK_XML'
 , xpath => '"XMLDATA"."worksheet"'
 , collection_table_name => 'WORKSHEET_XML'
 );
end;
/

insert into workbook_xml values(
 xmltype('<workbook>
 <worksheet sheetName="Sheet1" sheetId="1"/>
 <worksheet sheetName="Sheet2" sheetId="2"/>
 <worksheet sheetName="Sheet3" sheetId="3"/>
</workbook>')
);

commit;

col sheetName format a30
col sheetId format 99

select x.* 
from workbook_xml t
   , xmltable( '/workbook/worksheet' passing t.object_value
               columns sheetName varchar2(4000) path '@sheetName'
                     , sheetId   number         path '@sheetId' ) x
;

update workbook_xml t
set t.object_value = xmlquery(
'copy $d := . 
 modify ( 
  for $i in $d/workbook/worksheet
  return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName)
 ) 
return $d'
passing t.object_value
returning content
);

select xmlquery(
'copy $d := . 
 modify ( 
  for $i in $d/workbook/worksheet
  return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName) 
 ) 
return $d'
 passing t.object_value
 returning content
) as modified_doc
from workbook_xml t
;

select /*+ no_xml_query_rewrite */ xmlquery(
'copy $d := . 
 modify ( 
  for $i in $d/workbook/worksheet
  return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName) 
 ) 
return $d'
 passing t.object_value
 returning content
) as modified_doc
from workbook_xml t
;
Output :
SQL> @xquftest.sql
SQL> set echo on
SQL> set long 10000
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production
PL/SQL Release 11.2.0.3.0 - Production
CORE    11.2.0.3.0      Production
TNS for 32-bit Windows: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production

5 rows selected.

SQL>
SQL> begin
  2   dbms_xmlschema.deleteSchema('workbook.xsd', dbms_xmlschema.DELETE_CASCADE);
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL>
SQL> begin
  2   dbms_xmlschema.registerSchema(
  3     schemaURL => 'workbook.xsd'
  4   , schemaDoc => '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xdb="http://xmlns.oracle.com/xdb">
  5    <xs:complexType name="worksheetType" xdb:SQLType="T_WORKSHEET">
  6      <xs:attribute name="sheetName" type="xs:string"/>
  7      <xs:attribute name="sheetId" type="xs:integer"/>
  8    </xs:complexType>
  9    <xs:complexType name="workbookType" xdb:SQLType="T_WORKBOOK" xdb:maintainDOM="false">
 10      <xs:sequence>
 11        <xs:element name="worksheet" type="worksheetType" minOccurs="1" maxOccurs="unbounded" xdb:SQLCollType="T_WORKSHEET_CO
LL"/>
 12      </xs:sequence>
 13    </xs:complexType>
 14    <xs:element name="workbook" type="workbookType" xdb:defaultTable="WORKBOOK_XML"/>
 15  </xs:schema>'
 16   , local => true
 17   , genTypes => true
 18   , genTables => true
 19   , enableHierarchy => dbms_xmlschema.ENABLE_HIERARCHY_NONE
 20   );
 21  end;
 22  /

PL/SQL procedure successfully completed.

SQL>
SQL> begin
  2   dbms_xmlstorage_manage.renameCollectionTable(
  3     tab_name => 'WORKBOOK_XML'
  4   , xpath => '"XMLDATA"."worksheet"'
  5   , collection_table_name => 'WORKSHEET_XML'
  6   );
  7  end;
  8  /

PL/SQL procedure successfully completed.

SQL>
SQL> insert into workbook_xml values(
  2   xmltype('<workbook>
  3   <worksheet sheetName="Sheet1" sheetId="1"/>
  4   <worksheet sheetName="Sheet2" sheetId="2"/>
  5   <worksheet sheetName="Sheet3" sheetId="3"/>
  6  </workbook>')
  7  );

1 row created.

SQL>
SQL> commit;

Commit complete.

SQL>
SQL> col sheetName format a30
SQL> col sheetId format 99
SQL>
SQL> select x.*
  2  from workbook_xml t
  3     , xmltable( '/workbook/worksheet' passing t.object_value
  4                 columns sheetName varchar2(4000) path '@sheetName'
  5                       , sheetId   number         path '@sheetId' ) x
  6  ;

SHEETNAME                      SHEETID
------------------------------ -------
Sheet1                               1
Sheet2                               2
Sheet3                               3

3 rows selected.

SQL>
SQL> update workbook_xml t
  2  set t.object_value = xmlquery(
  3  'copy $d := .
  4   modify (
  5    for $i in $d/workbook/worksheet
  6    return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName)
  7   )
  8  return $d'
  9  passing t.object_value
 10  returning content
 11  );
update workbook_xml t
 *
ERROR at line 1:
ORA-01427: single-row subquery returns more than one row


SQL>
SQL> select xmlquery(
  2  'copy $d := .
  3   modify (
  4    for $i in $d/workbook/worksheet
  5    return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName)
  6   )
  7  return $d'
  8   passing t.object_value
  9   returning content
 10  ) as modified_doc
 11  from workbook_xml t
 12  ;
ERROR:
ORA-01427: single-row subquery returns more than one row



no rows selected

SQL>
SQL> select /*+ no_xml_query_rewrite */ xmlquery(
  2  'copy $d := .
  3   modify (
  4    for $i in $d/workbook/worksheet
  5    return replace value of node $i/@sheetName with concat("NEW_", $i/@sheetName)
  6   )
  7  return $d'
  8   passing t.object_value
  9   returning content
 10  ) as modified_doc
 11  from workbook_xml t
 12  ;

MODIFIED_DOC
--------------------------------------------------------------------------------
<workbook><worksheet sheetName="NEW_Sheet1" sheetId="1"/><worksheet sheetName="N
EW_Sheet2" sheetId="2"/><worksheet sheetName="NEW_Sheet3" sheetId="3"/></workboo
k>


1 row selected.
So as you can see, the error occurs when we try to update more than one node at a time (unless we force functional evaluation).
In my understanding, I would have expected the optimizer to rewrite the query like this :
SQL> set autotrace on explain
SQL> set lines 120
SQL> update table(
  2    select t.xmldata."worksheet"
  3    from workbook_xml t
  4  )
  5  set "sheetName" = 'NEW_' || "sheetName"
  6  ;

3 rows updated.


Execution Plan
----------------------------------------------------------
Plan hash value: 3126950886

-------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT    |               |     1 |  2012 |     5   (0)| 00:00:01 |
|   1 |  UPDATE             | WORKSHEET_XML |       |       |            |          |
|*  2 |   INDEX RANGE SCAN  | SYS_C0011990  |     1 |  2012 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| WORKBOOK_XML  |     1 |    10 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("WORKSHEET_XML"."NESTED_TABLE_ID"= SYS_OP_ENFORCE_NOT_NULL$
              (SELECT "T"."SYS_NC0000800009$" FROM "WORKBOOK_XML" "T"))

Note
-----
   - dynamic sampling used for this statement (level=2)
Is there something to do to have the optimizer rewrite the query to use the underlying storage structure, or are we just looking at an unsupported feature?
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Apr 10 2012
Added on Mar 3 2012
4 comments
935 views