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/09 00:06:01 UTC

svn commit: r429847 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/types/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/referen...

Author: bpendleton
Date: Tue Aug  8 15:06:01 2006
New Revision: 429847

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

This revision contains d688_phase3_v1_code.patch and d688_phase3_v1_tests.patch

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

Attaching a "phase 3" patch that implements the XMLQUERY operator. The patch is in two parts:

  - d688_phase3_v1_code.patch
  - d688_phase3_v1_tests.patch

When committed, though, *both* patches should be committed together in
order to avoid test diffs.

The SQL parsing/compile time logic was added as part of the phase 2 patch;
this patch handles the execution-time logic by making the necessary Xalan
calls to evaluate an expression and to retrieve the results.

The phase 3 patch also adds logic to distinguish between two "types" of XML:
XML(DOCUMENT(ANY)) and XML(SEQUENCE), as defined in the SQL/XML[2006]
specification. The reason we need to distinguish between the two is that
the result of evaluating an XML query expression against an XML document
can be an arbitrary list of items including atomic values, attributes,
etc.--i.e. a sequence of items that is *not* required to form a valid
DOCUMENT node. For now, though, we only allow valid DOCUMENTs to be
inserted into XML columns, so we have to be able to look at the results
of the XMLQUERY operator to determine whether or not it's a valid DOCUMENT,
and if not we disallow insertion of that result into an XML column.
We can, however, keep the result transiently and pass it into other
operations that accept an XML value (namely, XMLSERIALIZE, which a user
can then use to retrieve the results in serialized form). 


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/iapi/types/XMLDataValue.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
    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=429847&r1=429846&r2=429847&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 Tue Aug  8 15:06:01 2006
@@ -32,7 +32,9 @@
 // -- JDBC 3.0 JAXP API classes.
 
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.w3c.dom.Text;
 
 import org.xml.sax.ErrorHandler;
@@ -285,21 +287,39 @@
 
     /**
      * Evaluate this object's compiled XML query expression against
-     * the received xmlContext and return whether or not at least
-     * one item in the xmlContext is returned.
+     * the received xmlContext.  Then if returnResults is false,
+     * return an empty sequence (ArrayList) if evaluation yields
+     * at least one item and return null if evaluation yields zero
+     * items (the caller can then just check for null to see if the
+     * query returned any items).  If returnResults is true, then return
+     * return a sequence (ArrayList) containing all items returned
+     * from evaluation of the expression.  This array list can contain
+     * any combination of atomic values and XML nodes; it may also
+     * be empty.
      *
      * Assumption here is that the query expression has already been
      * compiled and is stored in this.query.
      *
      * @param xmlContext The XML value against which to evaluate
-     *  the stored (compiled) query expression.
-     * @return True if evaluation returned at least one item,
-     *  false otherwise.
+     *  the stored (compiled) query expression
+     * @param returnResults Whether or not to return the actual
+     *  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
+     *  then this will be XML(DOCUMENT(ANY)); else it will be
+     *  XML(SEQUENCE).  If returnResults is false, this value
+     *  is ignored.
+     * @return If returnResults is false then return an empty
+     *  ArrayList if evaluation returned at least one item and return
+     *  null otherwise.  If returnResults is true then return an
+     *  array list containing all of the result items and return
+     *  the qualified XML type via the resultXType parameter.
      * @exception Exception thrown on error (and turned into a
      *  StandardException by the caller).
      */
-    protected boolean evalXQExpression(XMLDataValue xmlContext)
-        throws Exception
+    protected ArrayList evalXQExpression(XMLDataValue xmlContext,
+        boolean returnResults, int [] resultXType) throws Exception
     {
         // Make sure we have a compiled query.
         if (SanityManager.DEBUG) {
@@ -308,8 +328,21 @@
                 "Failed to locate compiled XML query expression.");
         }
 
-        // Create a DOM node from the xmlContext, since that's how
-        // we feed the context to Xalan.
+        /* Create a DOM node from the xmlContext, since that's how
+         * we feed the context to Xalan.  We do this by creating
+         * a Document node using DocumentBuilder, which means that
+         * the serialized form of the context node must be a string
+         * value that is parse-able by DocumentBuilder--i.e. it must
+         * constitute a valid XML document.  If that's true then
+         * the context item's qualified type will be DOC_ANY.
+         */
+        if (xmlContext.getXType() != XML.XML_DOC_ANY)
+        {
+            throw StandardException.newException(
+                SQLState.LANG_INVALID_XML_CONTEXT_ITEM,
+                (returnResults ? "XMLQUERY" : "XMLEXISTS"));
+        } 
+
         Document docNode = null;
         docNode = dBuilder.parse(
             new InputSource(
@@ -320,23 +353,67 @@
         xpContext.reset();
         XObject xOb = query.execute(xpContext, docNode, null);
 
-        // We don't want to return the actual results, we just
-        // want to know if there was at least one item in the
-        // result sequence.
-        if ((xOb instanceof XNodeSet) &&
-            (((XNodeSet)xOb).nodelist().getLength() > 0))
-        { // If we have a sequence (XNodeSet) of length greater
-          // than zero, then we know that at least one item
-          // "exists" in the result.
-            return true;
+        if (!returnResults)
+        {
+            // We don't want to return the actual results, we just
+            // want to know if there was at least one item in the
+            // result sequence.
+            if ((xOb instanceof XNodeSet) &&
+                (((XNodeSet)xOb).nodelist().getLength() > 0))
+            { // If we have a sequence (XNodeSet) of length greater
+              // than zero, then we know that at least one item
+              // "exists" in the result so return a non-null list.
+                return new ArrayList(0);
+            }
+            else if (!(xOb instanceof XNodeSet))
+            // we have a single atomic value, which means the result is
+            // non-empty.  So return a non-null list.
+                return new ArrayList(0);
+            else {
+            // return null; caller will take this to mean we have an
+            // an empty sequence.
+                return null;
+            }
+        }
+
+        // Else process the results.
+        NodeList nodeList = null;
+        int numItems = 0;
+        if (!(xOb instanceof XNodeSet))
+        // then we only have a single (probably atomic) item.
+            numItems = 1;
+        else {
+            nodeList = xOb.nodelist();
+            numItems = nodeList.getLength();
+        }
+
+        // Return a list of the items contained in the query results.
+        ArrayList itemRefs = new ArrayList();
+        if (nodeList == null)
+        // result is a single, non-node value (ex. it's an atomic number);
+        // in this case, just take the string value.
+            itemRefs.add(xOb.str());
+        else {
+            for (int i = 0; i < numItems; i++)
+                itemRefs.add(nodeList.item(i));
+        }
+
+        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)))
+        {
+            resultXType[0] = XML.XML_DOC_ANY;
         }
