You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by bp...@apache.org on 2006/08/25 00:59:53 UTC

svn commit: r434556 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/types/ engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTests/master/DerbyNet/ testi...

Author: bpendleton
Date: Thu Aug 24 15:59:52 2006
New Revision: 434556

URL: http://svn.apache.org/viewvc?rev=434556&view=rev
Log:
DERBY-688: Enhancements to XML functionality toward XPath/XQuery support

This patch was submitted by Army Brown (qozinx@gmail.com)

Attaching a "phase 7" patch, d688_phase7_v1.patch, that does the following:

  1 - Makes changes to catch all "Throwable" errors that might be
      thrown by Xalan or JAXP, instead of just catching the exceptions
      declared by the APIs. This is per the email thread here:

      http://www.nabble.com/xalan-assertion-when-execution-a-xml-query...-tf2149830.html#a5953476

      This allows Derby to continue working as normal if/when an
      unexpected Xalan/JAXP error (such NPE or assertion failure)
      occurs. In that case the statement itself will fail and the
      error will be printed, but Derby will continue to work as
      expected after the failure.

  2 - Slight change so that, in the event of an unexpected Xalan
      compilation error, the name of the operator that encountered
      the error will be printed as part of Derby's message. Currently
      the operator name isn't passed in and thus "{0}" shows up
      in the error message, which is incorrect.

  3 - Fixes a small bug in XML query execution code that was leading
      to NPEs in Xalan. Namely, the current code passes a null argument
      into Xalan where a non-null is expected (and required) for namespace
      prefix resolution.

  4 - Makes the first of two changes required to ensure Derby SQL/XML
      support agrees with the specification. The two changes are
      mentioned in my previous comments; this phase 7 patch addresses
      the first one (insertion of a non-Document node into a Derby XML
      column should not be allowed).


Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xml_general.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/xml_general.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xml_general.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xml_general.sql

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java Thu Aug 24 15:59:52 2006
@@ -56,6 +56,8 @@
 import org.apache.xpath.objects.XObject;
 import org.apache.xpath.objects.XNodeSet;
 
+import org.apache.xml.utils.PrefixResolverDefault;
+
 import org.apache.xalan.serialize.DOMSerializer;
 import org.apache.xalan.serialize.Serializer;
 import org.apache.xalan.serialize.SerializerFactory;
@@ -203,12 +205,23 @@
             // Just rethrow it.
             throw se;
 
-        } catch (Exception e) {
+        } catch (Throwable t) {
 
-            // Must be something caused by JAXP or Xalan; wrap it in a
-            // StandardException and rethrow it.
+            /* Must be something caused by JAXP or Xalan; wrap it in a
+             * StandardException and rethrow it. Note: we catch "Throwable"
+             * here to catch as many external errors as possible in order
+             * to minimize the chance of an uncaught JAXP/Xalan error (such
+             * as a NullPointerException) causing Derby to fail in a more
+             * serious way.  In particular, an uncaught Java exception
+             * like NPE can result in Derby throwing "ERROR 40XT0: An
+             * internal error was identified by RawStore module" for all
+             * statements on the connection after the failure--which we
+             * clearly don't want.  If we catch the error and wrap it,
+             * though, the statement will fail but Derby will continue to
+             * run as normal.
+             */ 
             throw StandardException.newException(
-                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, e);
+                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, t);
 
         }
 
@@ -225,21 +238,43 @@
      *
      * @param queryExpr The XPath expression to compile
      */
-    public void compileXQExpr(String queryExpr)
+    public void compileXQExpr(String queryExpr, String opName)
         throws StandardException
     {
         try {
 
-            // The following XPath constructor compiles the expression
-            // as part of the construction process.
-            query = new XPath(queryExpr, null, null, XPath.SELECT);
-
-        } catch (TransformerException te) {
-
-            // Something went wrong during compilation of the
-            // expression; wrap the error and re-throw it.
+            /* The following XPath constructor compiles the expression
+             * as part of the construction process.  We have to pass
+             * in a PrefixResolver object in order to avoid NPEs when
+             * invalid/unknown functions are used, so we just create
+             * a dummy one, which means prefixes will not be resolved
+             * in the query (Xalan will just throw an error if a prefix
+             * is used).  In the future we may want to revisit this
+             * to make it easier for users to query based on namespaces.
+             */
+            query = new XPath(queryExpr, null,
+                new PrefixResolverDefault(dBuilder.newDocument()),
+                XPath.SELECT);
+
+        } catch (Throwable te) {
+
+            /* Something went wrong during compilation of the
+             * expression; wrap the error and re-throw it.
+             * Note: we catch "Throwable" here to catch as many
+             * Xalan-produced errors as possible in order to
+             * minimize the chance of an uncaught Xalan error
+             * (such as a NullPointerException) causing Derby
+             * to fail in a more serious way.  In particular, an
+             * uncaught Java exception like NPE can result in
+             * Derby throwing "ERROR 40XT0: An internal error was
+             * identified by RawStore module" for all statements on
+             * the connection after the failure--which we clearly
+             * don't want.  If we catch the error and wrap it,
+             * though, the statement will fail but Derby will
+             * continue to run as normal. 
+             */
             throw StandardException.newException(
-                SQLState.LANG_XML_QUERY_ERROR, te);
+                SQLState.LANG_XML_QUERY_ERROR, te, opName);
 
         }
     }