-        else if (!(xOb instanceof XNodeSet))
-        // we have a single atomic value, which means the result is
-        // non-empty.
-            return true;
+        else
+            resultXType[0] = XML.XML_SEQUENCE;
 
-        // Else the result was an empty sequence.
-        return false;
+        return itemRefs;
     }
 
     /* ****

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=429847&r1=429846&r2=429847&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 Tue Aug  8 15:06:01 2006
@@ -46,6 +46,8 @@
 import java.io.ObjectInput;
 import java.io.StringReader;
 
+import java.util.ArrayList;
+
 /**
  * This type implements the XMLDataValue interface and thus is
  * the type on which all XML related operations are executed.
@@ -76,14 +78,40 @@
     private static final int BASE_MEMORY_USAGE =
         ClassSize.estimateBaseFromCatalog(XML.class);
 
-	// Some syntax-related constants used to determine
-	// operator behavior.
-	public static final short XQ_PASS_BY_REF = 1;
-	public static final short XQ_PASS_BY_VALUE = 2;
-	public static final short XQ_RETURN_SEQUENCE = 3;
-	public static final short XQ_RETURN_CONTENT = 4;
-	public static final short XQ_EMPTY_ON_EMPTY = 5;
-	public static final short XQ_NULL_ON_EMPTY = 6;
+    // Some syntax-related constants used to determine
+    // operator behavior.
+    public static final short XQ_PASS_BY_REF = 1;
+    public static final short XQ_PASS_BY_VALUE = 2;
+    public static final short XQ_RETURN_SEQUENCE = 3;
+    public static final short XQ_RETURN_CONTENT = 4;
+    public static final short XQ_EMPTY_ON_EMPTY = 5;
+    public static final short XQ_NULL_ON_EMPTY = 6;
+
+    /* Per SQL/XML[2006] 4.2.2, there are several different
+     * XML "types" defined through use of primary and secondary
+     * "type modifiers".  For Derby we only support two kinds:
+     *
+     * XML(DOCUMENT(ANY)) : A valid and well-formed XML
+     *  document as defined by W3C, meaning that there is
+     *  exactly one root element node.  This is the only
+     *  type of XML that can be stored into a Derby XML
+     *  column.  This is also the type returned by a call
+     *  to XMLPARSE since we require the DOCUMENT keyword.
+     *
+     * XML(SEQUENCE): A sequence of items (could be nodes or
+     *  atomic values).  This is the type returned from an
+     *  XMLQUERY operation.  Any node that is XML(DOCUMENT(ANY))
+     *  is also XML(SEQUENCE).  Note that an XML(SEQUENCE)
+     *  value is *only* storable into a Derby XML column
+     *  if it is also an XML(DOCUMENT(ANY)).  See the
+     *  normalize method below for the code that enforces
+     *  this.
+     */
+    public static final int XML_DOC_ANY = 0;
+    public static final int XML_SEQUENCE = 1;
+
+    // The fully-qualified type for this XML value.
+    private int xType;
 
     // The actual XML data in this implementation is just a simple
     // string, so this class really just wraps a SQLChar and
@@ -112,6 +140,7 @@
     public XML()
     {
         xmlStringValue = null;
+        xType = -1;
     }
 
     /**
@@ -123,6 +152,22 @@
     private XML(SQLChar val)
     {
         xmlStringValue = (val == null ? null : (SQLChar)val.getClone());
+        xType = -1;
+    }
+
+    /**
+     * Private constructor used for the getClone() method.
+     * Takes a SQLChar and clones it and also takes a
+     * qualified XML type and stores that as this XML
+     * object's qualified type.
+     * @param val A SQLChar instance to clone and use for
+     *  this XML value.
+     * @param qualXType Qualified XML type.
+     */
+    private XML(SQLChar val, int xmlType)
+    {
+        xmlStringValue = (val == null ? null : (SQLChar)val.getClone());
+        setXType(xmlType);
     }
 
     /* ****
@@ -134,7 +179,7 @@
      */
     public DataValueDescriptor getClone()
     {
-        return new XML(xmlStringValue);
+        return new XML(xmlStringValue, getXType());
     }
 
     /**
@@ -206,16 +251,47 @@
 
         // Now just read the XML data as UTF-8.
         xmlStringValue.readExternalFromArray(in);
+
+        // If we read it from disk then it must have type
+        // XML_DOC_ANY because that's all we allow to be
+        // written into an XML column.
+        setXType(XML_DOC_ANY);
     }
 
     /**
+     * @see DataValueDescriptor#setFrom
+     *
+     * Note: 
      */
     protected void setFrom(DataValueDescriptor theValue)
         throws StandardException
     {
+        String strVal = theValue.getString();
+        if (strVal == null)
+        {
+            xmlStringValue = null;
+
+            // Null is a valid value for DOCUMENT(ANY)
+            setXType(XML_DOC_ANY);
+            return;
+        }
+
+        // Here we just store the received value locally.
         if (xmlStringValue == null)
             xmlStringValue = new SQLChar();
-        xmlStringValue.setValue(theValue.getString());
+        xmlStringValue.setValue(strVal);
+
+        /*
+         * Assumption is that if theValue is not an XML
+         * value then the caller is aware of whether or
+         * not theValue constitutes a valid XML(DOCUMENT(ANY))
+         * and will behave accordingly (see in particular the
+         * XMLQuery method of this class, which calls the
+         * setValue() method of XMLDataValue which in turn
+         * brings us to this method).
+         */
+        if (theValue instanceof XMLDataValue)
+        	setXType(((XMLDataValue)theValue).getXType());
     }
 
     /** 
@@ -281,6 +357,41 @@
         return 0;
     }
 
+    /**
+     * Normalization method - this method will always be called when
+     * storing an XML value into an XML column, for example, when
+     * inserting/updating.  We always force normalization in this
+     * case because we need to make sure the qualified type of the
+     * value we're trying to store is XML_DOC_ANY--we don't allow
+     * anything else.
+     *
+     * @param desiredType   The type to normalize the source column to
+     * @param source        The value to normalize
+     *
+     * @exception StandardException Thrown if source is not
+     *  XML_DOC_ANY.
+     */
+    public void normalize(
+                DataTypeDescriptor desiredType,
+                DataValueDescriptor source)
+                    throws StandardException
+    {
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(source instanceof XMLDataValue,
+                "Tried to store non-XML value into XML column; " +
+                "should have thrown error at compile time.");
+        }
+
+        if (((XMLDataValue)source).getXType() != XML_DOC_ANY) {
+            throw StandardException.newException(
+                SQLState.LANG_INVALID_XML_COLUMN_ASSIGN);
+        }
+
+        ((DataValueDescriptor) this).setValue(source);
+        return;
+
+    }
+
     /* ****
      * Storable interface, implies Externalizable, TypedFormat
      */