@@ -344,7 +379,7 @@
      *  results of the query
      * @param resultXType The qualified XML type of the result
      *  of evaluating the expression, if returnResults is true.
-     *  If the result is a sequence of one Document or Element node
+     *  If the result is a sequence of exactly one Document node
      *  then this will be XML(DOCUMENT(ANY)); else it will be
      *  XML(SEQUENCE).  If returnResults is false, this value
      *  is ignored.
@@ -438,16 +473,14 @@
 
         nodeList = null;
 
-        // Indicate what kind of XML result value we have.  If
-        // we have a sequence of exactly one Element or Document
-        // then it is XMLPARSE-able and so we consider it to be
-        // of type XML_DOC_ANY (which means we can store it in
-        // a Derby XML column).
-        if ((numItems == 1) && ((itemRefs.get(0) instanceof Document)
-            || (itemRefs.get(0) instanceof Element)))
-        {
+        /* Indicate what kind of XML result value we have.  If
+         * we have a sequence of exactly one Document then it
+         * is XMLPARSE-able and so we consider it to be of type
+         * XML_DOC_ANY (which means we can store it in a Derby
+         * XML column).
+         */
+        if ((numItems == 1) && (itemRefs.get(0) instanceof Document))
             resultXType[0] = XML.XML_DOC_ANY;
-        }
         else
             resultXType[0] = XML.XML_SEQUENCE;
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XML.java Thu Aug 24 15:59:52 2006
@@ -555,11 +555,23 @@
                         "but we shouldn't have made it this far");
             }
 
-        } catch (Exception xe) {
-        // Couldn't parse the XML document.  Throw a StandardException
-        // with the parse exception nested in it.
+        } catch (Throwable t) {
+        /* Couldn't parse the XML document.  Throw a StandardException
+         * with the parse exception (or other error) nested in it.
+         * Note: we catch "Throwable" here to catch as many external
+         * errors as possible in order to minimize the chance of an
+         * uncaught JAXP/Xalan error (such as a NullPointerException)
+         * causing Derby to fail in a more serious way.  In particular,
+         * an uncaught Java exception like NPE can result in Derby
+         * throwing "ERROR 40XT0: An internal error was identified by
+         * RawStore module" for all statements on the connection after
+         * the failure--which we clearly don't want.  If we catch the
+         * error and wrap it, though, the statement will fail but Derby
+         * will continue to run as normal.
+         */ 
             throw StandardException.newException(
-                SQLState.LANG_INVALID_XML_DOCUMENT, xe);
+                SQLState.LANG_INVALID_XML_DOCUMENT, t);
+
         }
 
         // If we get here, the text is valid XML so go ahead
@@ -676,15 +688,26 @@
             return new SQLBoolean(null !=
                 sqlxUtil.evalXQExpression(this, false, new int[1]));
 
-        } catch (Exception xe) {
-        // Failed somewhere during evaluation of the XML query expression;
-        // turn error into a StandardException and throw it.
-            if (xe instanceof StandardException)
-                throw (StandardException)xe;
-            else {
-                throw StandardException.newException(
-                    SQLState.LANG_XML_QUERY_ERROR, xe, "XMLEXISTS");
-            }
+        } catch (StandardException se) {
+
+            // Just re-throw it.
+            throw se;
+
+        } catch (Throwable xe) {
+        /* Failed somewhere during evaluation of the XML query expression;
+         * turn error into a StandardException and throw it.  Note: we
+         * catch "Throwable" here to catch as many Xalan-produced errors
+         * as possible in order to minimize the chance of an uncaught Xalan
+         * error (such as a NullPointerException) causing Derby to fail in
+         * a more serious way.  In particular, an uncaught Java exception
+         * like NPE can result in Derby throwing "ERROR 40XT0: An internal
+         * error was identified by RawStore module" for all statements on
+         * the connection after the failure--which we clearly don't want.  
+         * If we catch the error and wrap it, though, the statement will
+         * fail but Derby will continue to run as normal. 
+         */
+            throw StandardException.newException(
+                SQLState.LANG_XML_QUERY_ERROR, xe, "XMLEXISTS");
         }
     }
 