@@ -330,6 +441,11 @@
 
         // Now just read the XML data as UTF-8.
         xmlStringValue.readExternal(in);
+
+        // If we read it from disk then it must have type
+        // XML_DOC_ANY because that's all we allow to be
+        // written into an XML column.
+        setXType(XML_DOC_ANY);
     }
 
     /**
@@ -390,6 +506,11 @@
 
         // Now go ahead and use the stream.
         xmlStringValue.setStream(newStream);
+
+        // If we read it from disk then it must have type
+        // XML_DOC_ANY because that's all we allow to be
+        // written into an XML column.
+        setXType(XML_DOC_ANY);
     }
 
     /**
@@ -450,6 +571,7 @@
 
         // If we get here, the text is valid XML so go ahead
         // and load/store it.
+        setXType(XML_DOC_ANY);
         if (xmlStringValue == null)
             xmlStringValue = new SQLChar();
         xmlStringValue.setValue(text);
@@ -558,7 +680,8 @@
 
         try {
 
-            return new SQLBoolean(sqlxUtil.evalXQExpression(this));
+            return new SQLBoolean(null !=
+                sqlxUtil.evalXQExpression(this, false, new int[1]));
 
         } catch (Exception xe) {
         // We don't expect to get here.  Turn it into a StandardException
@@ -570,6 +693,91 @@
                     SQLState.LANG_UNEXPECTED_XML_EXCEPTION, xe);
             }
         }
+    }
+
+    /**
+     * Evaluate the XML query expression contained within the received
+     * util object against this XML value and store the results into
+     * the received XMLDataValue "result" param (assuming "result" is
+     * non-null; else create a new XMLDataValue).
+     *
+     * @param result The result of a previous call to this method; null
+     *  if not called yet.
+     * @param sqlxUtil Contains SQL/XML objects and util methods that
+     *  facilitate execution of XML-related operations
+     * @return An XMLDataValue whose content corresponds to the serialized
+     *  version of the results from evaluation of the query expression.
+     *  Note: this XMLDataValue may not be storable into Derby XML
+     *  columns.
+     * @exception Exception thrown on error (and turned into a
+     *  StandardException by the caller).
+     */
+    public XMLDataValue XMLQuery(XMLDataValue result,
+        SqlXmlUtil sqlxUtil) throws StandardException
+    {
+        if (this.isNull()) {
+        // if the context is null, we return null,
+        // per SQL/XML[2006] 6.17:GR.1.a.ii.1.
+            if (result == null)
+                result = (XMLDataValue)getNewNull();
+            else
+                result.setToNull();
+            return result;
+        }
+
+        try {
+ 
+            // Return an XML data value whose contents are the
+            // serialized version of the query results.
+            int [] xType = new int[1];
+            ArrayList itemRefs = sqlxUtil.evalXQExpression(
+                this, true, xType);
+
+            String strResult = sqlxUtil.serializeToString(itemRefs);
+            if (result == null)
+                result = new XML(new SQLChar(strResult));
+            else
+                result.setValue(new SQLChar(strResult));
+
+            // Now that we've set the result value, make sure
+            // to indicate what kind of XML value we have.
+            result.setXType(xType[0]);
+
+            // And finally we return the query result as an XML value.
+            return result;
+
+        } catch (StandardException se) {
+
+            // Just re-throw it.
+            throw se;
+
+        } catch (Exception xe) {
+        // We don't expect to get here.  Turn it into a
+        // StandardException and throw it.
+
+            throw StandardException.newException(
+                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, xe);
+        }
+    }
+
+    /* ****
+     * Helper classes and methods.
+     * */
+
+    /**
+     * Set this XML value's qualified type.
+     */
+    public void setXType(int xtype)
+    {
+        this.xType = xtype;
+    }
+
+    /**
+     * Retrieve this XML value's qualified type.
+     */
+    public int getXType()
+    {
+        return xType;
     }
 
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XMLDataValue.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XMLDataValue.java?rev=429847&r1=429846&r2=429847&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XMLDataValue.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/XMLDataValue.java Tue Aug  8 15:06:01 2006
@@ -81,4 +81,37 @@
     public BooleanDataValue XMLExists(SqlXmlUtil sqlxUtil)
 		throws StandardException;
 
+    /**
+     * Evaluate the XML query expression contained within the received
+     * util object against this XML value and store the results into
+     * the received XMLDataValue "result" param (assuming "result" is
+     * non-null; else create a new XMLDataValue).
+     *
+     * @param result The result of a previous call to this method; null
+     *  if not called yet.
+     * @param sqlxUtil Contains SQL/XML objects and util methods that
+     *  facilitate execution of XML-related operations
+     * @return An XMLDataValue whose content corresponds to the serialized
+     *  version of the results from evaluation of the query expression.
+     *  Note: this XMLDataValue may not be storable into Derby XML
+     *  columns.
+     * @exception Exception thrown on error (and turned into a
+     *  StandardException by the caller).
+     */
+    public XMLDataValue XMLQuery(XMLDataValue result, SqlXmlUtil sqlxUtil)
+		throws StandardException;
+
+    /* ****
+     * Helper classes and methods.
+     * */
+
+    /**
+     * Set this XML value's qualified type.
+     */
+    public void setXType(int xtype);
+
+    /**
+     * Retrieve this XML value's qualified type.
+     */
+    public int getXType();
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java?rev=429847&r1=429846&r2=429847&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java Tue Aug  8 15:06:01 2006
@@ -975,6 +975,16 @@
 										  this);
 			}
 		}
+
+		// Are we inserting/updating an XML column?  If so, we always
+		// return false so that normalization will occur.  We have to
+		// do this because there are different "kinds" of XML values
+		// and we need to make sure they match--but we don't know
+		// the "kind" until execution time.  See the "normalize"
+		// method in org.apache.derby.iapi.types.XML for more.
+		if (resultColumnType.getTypeId().isXMLTypeId())
+			return false;
+
 		/* Are they the same type? */
 		if ( ! resultColumnType.getTypeId().getSQLTypeName().equals(
 			expressionType.getTypeId().getSQLTypeName()
@@ -1039,6 +1049,15 @@
 		{
 			return false;
 		}
+
+		// Are we inserting/updating an XML column?  If so, we always
+		// return false so that normalization will occur.  We have to
+		// do this because there are different "kinds" of XML values
+		// and we need to make sure they match--but we don't know
+		// the "kind" until execution time.  See the "normalize"
+		// method in org.apache.derby.iapi.types.XML for more.
+		if (resultColumnType.getTypeId().isXMLTypeId())
+			return false;
 
 		/* Are they the same type? */
 		if ( ! resultColumnType.getTypeId().equals(

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=429847&r1=429846&r2=429847&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 Tue Aug  8 15:06:01 2006
@@ -7088,11 +7088,15 @@
  *
  * NOTE: This means that we may not be able to store the results
  * of an XMLQUERY operation into a Derby XML column.  Right now
- * an XML column can only hold valid DOCUMENT nodes, which translates
- * into a sequence of exactly one org.w3c.dom.Node.  So if the
- * result of an XMLQUERY operation is not a sequence of exactly
- * one Node, then that result will *not* be storable into
- * Derby XML columns.
+ * an XML column can only hold valid DOCUMENT nodes, which we
+ * we define as an XML value whose serialized form can be parsed
+ * by a JAXP DocumentBuilder (because that's what Derby's XMLPARSE
+ * 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.
  */
 short
 	xqReturningClause() throws StandardException :

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java?rev=429847&r1=429846&r2=429847&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java Tue Aug  8 15:06:01 2006
@@ -251,10 +251,7 @@
         XMLDataValue xmlContext, XMLDataValue result)
         throws StandardException
     {
-        // Incremental development (DERBY-688); this is not yet
-        // implemented.
-        throw StandardException.newException(
-            SQLState.NOT_IMPLEMENTED, "XMLQUERY");
+        return xmlContext.XMLQuery(result, getSqlXmlUtil());
     }
 
     /**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?rev=429847&r1=429846&r2=429847&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties Tue Aug  8 15:06:01 2006
@@ -1020,6 +1020,8 @@
 X0X19.S=XML query expression must be a string literal.
 X0X20.S=Multiple XML context items are not allowed.
 X0X21.S=Context item must have type ''XML''; ''{0}'' is not allowed.
+X0X22.S=Values assigned to XML columns must be well-formed DOCUMENT nodes.
+X0X23.S=Invalid context item for {0} operation; context items must be well-formed DOCUMENT nodes.
 X0XML.S=Encountered unexpected error while processing XML; see next exception for details.
 
 X0Y16.S=''{0}'' is not a view.  If it is a table, then use DROP TABLE instead.

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=429847&r1=429846&r2=429847&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Tue Aug  8 15:06:01 2006
@@ -1210,6 +1210,8 @@
 	String LANG_INVALID_XML_QUERY_EXPRESSION                           = "X0X19.S";
 	String LANG_MULTIPLE_XML_CONTEXT_ITEMS                             = "X0X20.S";
 	String LANG_INVALID_CONTEXT_ITEM_TYPE                              = "X0X21.S";
+	String LANG_INVALID_XML_COLUMN_ASSIGN                              = "X0X22.S";
+	String LANG_INVALID_XML_CONTEXT_ITEM                               = "X0X23.S";
 	String LANG_UNEXPECTED_XML_EXCEPTION                               = "X0XML.S";
 
 	// X0Y01 used to be DUPLICATE_KEY_CONSTRAINT

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=429847&r1=429846&r2=429847&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 Tue Aug  8 15:06:01 2006
@@ -162,6 +162,8 @@
 1 row inserted/updated/deleted
 ij> insert into t5 (x1, x2) values (null, xmlparse(document '<notnull/>' preserve whitespace));
 1 row inserted/updated/deleted
+ij> insert into t1 values (7, xmlparse(document '<?xml version="1.0" encoding= "UTF-8"?><umm> decl check </umm>' preserve whitespace));
+1 row inserted/updated/deleted
 ij> update t1 set x = xmlparse(document '<update> document was inserted as part of an UPDATE </update>' preserve whitespace) where i = 1;
 1 row inserted/updated/deleted
 ij> update t1 set x = xmlparse(document '<update2> document was inserted as part of an UPDATE </update2>' preserve whitespace) where xmlexists('/update' passing by ref x);
@@ -175,6 +177,7 @@
 3          
 5          
 6          
+7          
 ij> select i from t1 where xmlparse(document '<hein/>' preserve whitespace) is not null order by i;
 I          
 -----
@@ -184,6 +187,7 @@
 4          
 5          
 6          
+7          
 ij> -- "is [not] null" should work with XML.
 select i from t1 where x is not null;
 I          
@@ -191,6 +195,7 @@
 1          
 5          
 6          
+7          
 ij> select i from t1 where x is null;
 I          
 -----
@@ -238,6 +243,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> select xmlserialize(x1 as clob), xmlserialize(x2 as clob) from t5;
 1 |2                                                                                                                               
 -----
@@ -251,6 +257,7 @@
 NULL                                                                                                
 <hmm/>                                                                                              
 <half> <masted> bass </masted> boosted. </half>                                                     
+<umm> decl check </umm>                                                                             
 ij> select xmlserialize(x as varchar(300)) from t1;
 1                                                                                                                               
 -----
@@ -260,6 +267,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> -- These should succeed at the XMLEXISTS level, but fail with
 ----- parse/truncation errors.
 select xmlserialize(xmlparse(document vc preserve whitespace) as char(10)) from t4;
@@ -310,6 +318,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> values xmlserialize(xmlparse(document '<okay> dokie </okay>' preserve whitespace) as clob);
 1                                                                                                                               
 -----
@@ -320,6 +329,7 @@
 1          
 5          
 6          
+7          
 ij> -- Test XMLEXISTS operator.
 insert into t1 values (7, xmlparse(document '<lets> <try> this out </try> </lets>' preserve whitespace));
 1 row inserted/updated/deleted
@@ -354,6 +364,7 @@
 5          
 6          
 7          
+7          
 ij> select i from t1 where xmlexists('//person' passing by ref x);
 I          
 -----
@@ -370,6 +381,7 @@
 NULL  
 0     
 0     
+0     
 1     
 ij> select xmlexists('//try[text()='' this out '']' passing by ref x) from t1;
 1     
@@ -380,6 +392,7 @@
 NULL  
 0     
 0     
+0     
 1     
 ij> select xmlexists('//let' passing by ref x) from t1;
 1     
@@ -391,6 +404,7 @@
 0     
 0     
 0     
+0     
 ij> select xmlexists('//try[text()='' this in '']' passing by ref x) from t1;
 1     
 -----
@@ -401,6 +415,7 @@
 0     
 0     
 0     
+0     
 ij> select i, xmlexists('//let' passing by ref x) from t1;
 I |2     
 -----
@@ -411,6 +426,7 @@
 5 |0     
 6 |0     
 7 |0     
+7 |0     
 ij> select i, xmlexists('//lets' passing by ref x) from t1;
 I |2     
 -----
@@ -420,6 +436,7 @@
 3 |NULL  
 5 |0     
 6 |0     
+7 |0     
 7 |1     
 ij> values xmlexists('//let' passing by ref xmlparse(document '<lets> try this </lets>' preserve whitespace));
 1     
@@ -552,6 +569,494 @@
 0     
 1     
 0     
+ij> -- Test XMLQUERY operator.
+----- These should fail w/ syntax errors.
+select i, xmlquery('//*') from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 2, column 25.
+ij> select i, xmlquery('//*' passing) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 33.
+ij> select i, xmlquery('//*' passing by ref x) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 42.
+ij> select i, xmlquery('//*' passing by ref x returning sequence) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 61.
+ij> select i, xmlquery(passing by ref x empty on empty) from t1;
+ERROR 42X01: Syntax error: Encountered "by" at line 1, column 28.
+ij> select i, xmlquery(xmlquery('//*' returning sequence empty on empty) as char(75)) from t1;
+ERROR 42X01: Syntax error: Encountered "returning" at line 1, column 35.
+ij> -- These should fail with "not supported" errors.
+select i, xmlquery('//*' passing by ref x returning sequence null on empty) from t1;
+ERROR X0X18: XML feature not supported: 'NULL ON EMPTY'.
+ij> select i, xmlquery('//*' passing by ref x returning content empty on empty) from t1;
+ERROR X0X18: XML feature not supported: 'RETURNING CONTENT'.
+ij> -- This should fail because XMLQUERY returns an XML value which
+----- is not allowed in top-level result set.
+select i, xmlquery('//*' passing by ref x empty on empty) from t1;
+ERROR X0X15: XML values are not allowed in top-level result sets; try using XMLSERIALIZE.
+ij> -- These should fail because context item must be XML.
+select i, xmlquery('//*' passing by ref i empty on empty) from t1;
+ERROR X0X21: Context item must have type 'XML'; 'INTEGER' is not allowed.
+ij> select i, xmlquery('//*' passing by ref 'hello' empty on empty) from t1;
+ERROR X0X21: 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 X0X21: Context item must have type 'XML'; 'CLOB' is not allowed.
+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
+----- an empty sequence, when the xml context is null, and when there
+----- is a sequence with one or more nodes/items in it.  So we just try
+----- out some queries and look at the results.  The selection of queries
+----- is random and is not meant to be exhaustive.
+select i,
+  xmlserialize(
+    xmlquery('2+2' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |4                                                                     
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |4                                                                     
+6 |4                                                                     
+7 |4                                                                     
+7 |4                                                                     
+ij> select i,
+  xmlserialize(
+    xmlquery('./notthere' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('//*' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |<update2> document was inserted as part of an UPDATE </update2>       
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |<hmm/>                                                                
+6 |<half> <masted> bass </masted> boosted. </half><masted> bass </masted>
+7 |<umm> decl check </umm>                                               
+7 |<lets> <try> this out </try> </lets><try> this out </try>             
+ij> select i,
+  xmlserialize(
+    xmlquery('//*[text() = " bass "]' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |<masted> bass </masted>                                               
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('//lets' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |<lets> <try> this out </try> </lets>                                  
+ij> select i,
+  xmlserialize(
+    xmlquery('//text()' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 | document was inserted as part of an UPDATE                           
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |  bass  boosted.                                                      
+7 | decl check                                                           
+7 |  this out                                                            
+ij> select i,
+  xmlserialize(
+    xmlquery('//try[text()='' this out '']' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |<try> this out </try>                                                 
+ij> select i,
+  xmlserialize(
+    xmlquery('//try[text()='' this in '']' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('2+.//try' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |NaN                                                                   
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |NaN                                                                   
+6 |NaN                                                                   
+7 |NaN                                                                   
+7 |NaN                                                                   
+ij> values xmlserialize(
+  xmlquery('//let' passing by ref
+    xmlparse(document '<lets> try this </lets>' preserve whitespace)
+  empty on empty)
+as char(30));
+1                             
+-----
+ij> values xmlserialize(
+  xmlquery('//lets' passing by ref
+    xmlparse(document '<lets> try this </lets>' preserve whitespace)
+  empty on empty)
+as char(30));
+1                             
+-----
+<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).
+insert into t1 values (
+  9,
+  xmlparse(document '<here><is><my height="4.4">attribute</my></is></here>' preserve whitespace)
+);
+1 row inserted/updated/deleted
+ij> insert into t3 values (
+  0,
+  xmlparse(document '<there><goes><my weight="180">attribute</my></goes></there>' preserve whitespace)
+);
+1 row inserted/updated/deleted
+ij> -- Show target tables before insertions.
+select i, xmlserialize(x as char(75)) from t2;
+I |2                                                                          
+-----
+1 |<should> work as planned </should>                                         
+ij> select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+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.
+insert into t2 (i, x) values (
+  20, 
+  (select
+    xmlquery('./notthere' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  21,
+  (select
+    xmlquery('//@*' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  22,
+  (select
+    xmlquery('. + 2' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  23,
+  (select
+    xmlquery('//*' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  24,
+  (select
+    xmlquery('//*[//@*]' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- These should succeed.
+insert into t2 (i, x) values (
+  25,
+  (select
+    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 (
+  26,
+  (select
+    xmlquery('//is' 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 (
+  27,
+  (select
+    xmlquery('/here' 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 (
+  28,
+  (select
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+1 row inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t2;
+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>                                            
+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.
+insert into t3 (i, x) values (
+  29,
+  (select
+    xmlquery('2+2' passing by ref x returning sequence empty on empty)
+    from t1 where i = 100
+  )
+);
+1 row inserted/updated/deleted
+ij> insert into t3 (i, x) values (
+  30,
+  (select
+    xmlquery('.' passing by ref x returning sequence empty on empty)
+    from t1 where i = 100
+  )
+);
+1 row inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+0 |<there><goes><my weight="180">attribute</my></goes></there>                
+29 |NULL                                                                       
+30 |NULL                                                                       
+ij> -- Check updates using XMLQUERY results.  Should only allow results
+----- that constitute a valid DOCUMENT node (i.e. that can be parsed
+----- by the XMLPARSE operator).
+----- These should succeed.
+update t3
+  set x = 
+    xmlquery('.' passing by ref
+      xmlparse(document '<none><here/></none>' preserve whitespace)
+    returning sequence empty on empty)
+where i = 29;
+1 row inserted/updated/deleted
+ij> update t3
+  set x = 
+    xmlquery('//*[@height]' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+1 row inserted/updated/deleted
+ij> -- These should fail because result of XMLQUERY isn't a DOCUMENT.
+update t3
+  set x = xmlquery('.//*' passing by ref x empty on empty)
+where i = 29;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x = xmlquery('./notthere' passing by ref x empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x =
+    xmlquery('//*[@weight]' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x =
+    xmlquery('//*/@height' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- Next two should succeed because there's no row with i = 100
+----- in t3 and thus t3 should remain unchanged after these updates.
+update t3
+  set x = xmlquery('//*' passing by ref x empty on empty)
+where i = 100;
+0 rows inserted/updated/deleted
+ij> update t3
+  set x = xmlquery('4+4' passing by ref x empty on empty)
+where i = 100;
+0 rows inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+0 |<there><goes><my weight="180">attribute</my></goes></there>                
+29 |<none><here/></none>                                                       
+30 |<my height="4.4">attribute</my>                                            
+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.
+----- Should fail because result of inner XMLQUERY op isn't a valid document.
+select i,
+  xmlserialize(
+    xmlquery('//lets/@*' passing by ref
+      xmlquery('/okay/text()' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+ERROR X0Y79: Statement.executeUpdate() cannot be called with a statement that returns a ResultSet.
+ij> select i,
+  xmlserialize(
+    xmlquery('.' passing by ref
+      xmlquery('//lets/@*' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+ERROR X0X23: Invalid context item for XMLQUERY operation; context items must be well-formed DOCUMENT nodes.
+ij> select i,
+  xmlexists('.' passing by ref
+    xmlquery('//lets/@*' passing by ref
+      xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+    empty on empty)
+  )
+from t1 where i > 5;
+ERROR X0X23: Invalid context item for XMLEXISTS operation; context items must be well-formed DOCUMENT nodes.
+ij> -- Should succeed but result is empty sequence.
+select i,
+  xmlserialize(
+    xmlquery('/not' passing by ref
+      xmlquery('//lets' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |                                                                                                    
+7 |                                                                                                    
+7 |                                                                                                    
+9 |                                                                                                    
+ij> -- Should succeed with various results.
+select i,
+  xmlserialize(
+    xmlquery('.' passing by ref
+      xmlquery('//lets' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |<lets boki="inigo"/>                                                                                
+7 |<lets boki="inigo"/>                                                                                
+7 |<lets boki="inigo"/>                                                                                
+9 |<lets boki="inigo"/>                                                                                
+ij> select i,
+  xmlserialize(
+    xmlquery('//@boki' passing by ref
+      xmlquery('/okay' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |inigo                                                                                               
+7 |inigo                                                                                               
+7 |inigo                                                                                               
+9 |inigo                                                                                               
+ij> select i,
+  xmlserialize(
+    xmlquery('/masted/text()' passing by ref
+      xmlquery('//masted' passing by ref x empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i = 6;
+I |2                                                                                                   
+-----
+6 | bass                                                                                               
+ij> select i,
+  xmlexists('/masted/text()' passing by ref
+    xmlquery('//masted' passing by ref x empty on empty)
+  )
+from t1 where i = 6;
+I |2     
+-----
+6 |1     
 ij> -- clean up.
 drop table t0;
 0 rows inserted/updated/deleted

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=429847&r1=429846&r2=429847&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 Tue Aug  8 15:06:01 2006
@@ -162,6 +162,8 @@
 1 row inserted/updated/deleted
 ij> insert into t5 (x1, x2) values (null, xmlparse(document '<notnull/>' preserve whitespace));
 1 row inserted/updated/deleted
+ij> insert into t1 values (7, xmlparse(document '<?xml version="1.0" encoding= "UTF-8"?><umm> decl check </umm>' preserve whitespace));
+1 row inserted/updated/deleted
 ij> update t1 set x = xmlparse(document '<update> document was inserted as part of an UPDATE </update>' preserve whitespace) where i = 1;
 1 row inserted/updated/deleted
 ij> update t1 set x = xmlparse(document '<update2> document was inserted as part of an UPDATE </update2>' preserve whitespace) where xmlexists('/update' passing by ref x);
@@ -175,6 +177,7 @@
 3          
 5          
 6          
+7          
 ij> select i from t1 where xmlparse(document '<hein/>' preserve whitespace) is not null order by i;
 I          
 -----
@@ -184,6 +187,7 @@
 4          
 5          
 6          
+7          
 ij> -- "is [not] null" should work with XML.
 select i from t1 where x is not null;
 I          
@@ -191,6 +195,7 @@
 1          
 5          
 6          
+7          
 ij> select i from t1 where x is null;
 I          
 -----
@@ -238,6 +243,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> select xmlserialize(x1 as clob), xmlserialize(x2 as clob) from t5;
 1 |2                                                                                                                               
 -----
@@ -251,6 +257,7 @@
 NULL                                                                                                
 <hmm/>                                                                                              
 <half> <masted> bass </masted> boosted. </half>                                                     
+<umm> decl check </umm>                                                                             
 ij> select xmlserialize(x as varchar(300)) from t1;
 1                                                                                                                               
 -----
@@ -260,6 +267,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> -- These should succeed at the XMLEXISTS level, but fail with
 ----- parse/truncation errors.
 select xmlserialize(xmlparse(document vc preserve whitespace) as char(10)) from t4;
@@ -310,6 +318,7 @@
 NULL                                                                                                                            
 <hmm/>                                                                                                                          
 <half> <masted> bass </masted> boosted. </half>                                                                                 
+<umm> decl check </umm>                                                                                                         
 ij> values xmlserialize(xmlparse(document '<okay> dokie </okay>' preserve whitespace) as clob);
 1                                                                                                                               
 -----
@@ -320,6 +329,7 @@
 1          
 5          
 6          
+7          
 ij> -- Test XMLEXISTS operator.
 insert into t1 values (7, xmlparse(document '<lets> <try> this out </try> </lets>' preserve whitespace));
 1 row inserted/updated/deleted
@@ -354,6 +364,7 @@
 5          
 6          
 7          
+7          
 ij> select i from t1 where xmlexists('//person' passing by ref x);
 I          
 -----
@@ -370,6 +381,7 @@
 NULL  
 0     
 0     
+0     
 1     
 ij> select xmlexists('//try[text()='' this out '']' passing by ref x) from t1;
 1     
@@ -380,6 +392,7 @@
 NULL  
 0     
 0     
+0     
 1     
 ij> select xmlexists('//let' passing by ref x) from t1;
 1     
@@ -391,6 +404,7 @@
 0     
 0     
 0     
+0     
 ij> select xmlexists('//try[text()='' this in '']' passing by ref x) from t1;
 1     
 -----
@@ -401,6 +415,7 @@
 0     
 0     
 0     
+0     
 ij> select i, xmlexists('//let' passing by ref x) from t1;
 I |2     
 -----
@@ -411,6 +426,7 @@
 5 |0     
 6 |0     
 7 |0     
+7 |0     
 ij> select i, xmlexists('//lets' passing by ref x) from t1;
 I |2     
 -----
@@ -420,6 +436,7 @@
 3 |NULL  
 5 |0     
 6 |0     
+7 |0     
 7 |1     
 ij> values xmlexists('//let' passing by ref xmlparse(document '<lets> try this </lets>' preserve whitespace));
 1     
@@ -552,6 +569,494 @@
 0     
 1     
 0     
+ij> -- Test XMLQUERY operator.
+----- These should fail w/ syntax errors.
+select i, xmlquery('//*') from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 4, column 25.
+ij> select i, xmlquery('//*' passing) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 33.
+ij> select i, xmlquery('//*' passing by ref x) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 42.
+ij> select i, xmlquery('//*' passing by ref x returning sequence) from t1;
+ERROR 42X01: Syntax error: Encountered ")" at line 1, column 61.
+ij> select i, xmlquery(passing by ref x empty on empty) from t1;
+ERROR 42X01: Syntax error: Encountered "by" at line 1, column 28.
+ij> select i, xmlquery(xmlquery('//*' returning sequence empty on empty) as char(75)) from t1;
+ERROR 42X01: Syntax error: Encountered "returning" at line 1, column 35.
+ij> -- These should fail with "not supported" errors.
+select i, xmlquery('//*' passing by ref x returning sequence null on empty) from t1;
+ERROR X0X18: XML feature not supported: 'NULL ON EMPTY'.
+ij> select i, xmlquery('//*' passing by ref x returning content empty on empty) from t1;
+ERROR X0X18: XML feature not supported: 'RETURNING CONTENT'.
+ij> -- This should fail because XMLQUERY returns an XML value which
+----- is not allowed in top-level result set.
+select i, xmlquery('//*' passing by ref x empty on empty) from t1;
+ERROR X0X15: XML values are not allowed in top-level result sets; try using XMLSERIALIZE.
+ij> -- These should fail because context item must be XML.
+select i, xmlquery('//*' passing by ref i empty on empty) from t1;
+ERROR X0X21: Context item must have type 'XML'; 'INTEGER' is not allowed.
+ij> select i, xmlquery('//*' passing by ref 'hello' empty on empty) from t1;
+ERROR X0X21: 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 X0X21: Context item must have type 'XML'; 'CLOB' is not allowed.
+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
+----- an empty sequence, when the xml context is null, and when there
+----- is a sequence with one or more nodes/items in it.  So we just try
+----- out some queries and look at the results.  The selection of queries
+----- is random and is not meant to be exhaustive.
+select i,
+  xmlserialize(
+    xmlquery('2+2' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |4                                                                     
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |4                                                                     
+6 |4                                                                     
+7 |4                                                                     
+7 |4                                                                     
+ij> select i,
+  xmlserialize(
+    xmlquery('./notthere' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('//*' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |<update2> document was inserted as part of an UPDATE </update2>       
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |<hmm/>                                                                
+6 |<half> <masted> bass </masted> boosted. </half><masted> bass </masted>
+7 |<umm> decl check </umm>                                               
+7 |<lets> <try> this out </try> </lets><try> this out </try>             
+ij> select i,
+  xmlserialize(
+    xmlquery('//*[text() = " bass "]' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |<masted> bass </masted>                                               
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('//lets' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |<lets> <try> this out </try> </lets>                                  
+ij> select i,
+  xmlserialize(
+    xmlquery('//text()' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 | document was inserted as part of an UPDATE                           
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |  bass  boosted.                                                      
+7 | decl check                                                           
+7 |  this out                                                            
+ij> select i,
+  xmlserialize(
+    xmlquery('//try[text()='' this out '']' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |<try> this out </try>                                                 
+ij> select i,
+  xmlserialize(
+    xmlquery('//try[text()='' this in '']' passing by ref x empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |                                                                      
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |                                                                      
+6 |                                                                      
+7 |                                                                      
+7 |                                                                      
+ij> select i,
+  xmlserialize(
+    xmlquery('2+.//try' passing by ref x returning sequence empty on empty)
+  as char(70))
+from t1;
+I |2                                                                     
+-----
+1 |NaN                                                                   
+2 |NULL                                                                  
+4 |NULL                                                                  
+3 |NULL                                                                  
+5 |NaN                                                                   
+6 |NaN                                                                   
+7 |NaN                                                                   
+7 |NaN                                                                   
+ij> values xmlserialize(
+  xmlquery('//let' passing by ref
+    xmlparse(document '<lets> try this </lets>' preserve whitespace)
+  empty on empty)
+as char(30));
+1                             
+-----
+ij> values xmlserialize(
+  xmlquery('//lets' passing by ref
+    xmlparse(document '<lets> try this </lets>' preserve whitespace)
+  empty on empty)
+as char(30));
+1                             
+-----
+<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).
+insert into t1 values (
+  9,
+  xmlparse(document '<here><is><my height="4.4">attribute</my></is></here>' preserve whitespace)
+);
+1 row inserted/updated/deleted
+ij> insert into t3 values (
+  0,
+  xmlparse(document '<there><goes><my weight="180">attribute</my></goes></there>' preserve whitespace)
+);
+1 row inserted/updated/deleted
+ij> -- Show target tables before insertions.
+select i, xmlserialize(x as char(75)) from t2;
+I |2                                                                          
+-----
+1 |<should> work as planned </should>                                         
+ij> select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+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.
+insert into t2 (i, x) values (
+  20, 
+  (select
+    xmlquery('./notthere' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  21,
+  (select
+    xmlquery('//@*' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  22,
+  (select
+    xmlquery('. + 2' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  23,
+  (select
+    xmlquery('//*' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> insert into t2 (i, x) values (
+  24,
+  (select
+    xmlquery('//*[//@*]' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- These should succeed.
+insert into t2 (i, x) values (
+  25,
+  (select
+    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 (
+  26,
+  (select
+    xmlquery('//is' 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 (
+  27,
+  (select
+    xmlquery('/here' 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 (
+  28,
+  (select
+    xmlquery('//*[@*]' passing by ref x returning sequence empty on empty)
+    from t1 where i = 9
+  )
+);
+1 row inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t2;
+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>                                            
+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.
+insert into t3 (i, x) values (
+  29,
+  (select
+    xmlquery('2+2' passing by ref x returning sequence empty on empty)
+    from t1 where i = 100
+  )
+);
+1 row inserted/updated/deleted
+ij> insert into t3 (i, x) values (
+  30,
+  (select
+    xmlquery('.' passing by ref x returning sequence empty on empty)
+    from t1 where i = 100
+  )
+);
+1 row inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+0 |<there><goes><my weight="180">attribute</my></goes></there>                
+29 |NULL                                                                       
+30 |NULL                                                                       
+ij> -- Check updates using XMLQUERY results.  Should only allow results
+----- that constitute a valid DOCUMENT node (i.e. that can be parsed
+----- by the XMLPARSE operator).
+----- These should succeed.
+update t3
+  set x = 
+    xmlquery('.' passing by ref
+      xmlparse(document '<none><here/></none>' preserve whitespace)
+    returning sequence empty on empty)
+where i = 29;
+1 row inserted/updated/deleted
+ij> update t3
+  set x = 
+    xmlquery('//*[@height]' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+1 row inserted/updated/deleted
+ij> -- These should fail because result of XMLQUERY isn't a DOCUMENT.
+update t3
+  set x = xmlquery('.//*' passing by ref x empty on empty)
+where i = 29;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x = xmlquery('./notthere' passing by ref x empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x =
+    xmlquery('//*[@weight]' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> update t3
+  set x =
+    xmlquery('//*/@height' passing by ref
+      (select
+        xmlquery('.' passing by ref x empty on empty)
+        from t1
+        where i = 9
+      )
+    empty on empty)
+where i = 30;
+ERROR X0X22: Values assigned to XML columns must be well-formed DOCUMENT nodes.
+ij> -- Next two should succeed because there's no row with i = 100
+----- in t3 and thus t3 should remain unchanged after these updates.
+update t3
+  set x = xmlquery('//*' passing by ref x empty on empty)
+where i = 100;
+0 rows inserted/updated/deleted
+ij> update t3
+  set x = xmlquery('4+4' passing by ref x empty on empty)
+where i = 100;
+0 rows inserted/updated/deleted
+ij> -- Verify results.
+select i, xmlserialize(x as char(75)) from t3;
+I |2                                                                          
+-----
+0 |<there><goes><my weight="180">attribute</my></goes></there>                
+29 |<none><here/></none>                                                       
+30 |<my height="4.4">attribute</my>                                            
+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.
+----- Should fail because result of inner XMLQUERY op isn't a valid document.
+select i,
+  xmlserialize(
+    xmlquery('//lets/@*' passing by ref
+      xmlquery('/okay/text()' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+ERROR X0X23: Invalid context item for XMLQUERY operation; context items must be well-formed DOCUMENT nodes.
+ij> select i,
+  xmlserialize(
+    xmlquery('.' passing by ref
+      xmlquery('//lets/@*' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+ERROR X0X23: Invalid context item for XMLQUERY operation; context items must be well-formed DOCUMENT nodes.
+ij> select i,
+  xmlexists('.' passing by ref
+    xmlquery('//lets/@*' passing by ref
+      xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+    empty on empty)
+  )
+from t1 where i > 5;
+ERROR X0X23: Invalid context item for XMLEXISTS operation; context items must be well-formed DOCUMENT nodes.
+ij> -- Should succeed but result is empty sequence.
+select i,
+  xmlserialize(
+    xmlquery('/not' passing by ref
+      xmlquery('//lets' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |                                                                                                    
+7 |                                                                                                    
+7 |                                                                                                    
+9 |                                                                                                    
+ij> -- Should succeed with various results.
+select i,
+  xmlserialize(
+    xmlquery('.' passing by ref
+      xmlquery('//lets' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |<lets boki="inigo"/>                                                                                
+7 |<lets boki="inigo"/>                                                                                
+7 |<lets boki="inigo"/>                                                                                
+9 |<lets boki="inigo"/>                                                                                
+ij> select i,
+  xmlserialize(
+    xmlquery('//@boki' passing by ref
+      xmlquery('/okay' passing by ref
+        xmlparse(document '<okay><lets boki="inigo"/></okay>' preserve whitespace)
+      empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i > 5;
+I |2                                                                                                   
+-----
+6 |inigo                                                                                               
+7 |inigo                                                                                               
+7 |inigo                                                                                               
+9 |inigo                                                                                               
+ij> select i,
+  xmlserialize(
+    xmlquery('/masted/text()' passing by ref
+      xmlquery('//masted' passing by ref x empty on empty)
+    empty on empty)
+  as char(100))
+from t1 where i = 6;
+I |2                                                                                                   
+-----
+6 | bass                                                                                               
+ij> select i,
+  xmlexists('/masted/text()' passing by ref
+    xmlquery('//masted' passing by ref x empty on empty)
+  )
+from t1 where i = 6;
+I |2     
+-----
+6 |1     
 ij> -- clean up.
 drop table t0;
 0 rows inserted/updated/deleted