@@ -744,9 +767,19 @@
             // Just re-throw it.
             throw se;
 
-        } catch (Exception xe) {
-        // Failed somewhere during evaluation of the XML query expression;
-        // turn error into a StandardException and throw it.
+        } catch (Throwable xe) {
+        /* Failed somewhere during evaluation of the XML query expression;
+         * turn error into a StandardException and throw it.  Note: we
+         * catch "Throwable" here to catch as many Xalan-produced errors
+         * as possible in order to minimize the chance of an uncaught Xalan
+         * error (such as a NullPointerException) causing Derby to fail in
+         * a more serious way.  In particular, an uncaught Java exception
+         * like NPE can result in Derby throwing "ERROR 40XT0: An internal
+         * error was identified by RawStore module" for all statements on
+         * the connection after the failure--which we clearly don't want.  
+         * If we catch the error and wrap it, though, the statement will
+         * fail but Derby will continue to run as normal. 
+         */
             throw StandardException.newException(
                 SQLState.LANG_XML_QUERY_ERROR, xe, "XMLQUERY");
         }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java Thu Aug 24 15:59:52 2006
@@ -367,7 +367,8 @@
         // compile the query expression.
             sqlxUtil = new SqlXmlUtil();
             sqlxUtil.compileXQExpr(
-                ((CharConstantNode)leftOperand).getString());
+                ((CharConstantNode)leftOperand).getString(),
+                (operatorType == XMLEXISTS_OP ? "XMLEXISTS" : "XMLQUERY"));
         }
 
         // Right operand must be an XML data value.  NOTE: This

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj Thu Aug 24 15:59:52 2006
@@ -7098,9 +7098,9 @@
  * operator uses and the result is always a Document node).
  * Internally this means that we can only store a sequence if it
  * contains exactly one org.w3c.dom.Node that is an instance of
- * either org.w3c.dom.Document or org.w3c.dom.Element.  If the
- * result of an XMLQUERY operation does not fit this criteria then
- * it will *not* be storable into Derby XML columns.
+ * org.w3c.dom.Document.  If the result of an XMLQUERY operation
+ * does not fit this criteria then it will *not* be storable into
+ * Derby XML columns.
  */
 short
 	xqReturningClause() throws StandardException :

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xml_general.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xml_general.out?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xml_general.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xml_general.out Thu Aug 24 15:59:52 2006
@@ -632,6 +632,16 @@
 ERROR 42Z77: Context item must have type 'XML'; 'CHAR' is not allowed.
 ij> select i, xmlquery('//*' passing by ref cast ('hello' as clob) empty on empty) from t1;
 ERROR 42Z77: Context item must have type 'XML'; 'CLOB' is not allowed.
+ij> -- This should fail because the function is not recognized by Xalan.
+----- The failure should be an error from Xalan saying what the problem
+----- is; it should *NOT* be a NPE, which is what we were seeing before
+----- DERBY-688 was completed.
+select i,
+  xmlserialize(
+    xmlquery('data(//@*)' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+ERROR 10000: Encountered error while evaluating XML query expression for XMLQUERY operator; see next exception for details. SQLSTATE: XJ001: Java exception: 'Could not find function: data: javax.xml.transform.TransformerException'.
 ij> -- These should all succeed.  Since it's Xalan that's actually doing
 ----- the query evaluation we don't need to test very many queries; we
 ----- just want to make sure we get the correct results when there is
@@ -790,8 +800,7 @@
 -----
 <lets> try this </lets>       
 ij> -- Check insertion of XMLQUERY result into a table.  Should only allow
------ results that constitute a valid DOCUMENT node (i.e. that can be parsed
------ by the XMLPARSE operator).
+----- results that are a sequence of exactly one Document node.
 insert into t1 values (
   9,
   xmlparse(document '<here><is><my height="4.4">attribute</my></is></here>' preserve whitespace)
@@ -813,9 +822,9 @@
 0 |<ay>caramba</ay>                                                           
 0 |<there><goes><my weight="180">attribute</my></goes></there>                
 ij> -- These should all fail because the result of the XMLQUERY op is
------ not a valid document (it's either an empty sequence, an attribute,
------ some undefined value, or a sequence with more than one item in
------ it.
+----- not a valid document (it's either an empty sequence, a node that is
+----- not a Document node, some undefined value, or a sequence with more
+----- than one item in it).
 insert into t2 (i, x) values (
   20, 
   (select
@@ -856,27 +865,27 @@
   )
 );
 ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
-ij> -- These should succeed.
-insert into t2 (i, x) values (
+ij> insert into t2 (i, x) values (
   25,
   (select
-    xmlquery('.' passing by ref x returning sequence empty on empty)
+    xmlquery('//is' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
 ij> insert into t2 (i, x) values (
   26,
   (select
-    xmlquery('//is' passing by ref x returning sequence empty on empty)
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
-ij> insert into t2 (i, x) values (
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- These should succeed.
+insert into t2 (i, x) values (
   27,
   (select
-    xmlquery('/here' passing by ref x returning sequence empty on empty)
+    xmlquery('.' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -884,7 +893,7 @@
 ij> insert into t2 (i, x) values (
   28,
   (select
-    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    xmlquery('/here/..' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -894,10 +903,8 @@
 I |2                                                                          
 -----
 1 |<should> work as planned </should>                                         
-25 |<here><is><my height="4.4">attribute</my></is></here>                      
-26 |<is><my height="4.4">attribute</my></is>                                   
 27 |<here><is><my height="4.4">attribute</my></is></here>                      
-28 |<my height="4.4">attribute</my>                                            
+28 |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Next two should _both_ succeed because there's no row with i = 100
 ----- in t1, thus the SELECT will return null and XMLQuery operator should
 ----- never get executed.  x will be NULL in these cases.
@@ -938,7 +945,7 @@
 1 row inserted/updated/deleted
 ij> update t3
   set x = 
-    xmlquery('//*[@height]' passing by ref
+    xmlquery('self::node()[//@height]' passing by ref
       (select
         xmlquery('.' passing by ref x empty on empty)
         from t1
@@ -995,7 +1002,7 @@
 0 |<ay>caramba</ay>                                                           
 0 |<there><goes><my weight="180">attribute</my></goes></there>                
 29 |<none><here/></none>                                                       
-30 |<my height="4.4">attribute</my>                                            
+30 |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Pass results of an XMLQUERY op into another XMLQUERY op.
 ----- Should work so long as results of the first op constitute
 ----- a valid document.
@@ -1013,7 +1020,7 @@
 ij> select i,
   xmlserialize(
     xmlquery('.' passing by ref
-      xmlquery('//lets/@*' passing by ref
+      xmlquery('//lets' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1022,7 +1029,7 @@
 ERROR 2200V: Invalid context item for XMLQUERY operator; context items must be well-formed DOCUMENT nodes.
 ij> select i,
   xmlexists('.' passing by ref
-    xmlquery('//lets/@*' passing by ref
+    xmlquery('/okay' passing by ref
       xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
     empty on empty)
   )
@@ -1032,7 +1039,7 @@
 select i,
   xmlserialize(
     xmlquery('/not' passing by ref
-      xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1047,8 +1054,8 @@
 ij> -- Should succeed with various results.
 select i,
   xmlserialize(
-    xmlquery('.' passing by ref
-      xmlquery('//lets' passing by ref
+    xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1062,8 +1069,8 @@
 9 |<lets boki="inigo"/>                                                                                
 ij> select i,
   xmlserialize(
-    xmlquery('//@boki' passing by ref
-      xmlquery('/okay' passing by ref
+    xmlquery('string(//@boki)' passing by ref
+      xmlquery('/okay/..' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1077,8 +1084,8 @@
 9 |inigo                                                                                               
 ij> select i,
   xmlserialize(
-    xmlquery('/masted/text()' passing by ref
-      xmlquery('//masted' passing by ref x empty on empty)
+    xmlquery('/half/masted/text()' passing by ref
+      xmlquery('.' passing by ref x empty on empty)
     empty on empty)
   as char(100))
 from t1 where i = 6;
@@ -1086,8 +1093,8 @@
 -----
 6 | bass                                                                                               
 ij> select i,
-  xmlexists('/masted/text()' passing by ref
-    xmlquery('//masted' passing by ref x empty on empty)
+  xmlexists('/half/masted/text()' passing by ref
+    xmlquery('.' passing by ref x empty on empty)
   )
 from t1 where i = 6;
 I |2     

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/xml_general.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/xml_general.out?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/xml_general.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/xml_general.out Thu Aug 24 15:59:52 2006
@@ -633,6 +633,16 @@
 ERROR 42Z77: Context item must have type 'XML'; 'CHAR' is not allowed.
 ij> select i, xmlquery('//*' passing by ref cast ('hello' as clob) empty on empty) from t1;
 ERROR 42Z77: Context item must have type 'XML'; 'CLOB' is not allowed.
+ij> -- This should fail because the function is not recognized by Xalan.
+----- The failure should be an error from Xalan saying what the problem
+----- is; it should *NOT* be a NPE, which is what we were seeing before
+----- DERBY-688 was completed.
+select i,
+  xmlserialize(
+    xmlquery('data(//@*)' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+ERROR 10000: Encountered error while evaluating XML query expression for XMLQUERY operator; see next exception for details. SQLSTATE: XJ001: Java exception: 'Could not find function: data: javax.xml.transform.TransformerException'.
 ij> -- These should all succeed.  Since it's Xalan that's actually doing
 ----- the query evaluation we don't need to test very many queries; we
 ----- just want to make sure we get the correct results when there is
@@ -791,8 +801,7 @@
 -----
 <lets> try this </lets>       
 ij> -- Check insertion of XMLQUERY result into a table.  Should only allow
------ results that constitute a valid DOCUMENT node (i.e. that can be parsed
------ by the XMLPARSE operator).
+----- results that are a sequence of exactly one Document node.
 insert into t1 values (
   9,
   xmlparse(document '<here><is><my height="4.4">attribute</my></is></here>' preserve whitespace)
@@ -814,9 +823,9 @@
 0 |<ay>caramba</ay>                                                           
 0 |<there><goes><my weight="180">attribute</my></goes></there>                
 ij> -- These should all fail because the result of the XMLQUERY op is
------ not a valid document (it's either an empty sequence, an attribute,
------ some undefined value, or a sequence with more than one item in
------ it.
+----- not a valid document (it's either an empty sequence, a node that is
+----- not a Document node, some undefined value, or a sequence with more
+----- than one item in it).
 insert into t2 (i, x) values (
   20, 
   (select
@@ -857,27 +866,27 @@
   )
 );
 ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
-ij> -- These should succeed.
-insert into t2 (i, x) values (
+ij> insert into t2 (i, x) values (
   25,
   (select
-    xmlquery('.' passing by ref x returning sequence empty on empty)
+    xmlquery('//is' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
 ij> insert into t2 (i, x) values (
   26,
   (select
-    xmlquery('//is' passing by ref x returning sequence empty on empty)
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
-ij> insert into t2 (i, x) values (
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- These should succeed.
+insert into t2 (i, x) values (
   27,
   (select
-    xmlquery('/here' passing by ref x returning sequence empty on empty)
+    xmlquery('.' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -885,7 +894,7 @@
 ij> insert into t2 (i, x) values (
   28,
   (select
-    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    xmlquery('/here/..' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -895,10 +904,8 @@
 I |2                                                                          
 -----
 1 |<should> work as planned </should>                                         
-25 |<here><is><my height="4.4">attribute</my></is></here>                      
-26 |<is><my height="4.4">attribute</my></is>                                   
 27 |<here><is><my height="4.4">attribute</my></is></here>                      
-28 |<my height="4.4">attribute</my>                                            
+28 |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Next two should _both_ succeed because there's no row with i = 100
 ----- in t1, thus the SELECT will return null and XMLQuery operator should
 ----- never get executed.  x will be NULL in these cases.
@@ -939,7 +946,7 @@
 1 row inserted/updated/deleted
 ij> update t3
   set x = 
-    xmlquery('//*[@height]' passing by ref
+    xmlquery('self::node()[//@height]' passing by ref
       (select
         xmlquery('.' passing by ref x empty on empty)
         from t1
@@ -996,7 +1003,7 @@
 0 |<ay>caramba</ay>                                                           
 0 |<there><goes><my weight="180">attribute</my></goes></there>                
 29 |<none><here/></none>                                                       
-30 |<my height="4.4">attribute</my>                                            
+30 |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Pass results of an XMLQUERY op into another XMLQUERY op.
 ----- Should work so long as results of the first op constitute
 ----- a valid document.
@@ -1014,7 +1021,7 @@
 ij> select i,
   xmlserialize(
     xmlquery('.' passing by ref
-      xmlquery('//lets/@*' passing by ref
+      xmlquery('//lets' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1023,7 +1030,7 @@
 ERROR 2200V: Invalid context item for XMLQUERY operator; context items must be well-formed DOCUMENT nodes.
 ij> select i,
   xmlexists('.' passing by ref
-    xmlquery('//lets/@*' passing by ref
+    xmlquery('/okay' passing by ref
       xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
     empty on empty)
   )
@@ -1033,7 +1040,7 @@
 select i,
   xmlserialize(
     xmlquery('/not' passing by ref
-      xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1048,8 +1055,8 @@
 ij> -- Should succeed with various results.
 select i,
   xmlserialize(
-    xmlquery('.' passing by ref
-      xmlquery('//lets' passing by ref
+    xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1063,8 +1070,8 @@
 9 |<lets boki="inigo"/>                                                                                
 ij> select i,
   xmlserialize(
-    xmlquery('//@boki' passing by ref
-      xmlquery('/okay' passing by ref
+    xmlquery('string(//@boki)' passing by ref
+      xmlquery('/okay/..' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1078,8 +1085,8 @@
 9 |inigo                                                                                               
 ij> select i,
   xmlserialize(
-    xmlquery('/masted/text()' passing by ref
-      xmlquery('//masted' passing by ref x empty on empty)
+    xmlquery('/half/masted/text()' passing by ref
+      xmlquery('.' passing by ref x empty on empty)
     empty on empty)
   as char(100))
 from t1 where i = 6;
@@ -1087,8 +1094,8 @@
 -----
 6 | bass                                                                                               
 ij> select i,
-  xmlexists('/masted/text()' passing by ref
-    xmlquery('//masted' passing by ref x empty on empty)
+  xmlexists('/half/masted/text()' passing by ref
+    xmlquery('.' passing by ref x empty on empty)
   )
 from t1 where i = 6;
 I |2     

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xml_general.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xml_general.out?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xml_general.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xml_general.out Thu Aug 24 15:59:52 2006
@@ -651,6 +651,17 @@
 ERROR 42Z77: Context item must have type 'XML'; 'CHAR' is not allowed.
 ij> select i, xmlquery('//*' passing by ref cast ('hello' as clob) empty on empty) from t1;
 ERROR 42Z77: Context item must have type 'XML'; 'CLOB' is not allowed.
+ij> -- This should fail because the function is not recognized by Xalan.
+-- The failure should be an error from Xalan saying what the problem
+-- is; it should *NOT* be a NPE, which is what we were seeing before
+-- DERBY-688 was completed.
+select i,
+  xmlserialize(
+    xmlquery('data(//@*)' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+ERROR 10000: Encountered error while evaluating XML query expression for XMLQUERY operator; see next exception for details.
+ERROR XJ001: Java exception: 'Could not find function: data: javax.xml.transform.TransformerException'.
 ij> -- These should all succeed.  Since it's Xalan that's actually doing
 -- the query evaluation we don't need to test very many queries; we
 -- just want to make sure we get the correct results when there is
@@ -809,8 +820,7 @@
 ------------------------------
 <lets> try this </lets>       
 ij> -- Check insertion of XMLQUERY result into a table.  Should only allow
--- results that constitute a valid DOCUMENT node (i.e. that can be parsed
--- by the XMLPARSE operator).
+-- results that are a sequence of exactly one Document node.
 insert into t1 values (
   9,
   xmlparse(document '<here><is><my height="4.4">attribute</my></is></here>' preserve whitespace)
@@ -832,9 +842,9 @@
 0          |<ay>caramba</ay>                                                           
 0          |<there><goes><my weight="180">attribute</my></goes></there>                
 ij> -- These should all fail because the result of the XMLQUERY op is
--- not a valid document (it's either an empty sequence, an attribute,
--- some undefined value, or a sequence with more than one item in
--- it.
+-- not a valid document (it's either an empty sequence, a node that is
+-- not a Document node, some undefined value, or a sequence with more
+-- than one item in it).
 insert into t2 (i, x) values (
   20, 
   (select
@@ -875,27 +885,27 @@
   )
 );
 ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
-ij> -- These should succeed.
-insert into t2 (i, x) values (
+ij> insert into t2 (i, x) values (
   25,
   (select
-    xmlquery('.' passing by ref x returning sequence empty on empty)
+    xmlquery('//is' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
 ij> insert into t2 (i, x) values (
   26,
   (select
-    xmlquery('//is' passing by ref x returning sequence empty on empty)
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
-1 row inserted/updated/deleted
-ij> insert into t2 (i, x) values (
+ERROR 2200L: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- These should succeed.
+insert into t2 (i, x) values (
   27,
   (select
-    xmlquery('/here' passing by ref x returning sequence empty on empty)
+    xmlquery('.' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -903,7 +913,7 @@
 ij> insert into t2 (i, x) values (
   28,
   (select
-    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    xmlquery('/here/..' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -913,10 +923,8 @@
 I          |2                                                                          
 ---------------------------------------------------------------------------------------
 1          |<should> work as planned </should>                                         
-25         |<here><is><my height="4.4">attribute</my></is></here>                      
-26         |<is><my height="4.4">attribute</my></is>                                   
 27         |<here><is><my height="4.4">attribute</my></is></here>                      
-28         |<my height="4.4">attribute</my>                                            
+28         |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Next two should _both_ succeed because there's no row with i = 100
 -- in t1, thus the SELECT will return null and XMLQuery operator should
 -- never get executed.  x will be NULL in these cases.
@@ -957,7 +965,7 @@
 1 row inserted/updated/deleted
 ij> update t3
   set x = 
-    xmlquery('//*[@height]' passing by ref
+    xmlquery('self::node()[//@height]' passing by ref
       (select
         xmlquery('.' passing by ref x empty on empty)
         from t1
@@ -1014,7 +1022,7 @@
 0          |<ay>caramba</ay>                                                           
 0          |<there><goes><my weight="180">attribute</my></goes></there>                
 29         |<none><here/></none>                                                       
-30         |<my height="4.4">attribute</my>                                            
+30         |<here><is><my height="4.4">attribute</my></is></here>                      
 ij> -- Pass results of an XMLQUERY op into another XMLQUERY op.
 -- Should work so long as results of the first op constitute
 -- a valid document.
@@ -1034,7 +1042,7 @@
 ij> select i,
   xmlserialize(
     xmlquery('.' passing by ref
-      xmlquery('//lets/@*' passing by ref
+      xmlquery('//lets' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1045,7 +1053,7 @@
 ERROR 2200V: Invalid context item for XMLQUERY operator; context items must be well-formed DOCUMENT nodes.
 ij> select i,
   xmlexists('.' passing by ref
-    xmlquery('//lets/@*' passing by ref
+    xmlquery('/okay' passing by ref
       xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
     empty on empty)
   )
@@ -1057,7 +1065,7 @@
 select i,
   xmlserialize(
     xmlquery('/not' passing by ref
-      xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1072,8 +1080,8 @@
 ij> -- Should succeed with various results.
 select i,
   xmlserialize(
-    xmlquery('.' passing by ref
-      xmlquery('//lets' passing by ref
+    xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1087,8 +1095,8 @@
 9          |<lets boki="inigo"/>                                                                                
 ij> select i,
   xmlserialize(
-    xmlquery('//@boki' passing by ref
-      xmlquery('/okay' passing by ref
+    xmlquery('string(//@boki)' passing by ref
+      xmlquery('/okay/..' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -1102,8 +1110,8 @@
 9          |inigo                                                                                               
 ij> select i,
   xmlserialize(
-    xmlquery('/masted/text()' passing by ref
-      xmlquery('//masted' passing by ref x empty on empty)
+    xmlquery('/half/masted/text()' passing by ref
+      xmlquery('.' passing by ref x empty on empty)
     empty on empty)
   as char(100))
 from t1 where i = 6;
@@ -1111,8 +1119,8 @@
 ----------------------------------------------------------------------------------------------------------------
 6          | bass                                                                                               
 ij> select i,
-  xmlexists('/masted/text()' passing by ref
-    xmlquery('//masted' passing by ref x empty on empty)
+  xmlexists('/half/masted/text()' passing by ref
+    xmlquery('.' passing by ref x empty on empty)
   )
 from t1 where i = 6;
 I          |2    

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xml_general.sql
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xml_general.sql?rev=434556&r1=434555&r2=434556&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xml_general.sql (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xml_general.sql Thu Aug 24 15:59:52 2006
@@ -265,6 +265,16 @@
 select i, xmlquery('//*' passing by ref 'hello' empty on empty) from t1;
 select i, xmlquery('//*' passing by ref cast ('hello' as clob) empty on empty) from t1;
 
+-- This should fail because the function is not recognized by Xalan.
+-- The failure should be an error from Xalan saying what the problem
+-- is; it should *NOT* be a NPE, which is what we were seeing before
+-- DERBY-688 was completed.
+select i,
+  xmlserialize(
+    xmlquery('data(//@*)' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+
 -- These should all succeed.  Since it's Xalan that's actually doing
 -- the query evaluation we don't need to test very many queries; we
 -- just want to make sure we get the correct results when there is
@@ -340,8 +350,7 @@
 as char(30));
 
 -- Check insertion of XMLQUERY result into a table.  Should only allow
--- results that constitute a valid DOCUMENT node (i.e. that can be parsed
--- by the XMLPARSE operator).
+-- results that are a sequence of exactly one Document node.
 
 insert into t1 values (
   9,
@@ -359,9 +368,9 @@
 select i, xmlserialize(x as char(75)) from t3;
 
 -- These should all fail because the result of the XMLQUERY op is
--- not a valid document (it's either an empty sequence, an attribute,
--- some undefined value, or a sequence with more than one item in
--- it.
+-- not a valid document (it's either an empty sequence, a node that is
+-- not a Document node, some undefined value, or a sequence with more
+-- than one item in it).
 
 insert into t2 (i, x) values (
   20, 
@@ -403,12 +412,10 @@
   )
 );
 
--- These should succeed.
-
 insert into t2 (i, x) values (
   25,
   (select
-    xmlquery('.' passing by ref x returning sequence empty on empty)
+    xmlquery('//is' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -416,15 +423,17 @@
 insert into t2 (i, x) values (
   26,
   (select
-    xmlquery('//is' passing by ref x returning sequence empty on empty)
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
 
+-- These should succeed.
+
 insert into t2 (i, x) values (
   27,
   (select
-    xmlquery('/here' passing by ref x returning sequence empty on empty)
+    xmlquery('.' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -432,7 +441,7 @@
 insert into t2 (i, x) values (
   28,
   (select
-    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    xmlquery('/here/..' passing by ref x returning sequence empty on empty)
     from t1 where i = 9
   )
 );
@@ -478,7 +487,7 @@
 
 update t3
   set x = 
-    xmlquery('//*[@height]' passing by ref
+    xmlquery('self::node()[//@height]' passing by ref
       (select
         xmlquery('.' passing by ref x empty on empty)
         from t1
@@ -551,7 +560,7 @@
 select i,
   xmlserialize(
     xmlquery('.' passing by ref
-      xmlquery('//lets/@*' passing by ref
+      xmlquery('//lets' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -560,7 +569,7 @@
 
 select i,
   xmlexists('.' passing by ref
-    xmlquery('//lets/@*' passing by ref
+    xmlquery('/okay' passing by ref
       xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
     empty on empty)
   )
@@ -571,7 +580,7 @@
 select i,
   xmlserialize(
     xmlquery('/not' passing by ref
-      xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -582,8 +591,8 @@
 
 select i,
   xmlserialize(
-    xmlquery('.' passing by ref
-      xmlquery('//lets' passing by ref
+    xmlquery('//lets' passing by ref
+      xmlquery('.' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -592,8 +601,8 @@
 
 select i,
   xmlserialize(
-    xmlquery('//@boki' passing by ref
-      xmlquery('/okay' passing by ref
+    xmlquery('string(//@boki)' passing by ref
+      xmlquery('/okay/..' passing by ref
         xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
       empty on empty)
     empty on empty)
@@ -602,15 +611,15 @@
 
 select i,
   xmlserialize(
-    xmlquery('/masted/text()' passing by ref
-      xmlquery('//masted' passing by ref x empty on empty)
+    xmlquery('/half/masted/text()' passing by ref
+      xmlquery('.' passing by ref x empty on empty)
     empty on empty)
   as char(100))
 from t1 where i = 6;
 
 select i,
-  xmlexists('/masted/text()' passing by ref
-    xmlquery('//masted' passing by ref x empty on empty)
+  xmlexists('/half/masted/text()' passing by ref
+    xmlquery('.' passing by ref x empty on empty)
   )
 from t1 where i = 6;