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/08 17:53:30 UTC

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

Author: bpendleton
Date: Tue Aug  8 08:53:29 2006
New Revision: 429698

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

This revision contains d688_phase1_v3.patch.

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

Attaching a "phase 1" patch, d688_phase1_v1.patch, for this issue that does the following:

  1. Reorganizes XML-specific code as follows:

    - Moves all code that relies on JAXP and Xalan classes
      out of XML.java and into a new class, SqlXmlUtil.java.
      See comments at the beginning of SqlXmlUtil for an
      explanation of why this was done.

    - Creates a new class, SqlXmlExecutor, in the impl.sql.execute
      package that serves as the class on which all XML operator
      calls are generated. Ex. for XMLEXISTS, instead of
      generating:

         <xmlOperand>.XMLExists(<query-expr>, xmlOperand)

      we now generate:

         <SqlXmlExecutor>.XMLSerialize(<query-expr>, xmlOperand)

      Along with making the code cleaner by allowing all
      XML operator calls to be defined in the same class,
      this new class has other benefits, as well--see
      comments at the beginning of SqlXmlExecutor for
      more of an explanation.

  2. Changes implementation of XPath from XSLT processing to
     the low-level Xalan API, which is faster, more flexible,
     and better for implementation of the XMLQUERY operator
     (the XMLQUERY operator will be coming in subsequent
     phases). Note that as part of this change I've removed
     the dependency on an explicit declaration of Xerces
     as the parser; Derby will now pick up the parser from
     the JVM (i.e. this patch resolves DERBY-567).

  3. Makes a small change to the XMLEXISTS operator to bring
     it more in line with SQL/XML spec. More specifically,
     the query expression that is specified must now be a string
     literal; parameters and other expressions are not allowed.

  4. Updates the XML test and master files (lang/xml_general.sql
     and lang/xmlBinding.java) to bring them in sync with the latest
     Derby codeline. Since the XML tests are not (yet) run
     as part of derbyall, the master files need to be updated
     to reflect some client/server changes that have gone into
     the codeline for 10.2 (for example, server pre-fetching
     behavior).


Added:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java   (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.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/iapi/types/build.xml
    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/UnaryOperatorNode.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/xmlBinding.out
    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/xmlBinding.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/xmlBinding.java
    db/derby/code/trunk/tools/jar/extraDBMSclasses.properties
    db/derby/code/trunk/tools/jar/extraDBMStypes.properties

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java Tue Aug  8 08:53:29 2006
@@ -2767,45 +2767,4 @@
 		this.localeFinder = localeFinder;
 	}
 
-    /*
-     * Implementation of the XMLParse operator.
-     *
-     * NOTE: The XMLParse operator is implemented here (and
-     * defined on the StringDataValue interface) since it is
-     * called with a _String_ operand, not with an XML operand.
-     * That said, though, the bulk of the work is done by
-     * calling the "parseAndLoadXML" method that is defined on
-     * XMLDataValue.
-     * @param result The result of a previous call to this method,
-     *  null if not called yet.
-     * @return An XML value containing the result of XMLParse IF
-     *  the String data in this SQLChar constitutes valid XML.
-     *  Otherwise, an exception is thrown.
-     * @exception StandardException Thrown on error
-     */
-    public XMLDataValue XMLParse(XMLDataValue result, boolean preserveWS)
-        throws StandardException
-    {
-
-        if (result == null)
-        {
-            result = new XML();
-        }
-
-        if (this.isNull())
-        {
-            result.setToNull();
-            return result;
-        }
-
-        // First make sure that the string is valid, well-formed XML.
-        String str = getString();
-        result.parseAndLoadXML(str, preserveWS);
-
-        // If we get here, the character string is valid XML
-		// and was loaded, so we're done.
-        return result;
-
-    }
-
 }

Added: 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=429698&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java Tue Aug  8 08:53:29 2006
@@ -0,0 +1,434 @@
+/*
+
+   Derby - Class org.apache.derby.iapi.types.SqlXmlUtil
+
+   Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.iapi.types;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+import java.util.Properties;
+import java.util.ArrayList;
+
+import java.io.StringReader;
+
+// -- JDBC 3.0 JAXP API classes.
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.TransformerException;
+
+// -- Xalan-specific classes.
+
+import org.apache.xpath.XPath;
+import org.apache.xpath.XPathContext;
+import org.apache.xpath.objects.XObject;
+import org.apache.xpath.objects.XNodeSet;
+
+import org.apache.xalan.serialize.DOMSerializer;
+import org.apache.xalan.serialize.Serializer;
+import org.apache.xalan.serialize.SerializerFactory;
+import org.apache.xalan.templates.OutputProperties;
+
+/**
+ * This class contains "utility" methods that work with XML-specific
+ * objects that are only available if JAXP and/or Xalan are in
+ * the classpath.
+ *
+ * NOTE: This class is only compiled with JDK 1.4 and higher since
+ * the XML-related classes that it uses (JAXP and Xalan) are not
+ * part of earlier JDKs.
+ *
+ * Having a separate class for this functionality is beneficial
+ * for two reasons:
+ *
+ *    1. Allows us to allocate XML objects and compile an XML
+ *       query expression a single time per statement, instead of
+ *       having to do it for every row against which the query
+ *       is evaluated.  An instance of this class is created at
+ *       compile time and then passed (using "saved objects")
+ *       to the appropriate operator implementation method in
+ *       XML.java; see SqlXmlExecutor.java for more about the
+ *       role this class plays in "saved object" processing.
+ *
+ *    2. By keeping all XML-specific references in this one class, 
+ *       we have a single "point of entry" to the XML objects--namely,
+ *       the constructor for this class.  Thus, if we always make
+ *       sure to check for the required XML classes _before_ calling
+ *       this class's constructor, we can detect early on whether
+ *       some classes (ex. Xalan) are missing, and can throw a friendly
+ *       error up front, instead of a ClassNotFoundException somewhere
+ *       deeper in the execution codepath.
+ *
+ *       Note that we don't want to put references to XML-specific
+ *       objects directly into XML.java because that class (XML.java) is
+ *       instantiated anytime a table with an XML column is referenced.
+ *       That would mean that if a user tried to select a non-XML column
+ *       (ex. integer) from a table that had at least one XML column in
+ *       it, the user would have to have JAXP and Xalan classes in
+ *       his/her classpath--which we don't want.  Instead, by keeping
+ *       all XML-specific objects in this one class, and then only
+ *       instantiating this class when an XML operator is used (either
+ *       implicitly or explicitly), we make it so that the user is only
+ *       required to have XML-specific classes in his/her classpath
+ *       _if_ s/he is trying to access or operate on XML values.
+ */
+
+public class SqlXmlUtil 
+{
+    // Used to parse a string into an XML value (DOM); checks
+    // the well-formedness of the string while parsing.
+    private DocumentBuilder dBuilder;
+
+    // Used to serialize an XML value according the standard
+    // XML serialization rules.
+    private Serializer serializer;
+
+    // Classes used to compile and execute an XPath expression
+    // against Xalan.
+    private XPath query;
+    private XPathContext xpContext;
+
+    /**
+     * Constructor: Initializes objects required for parsing
+     * and serializing XML values.  Since most XML operations
+     * that require XML-specific classes perform both parsing
+     * and serialization at some point, we just initialize the
+     * objects up front.
+     */
+    public SqlXmlUtil() throws StandardException
+    {
+        try {
+
+            /* Note: Use of DocumentBuilderFactory means that we get
+             * whatever XML parser is the "default" for the JVM in
+             * use--and thus, we don't have to hard-code the parser
+             * name, nor do we have to require that the user have a
+             * specific parser in his/her classpath.
+             *
+             * This DocumentBuilder is currently used for parsing
+             * (esp. XMLPARSE), and the SQL/XML spec says that XMLPARSE
+             * should NOT perform validation (SQL/XML[2006], 6.15:
+             * "Perform a non-validating parse of a string to produce
+             * an XML value.").   So we disable validation here, and
+             * we also make the parser namespace aware.
+             *
+             * At some point in the future we will probably want to add
+             * support for the XMLVALIDATE function--but until then, user
+             * is unable to validate the XML values s/he inserts.
+             *
+             * Note that, even with validation turned off, XMLPARSE
+             * _will_ still check the well-formedness of the values,
+             * and it _will_ still process DTDs to get default values,
+             * etc--but that's it; no validation errors will be thrown.
+             */
+
+            DocumentBuilderFactory dBF = DocumentBuilderFactory.newInstance();
+            dBF.setValidating(false);
+            dBF.setNamespaceAware(true);
+
+            // Load document builder that can be used for parsing XML.
+            dBuilder = dBF.newDocumentBuilder();
+            dBuilder.setErrorHandler(new XMLErrorHandler());
+
+            // Load serializer for serializing XML into string according
+            // XML serialization rules.
+            loadSerializer();
+
+        } catch (Exception e) {
+
+            // Must be something caused by JAXP or Xalan; wrap it in a
+            // StandardException and rethrow it.
+            throw StandardException.newException(
+                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, e);
+
+        }
+
+        // At construction time we don't have an XML query expression
+        // to compile.  If one is required, we'll load/compile it later.
+        query = null;
+    }
+
+    /**
+     * Take the received string, which is an XML query expression,
+     * compile it, and store the compiled query locally.  Note
+     * that for now, we only support XPath because that's what
+     * Xalan supports.
+     *
+     * @param queryExpr The XPath expression to compile
+     */
+    public void compileXQExpr(String queryExpr)
+        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.
+            throw StandardException.newException(
+                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, te);
+
+        }
+    }
+
+    /**
+     * Take a string representing an XML value and serialize it
+     * according SQL/XML serialization rules.  Right now, we perform
+     * this serialization by first parsing the string into a JAXP
+     * Document object, and then applying the serialization semantics
+     * to that Document.  That seems a bit inefficient, but neither
+     * Xalan nor JAXP provides a more direct way to do this.
+     *
+     * @param xmlAsText String version of XML on which to perform
+     *   serialization.
+     * @return A properly serialized version of xmlAsText.
+     */
+    protected String serializeToString(String xmlAsText)
+        throws Exception
+    {
+        ArrayList aList = new ArrayList();
+        aList.add(dBuilder.parse(
+            new InputSource(new StringReader(xmlAsText))));
+        return serializeToString(aList);
+    }
+
+    /**
+     * Take an array list (sequence) of XML nodes and/or string values
+     * and serialize that entire list according to SQL/XML serialization
+     * rules.  We do that by going through each item in the array
+     * list and either serializing it (if it's a Node) or else
+     * just echoing the value to the serializer (if it's a Text
+     * node or an atomic value).
+     *
+     * @param items List of items to serialize
+     * @return Single string holding the concatenation of the serialized
+     *  form of all items in the list
+     */
+    protected String serializeToString(ArrayList items)
+        throws java.io.IOException
+    {
+        if ((items == null) || (items.size() == 0))
+        // nothing to do; return empty sequence.
+            return "";
+
+        java.io.StringWriter sWriter = new java.io.StringWriter();
+
+        // Serializer should have been set by now.
+        if (SanityManager.DEBUG)
+        {
+            SanityManager.ASSERT(serializer != null,
+                "Tried to serialize with uninitialized XML serializer.");
+        }
+
+        serializer.setWriter(sWriter);
+        DOMSerializer dSer = serializer.asDOMSerializer();
+
+        int sz = items.size();
+        Object obj = null;
+
+        // Iterate through the list and serialize each item.
+        for (int i = 0; i < sz; i++)
+        {
+            obj = items.get(i);
+            if (obj instanceof String)
+            // if it's a string, then this corresponds to some atomic
+            // value, so just echo the string as it is.
+                sWriter.write((String)obj);
+            else
+            { // We have a Node, so try to serialize it.
+                Node n = (Node)obj;
+                if (n instanceof Text)
+                // Xalan doesn't allow a "serialize" call on Text nodes,
+                // so we just go ahead and echo the value of the text.
+                    sWriter.write(n.getNodeValue());
+                else
+                    dSer.serialize(n);
+            }
+        }
+
+        sWriter.flush();
+        return sWriter.toString();
+    }
+
+    /**
+     * 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.
+     *
+     * 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.
+     * @exception Exception thrown on error (and turned into a
+     *  StandardException by the caller).
+     */
+    protected boolean evalXQExpression(XMLDataValue xmlContext)
+        throws Exception
+    {
+        // Make sure we have a compiled query.
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(
+                (query != null) && (query.getExpression() != null),
+                "Failed to locate compiled XML query expression.");
+        }
+
+        // Create a DOM node from the xmlContext, since that's how
+        // we feed the context to Xalan.
+        Document docNode = null;
+        docNode = dBuilder.parse(
+            new InputSource(
+                new StringReader(xmlContext.getString())));
+
+        // Evaluate the expresion using Xalan.
+        getXPathContext();
+        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;
+        }
+        else if (!(xOb instanceof XNodeSet))
+        // we have a single atomic value, which means the result is
+        // non-empty.
+            return true;
+
+        // Else the result was an empty sequence.
+        return false;
+    }
+
+    /* ****
+     * Helper classes and methods.
+     * */
+
+    /**
+     * Create and return an instance of Xalan's XPathContext
+     * that can be used to compile an XPath expression.
+     */
+    private XPathContext getXPathContext()
+    {
+        if (xpContext == null)
+            xpContext = new XPathContext();
+
+        return xpContext;
+    }
+
+    /**
+     * Create an instance of Xalan serializer for the sake of
+     * serializing an XML value according the SQL/XML specification
+     * for serialization.
+     */
+    private void loadSerializer() throws java.io.IOException
+    {
+        java.io.StringWriter sWriter = new java.io.StringWriter();
+
+        // Set serialization properties.
+        Properties props = OutputProperties.getDefaultMethodProperties("xml");
+
+        // SQL/XML[2006] 10.15:General Rules:6 says method is "xml".
+        props.setProperty(OutputKeys.METHOD, "xml");
+
+        /* Since the XMLSERIALIZE operator doesn't currently support
+         * the DOCUMENT nor CONTENT keywords, SQL/XML spec says that
+         * the default is CONTENT (6.7:Syntax Rules:2.a).  Further,
+         * since the XMLSERIALIZE operator doesn't currently support the
+         * <XML declaration option> syntax, the SQL/XML spec says
+         * that the default for that option is "Unknown" (6.7:General
+         * Rules:2.f).  Put those together and that in turn means that
+         * the value of "OMIT XML DECLARATION" must be "Yes", as
+         * stated in section 10.15:General Rules:8.c.  SO, that's what
+         * we set here.
+         *
+         * NOTE: currently the only way to view the contents of an
+         * XML column is by using an explicit XMLSERIALIZE operator.
+         * This means that if an XML document is stored and it
+         * begins with an XML declaration, the user will never be
+         * able to _see_ that declaration after inserting the doc
+         * because, as explained above, our current support for
+         * XMLSERIALIZE dictates that the declaration must be
+         * omitted.  Similarly, other transformations that may
+         * occur from serialization (ex. entity replacement,
+         * attribute order, single-to-double quotes, etc)) will
+         * always be in effect for the string returned to the user;
+         * the original form of the XML document, if different
+         * from the serialized version, is not currently retrievable.
+         */
+        props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+
+        // We serialize everything as UTF-8 to match what we
+        // store on disk.
+        props.setProperty(OutputKeys.ENCODING, "UTF-8");
+
+        // Load the serializer with the correct properties.
+        serializer = SerializerFactory.getSerializer(props);
+        return;
+    }
+
+    /*
+     ** The XMLErrorHandler class is just a generic implementation
+     ** of the ErrorHandler interface.  It allows us to catch
+     ** and process XML parsing errors in a graceful manner.
+     */
+    private class XMLErrorHandler implements ErrorHandler
+    {
+        public void error (SAXParseException exception)
+            throws SAXException
+        {
+            throw new SAXException (exception);
+        }
+
+        public void fatalError (SAXParseException exception)
+            throws SAXException
+        {
+            throw new SAXException (exception);
+        }
+
+        public void warning (SAXParseException exception)
+            throws SAXException
+        {
+            throw new SAXException (exception);
+        }
+    }
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/StringDataValue.java Tue Aug  8 08:53:29 2006
@@ -147,23 +147,4 @@
 	 */
 	public char[] getCharArray() throws StandardException;
 
-    /*
-     * Get an XML value from a string.
-     *
-     * NOTE: The XMLParse operator is defined here since it
-     * is called with a _String_ operand, not with an XML
-     * operand.  That said, though, the bulk of the work is
-     * is done by a corresponding method that is defined
-     * on the XMLDataValue interface (implementations
-     * of this method should just call the XMLDataValue
-     * method, passing in the correct String data).
-     *
-     * @param result The result (reusable - allocate if null).
-     * @return An XML value corresponding to the string, if
-     *  the string is valid XML.
-     * @exception StandardException Thrown on error
-     */
-    public XMLDataValue XMLParse(XMLDataValue result, boolean preserveWS)
-        throws StandardException;
-
 }

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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -46,28 +46,6 @@
 import java.io.ObjectInput;
 import java.io.StringReader;
 
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.XMLReader;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.InputSource;
-
-import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
-
-import javax.xml.transform.Templates;
-import javax.xml.transform.TransformerFactory;
-
-import javax.xml.transform.sax.SAXResult;
-import javax.xml.transform.sax.TemplatesHandler;
-import javax.xml.transform.sax.TransformerHandler;
-
-// Note that even though the following has a Xalan
-// package name, it IS part of the JDK 1.4 API, and
-// thus we can compile it without having Xalan in
-// our classpath.
-import org.apache.xalan.processor.TransformerFactoryImpl;
-
 /**
  * This type implements the XMLDataValue interface and thus is
  * the type on which all XML related operations are executed.
@@ -94,18 +72,6 @@
     // across all XML type implementations.
     protected static final short UTF8_IMPL_ID = 0;
 
-    // Parser class to use for parsing XML.  We use the
-    // Xerces parser, so (for now) we require that Xerces
-    // be in the user's classpath.  Note that we load
-    // the Xerces class dynamically (using the class 
-    // name) so that Derby will build even if Xerces
-    // isn't in the build environment; i.e. Xerces is
-    // only required if XML is actually going to be used
-    // at runtime; it's not required for a successful
-    // build nor for non-XML database use.
-    protected static final String XML_PARSER_CLASS =
-        "org.apache.xerces.parsers.SAXParser";
-
     // Guess at how much memory this type will take.
     private static final int BASE_MEMORY_USAGE =
         ClassSize.estimateBaseFromCatalog(XML.class);
@@ -119,16 +85,17 @@
     // Derby string types.
     private SQLChar xmlStringValue;
 
-    // An XML reader for reading and parsing SAX events.
-    protected XMLReader saxReader;
-
-    // XSLT objects used when performing an XSLT query, which
-    // is the query mechanism for this UTF8-based implementation.
-    private static final String XPATH_PLACEHOLDER = "XPATH_PLACEHOLDER";
-    private static final String QUERY_MATCH_STRING = "MATCH";
-    private static String xsltStylesheet;
-    private XMLReader xsltReader;
-    private TransformerFactoryImpl saxTFactory;
+    /**
+      Loaded at execution time, this holds XML-related objects
+      that were created once during compilation but can be re-used
+      for each row in the target result set for the current
+      SQL statement.  In other words, we create the objects
+      once per SQL statement, instead of once per row.  In the
+      case of XMLEXISTS, one of the "objects" is the compiled
+      query expression, which means we don't have to compile
+      the expression for each row and thus we save some time.
+     */
+    private SqlXmlUtil sqlxUtil;
 
     /**
      * Default constructor.
@@ -430,26 +397,32 @@
 
     /**
      * Method to parse an XML string and, if it's valid,
-     * store the _parsed_ version for subsequent use.
-	 * If 'text' constitutes a valid XML document,
-     *  it has been stored in this XML value and nothing
-     *  is returned; otherwise, an exception is thrown.
+     * store the _serialized_ version locally and then return
+     * this XMLDataValue.
+     *
      * @param text The string value to check.
      * @param preserveWS Whether or not to preserve
      *  ignorable whitespace.
-     * @exception StandardException Thrown on parse error.
+     * @param sqlxUtil Contains SQL/XML objects and util
+     *  methods that facilitate execution of XML-related
+     *  operations
+     * @return If 'text' constitutes a valid XML document,
+     *  it has been stored in this XML value and this XML
+     *  value is returned; otherwise, an exception is thrown. 
+     * @exception StandardException Thrown on error.
      */
-    public void parseAndLoadXML(String text, boolean preserveWS)
-        throws StandardException
+    public XMLDataValue XMLParse(String text, boolean preserveWS,
+        SqlXmlUtil sqlxUtil) throws StandardException
     {
         try {
 
             if (preserveWS) {
-            // We're just going to use the text exactly as it
-            // is, so we just need to see if it parses. 
-                loadSAXReader();
-                saxReader.parse(
-                    new InputSource(new StringReader(text)));
+            // Currently the only way a user can view the contents of
+            // an XML value is by explicitly calling XMLSERIALIZE.
+            // So do a serialization now and just store the result,
+            // so that we don't have to re-serialize every time a
+            // call is made to XMLSERIALIZE.
+                text = sqlxUtil.serializeToString(text);
             }
             else {
             // We don't support this yet, so we shouldn't
@@ -460,7 +433,7 @@
             }
 
         } catch (Exception xe) {
-        // The text isn't a valid XML document.  Throw a StandardException
+        // Couldn't parse the XML document.  Throw a StandardException
         // with the parse exception nested in it.
             throw StandardException.newException(
                 SQLState.LANG_NOT_AN_XML_DOCUMENT, xe);
@@ -471,15 +444,17 @@
         if (xmlStringValue == null)
             xmlStringValue = new SQLChar();
         xmlStringValue.setValue(text);
-        return;
+        return this;
     }
 
     /**
      * The SQL/XML XMLSerialize operator.
-     * Converts this XML value into a string with a user-specified
-     * type, and returns that string via the received StringDataValue
-     * (if the received StringDataValue is non-null; else a new
-     * StringDataValue is returned).
+     * Serializes this XML value into a string with a user-specified
+     * character type, and returns that string via the received
+     * StringDataValue (if the received StringDataValue is non-null
+     * and of the correct type; else, a new StringDataValue is
+     * returned).
+     *
      * @param result The result of a previous call to this method,
      *    null if not called yet.
      * @param targetType The string type to which we want to serialize.
@@ -505,7 +480,7 @@
                     if (SanityManager.DEBUG) {
                         SanityManager.THROWASSERT(
                             "Should NOT have made it to XMLSerialize " +
-                            "with a non-string target type.");
+                            "with a non-string target type: " + targetType);
                     }
                     return null;
             }
@@ -526,8 +501,9 @@
         }
 
         // Get the XML value as a string.  For this UTF-8 impl,
-        // we already have it as a string, so just use that.
-        result.setValue(xmlStringValue.getString());
+        // we already have it as a UTF-8 string, so just use
+        // that.
+        result.setValue(getString());
 
         // Seems wrong to trunc an XML document, as it then becomes non-
         // well-formed and thus useless.  So we throw an error (that's
@@ -538,325 +514,53 @@
 
     /**
      * The SQL/XML XMLExists operator.
-     * Takes an XML query expression (as a string) and an XML
-     * value and checks if at least one node in the XML
-     * value matches the query expression.  NOTE: For now,
-     * the query expression must be XPath only (XQuery not
-     * supported).
-     * @param xExpr The query expression, as a string.
-     * @param xml The XML value being queried.
-     * @return True if the received query expression matches at
-     *  least one node in the received XML value; unknown if
-     *  either the query expression or the xml value is null;
-     *  false otherwise.
+     * Checks to see if evaluation of the query expression contained
+     * within the received util object against this XML value returns
+     * at least one item. NOTE: For now, the query expression must be
+     * XPath only (XQuery not supported) because that's what Xalan
+     * supports.
+     *
+     * @param sqlxUtil Contains SQL/XML objects and util
+     *  methods that facilitate execution of XML-related
+     *  operations
+     * @return True if evaluation of the query expression stored
+     *  in sqlxUtil returns at least one node for this XML value;
+     *  unknown if the xml value is NULL; false otherwise.
      * @exception StandardException Thrown on error
      */
-    public BooleanDataValue XMLExists(StringDataValue xExpr,
-        XMLDataValue xml) throws StandardException
+    public BooleanDataValue XMLExists(SqlXmlUtil sqlxUtil)
+        throws StandardException
     {
-        if ((xExpr == null) || xExpr.isNull())
-        // If the query is null, we assume unknown.
-            return SQLBoolean.unknownTruthValue();
-
-        if ((xml == null) || xml.isNull())
-        // Then per SQL/XML spec 8.4, we return UNKNOWN.
+        if (this.isNull()) {
+        // if the user specified a context node and that context
+        // is null, result of evaluating the query is null
+        // (per SQL/XML 6.17:General Rules:1.a), which means that we
+        // return "unknown" here (per SQL/XML 8.4:General Rules:2.a).
             return SQLBoolean.unknownTruthValue();
-
-        return new SQLBoolean(xml.exists(xExpr.getString()));
-    }
-
-    /**
-     * Helper method for XMLExists.
-     * See if the received XPath expression returns at least
-     * one node when evaluated against _this_ XML value.
-     * @param xExpr The XPath expression.
-     * @return True if at least one node in this XML value
-     *  matches the received xExpr; false otherwise.
-     */
-    public boolean exists(String xExpr) throws StandardException
-    {
-        // NOTE: At some point we'll probably need to implement some
-        // some kind of query cache so that we don't have to recompile
-        // the same query over and over for every single XML row
-        // in a table.  That's what we do right now...
-
-        try {
-
-            xExpr = replaceDoubleQuotes(xExpr);
-            loadXSLTObjects();
-
-            // Take our simple stylesheet and plug in the query.
-            int pos = xsltStylesheet.indexOf(XPATH_PLACEHOLDER);
-            StringBuffer stylesheet = new StringBuffer(xsltStylesheet);
-            stylesheet.replace(pos, pos + XPATH_PLACEHOLDER.length(), xExpr);
-
-            // Create a Templates ContentHandler to handle parsing of the 
-            // stylesheet.
-            TemplatesHandler templatesHandler = 
-                saxTFactory.newTemplatesHandler();
-            xsltReader.setContentHandler(templatesHandler);
-    
-            // Now parse the generic stylesheet we created.
-            xsltReader.parse(
-                new InputSource(new StringReader(stylesheet.toString())));
-
-            // Get the Templates object (generated during the parsing of
-            // the stylesheet) from the TemplatesHandler.
-            Templates compiledQuery = templatesHandler.getTemplates();
-
-            // Create a Transformer ContentHandler to handle parsing of 
-            // the XML Source.  
-            TransformerHandler transformerHandler 
-                = saxTFactory.newTransformerHandler(compiledQuery);
-
-            // Reset the XMLReader's ContentHandler to the TransformerHandler.
-            xsltReader.setContentHandler(transformerHandler);
-
-            // Create an ExistsHandler.  When the XSLT transformation
-            // occurs, a period (".") will be thrown to this handler
-            // (via a SAX 'characters' event) for every matching
-            // node that XSLT finds.  This is how we know if a
-            // match was found.
-            ExistsHandler eH = new ExistsHandler();
-            transformerHandler.setResult(new SAXResult(eH));
-
-            // This call to "parse" is what does the query, because we
-            // passed in an XSLT handler with the compiled query above.
-            try {
-                xsltReader.parse(
-                    new InputSource(new StringReader(getString())));
-            } catch (Throwable th) {
-                if (th.getMessage().indexOf(
-                    "SAXException: " + QUERY_MATCH_STRING) == -1)
-                { // then this isn't the exception that means we have
-                  // a match; so re-throw it.
-                    throw new Exception(th.getMessage());
-                }
-            }
-
-            // Did we have any matches?
-            return eH.exists();
-
-        } catch (Exception xe) {
-        // We don't expect to get here.  Turn it into a
-        // StandardException, then throw it.
-            throw StandardException.newException(
-                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, xe);
-        }
-    }
-
-    /* ****
-     * Helper classes and methods.
-     * */
-
-    /**
-     * Load an XMLReader for SAX events that can be used
-     * for parsing XML data.
-     *
-     * This method is currently only used for XMLPARSE, and
-     * the SQL/XML[2003] spec says that XMLPARSE should NOT
-     * perform validation -- Seciont 6.11:
-     *
-     *    "Perform a non-validating parse of a character string to
-     *    produce an XML value."
-     *
-     * Thus, we make sure to disable validation on the XMLReader
-     * loaded here.  At some point in the future we will probably
-     * want to add support for the XMLVALIDATE function--but until
-     * then, user is unable to validate the XML values s/he inserts.
-     *
-     * Note that, even with validation turned off, XMLPARSE
-     * _will_ still check the well-formedness of the values,
-     * and it _will_ still process DTDs to get default values,
-     * etc--but that's it; no validation errors will be thrown.
-     *
-     * For future reference: the features needed to perform
-     * validation (with Xerces) are:
-     *
-     * http://apache.org/xml/features/validation/schema
-     * http://apache.org/xml/features/validation/dynamic
-     */
-    protected void loadSAXReader() throws Exception
-    {
-        if (saxReader != null)
-        // already loaded.
-            return;
-
-        // Get an instance of an XMLReader.
-        saxReader = XMLReaderFactory.createXMLReader(XML_PARSER_CLASS);
-
-        // Turn off validation, since it's not allowed by
-        // SQL/XML[2003] spec.
-        saxReader.setFeature(
-            "http://xml.org/sax/features/validation", false);
-
-        // Make the parser namespace aware.
-        saxReader.setFeature(
-            "http://xml.org/sax/features/namespaces", true);
-
-        // We have to set the error handler in order to properly
-        // receive the parse errors.
-        saxReader.setErrorHandler(new XMLErrorHandler());
-    }
-
-    /**
-     * Prepare for an XSLT query by loading the objects
-     * required for such a query.  We should only have
-     * to do this once per XML object.
-     */
-    private void loadXSLTObjects() throws SAXException
-    {
-        if (xsltReader != null)
-        // we already loaded everything.
-            return;
-
-        // Instantiate a TransformerFactory.
-        TransformerFactory tFactory = TransformerFactory.newInstance();
-
-        // Cast the TransformerFactory to SAXTransformerFactory.
-        saxTFactory = (TransformerFactoryImpl)tFactory;
-
-        // Get an XML reader.
-        xsltReader = XMLReaderFactory.createXMLReader(XML_PARSER_CLASS);
-
-        // Make the parser namespace aware.  Note that because we
-        // only support a small subset of SQL/XML, and because we
-        // only allow XPath (as opposed to XQuery) expressions,
-        // there is no way for a user to specify namespace
-        // bindings as part of the XMLEXISTS operator.  This means
-        // that in order to query for a node name, the user must
-        // use the XPath functions "name()" and "local-name()"
-        // in conjunction with XPath 1.0 'namespace' axis.  For
-        // example:
-        //
-        // To see if any elements exist that have a specific name
-        // with ANY namespace:
-        //     //child::*[local-name()="someName"]
-        //
-        // To see if any elements exist that have a specific name
-        // with NO namespace:
-        //     //child::*[name()="someName"]
-        //
-        // To see if any elements exist that have a specific name
-        // in a specific namespace:
-        //     //child::*[local-name()=''someName'' and
-        //        namespace::*[string()=''http://www.some.namespace'']]
-        //
-        xsltReader.setFeature(
-            "http://xml.org/sax/features/namespaces", true);
-
-        // Create a very simple XSLT stylesheet.  This stylesheet
-        // will execute the XPath expression and, for every match,
-        // write a period (".") to the ExistsHandler (see the exists()
-        // method above).  Then, in order to see if at least one
-        // node matches, we just check to see if the ExistsHandler
-        // caught at least one 'characters' event.  If it did, then
-        // we know we had a match.
-        if (xsltStylesheet == null) {
-            StringBuffer sb = new StringBuffer();
-            sb.append("<xsl:stylesheet version=\"1.0\"\n");
-            sb.append("xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n");
-            sb.append(" <xsl:template match=\"/\">\n"); // Search whole doc...
-            sb.append("  <xsl:for-each select=\"");     // For every match...
-            sb.append(XPATH_PLACEHOLDER);               // using XPath expr...
-            sb.append("\">.</xsl:for-each>\n");         // Write a "."
-            sb.append(" </xsl:template>\n");
-            sb.append("</xsl:stylesheet>\n");
-            xsltStylesheet = sb.toString();
         }
-    }
 
-    /**
-     * Takes a string (which is an XPath query specified by
-     * the user) and replaces any double quotes with single
-     * quotes.  We have to do this because a double quote
-     * in the XSLT stylesheet (which is where the user's
-     * query ends up) will be parsed as a query terminator
-     * thus will cause XSLT execution errors.
-     * @param queryText Text in which we want to replace double
-     *  quotes.
-     * @return queryText with all double quotes replaced by
-     *  single quotes.
-     */
-    private String replaceDoubleQuotes(String queryText)
-    {
-        int pos = queryText.indexOf("\"");
-        if (pos == -1)
-        // nothing to do.
-            return queryText;
-
-        StringBuffer sBuf = new StringBuffer(queryText);
-        while (pos >= 0) {
-            sBuf.replace(pos, pos+1, "'");
-            pos = queryText.indexOf("\"", pos+1);
+        // Make sure we have a compiled query (and associated XML
+        // objects) to evaluate.
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(
+                sqlxUtil != null,
+                "Tried to evaluate XML xquery, but no XML objects were loaded.");
         }
-        return sBuf.toString();
-    }
 
-    /*
-     ** The XMLErrorHandler class is just a generic implementation
-     ** of the ErrorHandler interface.  It allows us to catch
-     ** and process XML parsing errors in a graceful manner.
-     */
-    private class XMLErrorHandler implements ErrorHandler
-    {
-        public void error (SAXParseException exception)
-            throws SAXException
-        {
-            throw new SAXException (exception);
-        }
+        try {
 
-        public void fatalError (SAXParseException exception)
-            throws SAXException
-        {
-            throw new SAXException (exception);
-        }
+            return new SQLBoolean(sqlxUtil.evalXQExpression(this));
 
-        public void warning (SAXParseException exception)
-            throws SAXException
-        {
-            throw new SAXException (exception);
+        } catch (Exception xe) {
+        // We don't expect to get here.  Turn it into a StandardException
+        // (if needed), then throw it.
+            if (xe instanceof StandardException)
+                throw (StandardException)xe;
+            else {
+                throw StandardException.newException(
+                    SQLState.LANG_UNEXPECTED_XML_EXCEPTION, xe);
+            }
         }
     }
 
-    /*
-     ** The ExistsHandler is what we pass to the XSLT processor
-     ** when we query.  The generic xsltStylesheet that we defined
-     ** above will throw a 'characters' event for every matching
-     ** node that is found by the XSLT transformation.  This
-     ** handler is the one that catches the event, and thus
-     ** it tells us whether or not we had a match.
-     */
-    private class ExistsHandler extends DefaultHandler
-    {
-        // Did we catch at least one 'characters' event?
-        private boolean atLeastOneMatch;
-
-        public ExistsHandler() {
-            atLeastOneMatch = false;
-        }
-
-        /*
-         * Catch a SAX 'characters' event, which tells us that
-         * we had at least one matching node.
-         */
-        public void characters(char[] ch, int start, int length)
-            throws SAXException
-        {
-            // If we get here, we had at least one matching node.
-            // Since that's all we need to know, we don't have
-            // to continue querying--we can stop the XSLT
-            // transformation now by throwing a SAX exception.
-            atLeastOneMatch = true;
-            throw new SAXException(QUERY_MATCH_STRING);
-        }
-
-        /*
-         * Tell whether or not this handler caught a match.
-         */
-        public boolean exists()
-        {
-            return atLeastOneMatch;
-        }
-    }
 }

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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -24,43 +24,32 @@
 
 public interface XMLDataValue extends DataValueDescriptor
 {
-    /*
-     ** NOTE: Officially speaking, the XMLParse operator
-     ** is not defined here; it is instead defined on the
-     ** StringDataValue interface (and implemented in
-     ** SQLChar.java) since it is called with a _String_
-     ** operand, not with an XML operand.  That said,
-     ** though, the implemention in SQLChar.java
-     ** really just calls the "parseAndLoadXML" method that's
-     ** defined on this interface, so it's this interface
-     ** that really does the work.
-     **
-     ** XMLSerialize and XMLExists, on the other hand,
-     ** are called with XML operands, and thus they
-     ** can just be defined in this interface.
-     */
-
-    /**
-     * Parse the received string value as XML.  If the
-     * parse succeeds, store the string value as the
-     * contents of this XML value. If 'text' constitutes a valid XML document,
-     *  it has been stored in this XML value and nothing
-     *  is returned; otherwise, an exception is thrown.
+   /**
+     * Method to parse an XML string and, if it's valid,
+     * store the _serialized_ version locally and then return
+     * this XMLDataValue.
      *
-     * @param xmlText The string value to check.
+     * @param text The string value to check.
      * @param preserveWS Whether or not to preserve
      *  ignorable whitespace.
-     * @exception StandardException Thrown on parse error.
+     * @param sqlxUtil Contains SQL/XML objects and util
+     *  methods that facilitate execution of XML-related
+     *  operations
+     * @return If 'text' constitutes a valid XML document,
+     *  it has been stored in this XML value and this XML
+     *  value returned; otherwise, an exception is thrown. 
+     * @exception StandardException Thrown on error.
      */
-    public void parseAndLoadXML(String xmlText, boolean preserveWS)
-        throws StandardException;
+	public XMLDataValue XMLParse(String text, boolean preserveWS,
+		SqlXmlUtil sqlxUtil) throws StandardException;
 
     /**
      * The SQL/XML XMLSerialize operator.
-     * Converts this XML value into a string with a user-specified
-     * type, and returns that string via the received StringDataValue.
-     * (if the received StringDataValue is non-null and of the
-     * correct type; else, a new StringDataValue is returned).
+     * Serializes this XML value into a string with a user-specified
+     * character type, and returns that string via the received
+     * StringDataValue (if the received StringDataValue is non-null
+     * and of the correct type; else, a new StringDataValue is
+     * returned).
      *
      * @param result The result of a previous call to this method,
      *  null if not called yet.
@@ -75,31 +64,21 @@
 
     /**
      * The SQL/XML XMLExists operator.
-     * Takes an XML query expression (as a string) and an XML
-     * value and checks if at least one node in the XML
-     * value matches the query expression.  NOTE: For now,
-     * the query expression must be XPath only (XQuery not
-     * supported).
+     * Checks to see if evaluation of the query expression contained
+     * within the received util object against this XML value returns
+     * at least one item. NOTE: For now, the query expression must be
+     * XPath only (XQuery not supported) because that's what Xalan
+     * supports.
      *
-     * @param xExpr The query expression, as a string.
-     * @param xml The XML value being queried.
-     * @return True if the received query expression matches at
-     *  least one node in the received XML value; unknown if
-     *  either the query expression or the xml value is null;
-     *  false otherwise.
+     * @param sqlxUtil Contains SQL/XML objects and util
+     *  methods that facilitate execution of XML-related
+     *  operations
+     * @return True if evaluation of the query expression stored
+     *  in sqlxUtil returns at least one node for this XML value;
+     *  unknown if the xml value is NULL; false otherwise.
      * @exception StandardException Thrown on error
      */
-    public BooleanDataValue XMLExists(StringDataValue xExpr,
-        XMLDataValue xml) throws StandardException;
+    public BooleanDataValue XMLExists(SqlXmlUtil sqlxUtil)
+		throws StandardException;
 
-    /**
-     * Helper method for XMLExists.
-     * See if the received XPath expression returns at least
-     * one node when evaluated against _this_ XML value.
-     *
-     * @param xExpr The XPath expression.
-     * @return True if at least one node in this XML value
-     *  matches the received xExpr; false otherwise.
-     */
-    public boolean exists(String xExpr) throws StandardException;
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/build.xml Tue Aug  8 08:53:29 2006
@@ -19,8 +19,9 @@
 <!-- Targets -->
 
   <target name="compile_types">
-    <!-- We only compile XML against JDK 1.4 because it relies on    -->
-    <!-- several XML classes that are part of 1.4 but aren't in 1.3  -->
+    <!-- We only compile SqlXmlUtil against JDK 1.4 because it   -->
+    <!-- relies on several XML classes that are part of 1.4 but  -->
+    <!-- that aren't in 1.3.                                     -->
     <javac
       source="1.3"
       target="1.3"
@@ -37,7 +38,7 @@
       <classpath>
         <pathelement path="${java14compile.classpath};${xercesImpl};${xml-apis}"/>
       </classpath>
-      <include name="${derby.dir}/iapi/types/XML.java"/>
+      <include name="${derby.dir}/iapi/types/SqlXmlUtil.java"/>
     </javac>
     <javac
       source="1.3"
@@ -58,7 +59,7 @@
       <include name="${derby.dir}/iapi/types/*.java"/>
       <exclude name="${derby.dir}/iapi/types/SQLDecimal.java"/>
       <exclude name="${derby.dir}/iapi/types/J2SEDataValueFactory.java"/>
-      <exclude name="${derby.dir}/iapi/types/XML.java"/>
+      <exclude name="${derby.dir}/iapi/types/SqlXmlUtil.java"/>
     </javac>
     <javac
       source="1.3"
@@ -78,7 +79,7 @@
       </classpath>
       <include name="${derby.dir}/iapi/types/SQLDecimal.java"/>
       <include name="${derby.dir}/iapi/types/J2SEDataValueFactory.java"/>
-      <exclude name="${derby.dir}/iapi/types/XML.java"/>
+      <exclude name="${derby.dir}/iapi/types/SqlXmlUtil.java"/>
     </javac>
   </target>
 

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=429698&r1=429697&r2=429698&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 Tue Aug  8 08:53:29 2006
@@ -34,6 +34,7 @@
 import org.apache.derby.iapi.types.StringDataValue;
 import org.apache.derby.iapi.types.TypeId;
 import org.apache.derby.iapi.types.DataTypeDescriptor;
+import org.apache.derby.iapi.types.SqlXmlUtil;
 
 import org.apache.derby.iapi.store.access.Qualifier;
 
@@ -116,6 +117,10 @@
 		{ClassName.StringDataValue, ClassName.XMLDataValue}		// XMLExists
 	};
 
+	// Class used to compile an XML query expression and/or load/process
+	// XML-specific objects.
+	private SqlXmlUtil sqlxUtil;
+
 	/**
 	 * Initializer for a BinaryOperatorNode
 	 *
@@ -340,24 +345,19 @@
         TypeId leftOperandType = leftOperand.getTypeId();
         TypeId rightOperandType = rightOperand.getTypeId();
 
-        // Left operand is query expression, and must be a string.
-        if (leftOperandType != null) {
-            switch (leftOperandType.getJDBCTypeId())
-            {
-                case Types.CHAR:
-                case Types.VARCHAR:
-                case Types.LONGVARCHAR:
-                case Types.CLOB:
-                    break;
-                default:
-                {
-                    throw StandardException.newException(
-                        SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED, 
-                        methodName,
-                        leftOperandType.getSQLTypeName(),
-                        rightOperandType.getSQLTypeName());
-                }
-            }
+        // Left operand is query expression and must be a string
+        // literal.  SQL/XML spec doesn't allow params nor expressions
+        // 6.17: <XQuery expression> ::= <character string literal> 
+        if (!(leftOperand instanceof CharConstantNode))
+        {
+            throw StandardException.newException(
+                SQLState.LANG_INVALID_XML_QUERY_EXPRESSION);
+        }
+        else {
+        // compile the query expression.
+            sqlxUtil = new SqlXmlUtil();
+            sqlxUtil.compileXQExpr(
+                ((CharConstantNode)leftOperand).getString());
         }
 
         // Right operand is an XML data value.
@@ -371,15 +371,6 @@
                     rightOperandType.getSQLTypeName());
         }
 
-        // Is there a ? parameter on the left?
-        if (leftOperand.requiresTypeFromContext())
-        {
-            // Set the left operand to be a VARCHAR, which should be
-            // long enough to hold the XPath expression.
-            leftOperand.setType(
-                DataTypeDescriptor.getBuiltInDataTypeDescriptor(Types.VARCHAR));
-        }
-
         // Is there a ? parameter on the right?
         if (rightOperand.requiresTypeFromContext())
         {
@@ -469,6 +460,27 @@
 ** but how?
 */
 
+		// If we're dealing with XMLEXISTS, there is some
+		// additional work to be done.
+		boolean xmlGen = (operatorType == XMLEXISTS_OP);
+
+		if (xmlGen) {
+		// We create an execution-time object so that we can retrieve
+		// saved objects (esp. our compiled query expression) from
+		// the activation.  We do this for two reasons: 1) this level
+		// of indirection allows us to separate the XML data type
+		// from the required XML implementation classes (esp. JAXP
+		// and Xalan classes)--for more on how this works, see the
+		// comments in SqlXmlUtil.java; and 2) we can take
+		// the XML query expression, which we've already compiled,
+		// and pass it to the execution-time object for each row,
+		// which means that we only have to compile the query
+		// expression once per SQL statement (instead of once per
+		// row); see SqlXmlExecutor.java for more.
+			mb.pushNewStart(
+				"org.apache.derby.impl.sql.execute.SqlXmlExecutor");
+			mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
+		}
 
 		/*
 		** The receiver is the operand with the higher type precedence.
@@ -526,15 +538,25 @@
 			** Generate (with <right expression> only being evaluated once)
 			**
 			**	<right expression>.method(<left expression>, <right expression>)
+			**
+			** UNLESS we're generating an XML operator such as XMLEXISTS.
+			** In that case we want to generate
+			** 
+			**  SqlXmlExecutor.method(left, right)"
+			**
+			** and we've already pushed the SqlXmlExecutor object to
+			** the stack.
 			*/
 
 			rightOperand.generateExpression(acb, mb);			
 			mb.cast(receiverType); // cast the method instance
 			// stack: right
 			
-			mb.dup();
-			mb.cast(rightInterfaceType);
-			// stack: right,right
+			if (!xmlGen) {
+				mb.dup();
+				mb.cast(rightInterfaceType);
+				// stack: right,right
+			}
 			
 			leftOperand.generateExpression(acb, mb);
 			mb.cast(leftInterfaceType); // second arg with cast
@@ -604,7 +626,16 @@
 
 			mb.putField(resultField);
 		} else {
-			mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType, methodName, resultTypeName, 2);
+			if (xmlGen) {
+			// This is for an XMLEXISTS operation, so invoke the method
+			// on our execution-time object.
+				mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
+					methodName, resultTypeName, 2);
+			}
+			else {
+				mb.callMethod(VMOpcode.INVOKEINTERFACE, receiverType,
+					methodName, resultTypeName, 2);
+			}
 		}
 	}
 
@@ -805,5 +836,33 @@
 		}
 		
 		return returnNode;
+	}
+
+	/**
+	 * Push the fields necessary to generate an instance of
+	 * SqlXmlExecutor, which will then be used at execution
+	 * time to retrieve the compiled XML query expression,
+	 * along with any other XML-specific objects.
+	 *
+	 * @param acb The ExpressionClassBuilder for the class we're generating
+	 * @param mb  The method the code to place the code
+	 *
+	 * @return The number of items that this method pushed onto
+	 *  the mb's stack.
+	 */
+	private int addXmlOpMethodParams(ExpressionClassBuilder acb,
+		MethodBuilder mb) throws StandardException
+	{
+		// Push activation so that we can get our saved object
+		// (which will hold the compiled XML query expression)
+		// back at execute time.
+		acb.pushThisAsActivation(mb);
+
+		// Push our saved object (the compiled query and XML-specific
+		// objects).
+		mb.push(getCompilerContext().addSavedObject(sqlxUtil));
+
+		// We pushed 2 items to the stack.
+		return 2;
 	}
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UnaryOperatorNode.java Tue Aug  8 08:53:29 2006
@@ -37,6 +37,7 @@
 
 import org.apache.derby.iapi.types.TypeId;
 import org.apache.derby.iapi.types.DataTypeDescriptor;
+import org.apache.derby.iapi.types.SqlXmlUtil;
 
 import java.lang.reflect.Modifier;
 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
@@ -113,6 +114,10 @@
 	// args required by the operator method call.
 	private Object [] additionalArgs;
 
+	// Class used to hold XML-specific objects required for
+	// parsing/serializing XML data.
+	private SqlXmlUtil sqlxUtil;
+
 	/**
 	 * Initializer for a UnaryOperatorNode.
 	 *
@@ -391,6 +396,12 @@
             }
         }
 
+        // Create a new XML compiler object; the constructor
+        // here automatically creates the XML-specific objects 
+        // required for parsing/serializing XML, so all we
+        // have to do is create an instance.
+        sqlxUtil = new SqlXmlUtil();
+
         // The result type of XMLParse() is always an XML type.
         setType(DataTypeDescriptor.getBuiltInDataTypeDescriptor(
             StoredFormatIds.XML_TYPE_ID));
@@ -631,6 +642,26 @@
 		if (operand == null)
 			return;
 
+		// For XML operator we do some extra work.
+		boolean xmlGen = (operatorType == XMLPARSE_OP) ||
+			(operatorType == XMLSERIALIZE_OP);
+
+		if (xmlGen) {
+		// We create an execution-time object from which we call
+		// the necessary methods.  We do this for two reasons: 1) this
+		// level of indirection allows us to separate the XML data type
+		// from the required XML implementation classes (esp. JAXP and
+		// Xalan classes)--for more on how this works, see the comments
+		// in SqlXmlUtil.java; and 2) this allows us to create the
+		// required XML objects a single time (which we did at bind time
+		// when we created a new SqlXmlUtil) and then reuse those objects
+		// for each row in the target result set, instead of creating
+		// new objects every time; see SqlXmlUtil.java for more.
+			mb.pushNewStart(
+				"org.apache.derby.impl.sql.execute.SqlXmlExecutor");
+			mb.pushNewComplete(addXmlOpMethodParams(acb, mb));
+		}
+
 		String resultTypeName = 
 			(operatorType == -1)
 				? getTypeCompiler().interfaceName()
@@ -650,8 +681,26 @@
 			/* Allocate an object for re-use to hold the result of the operator */
 			LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);
 			mb.getField(field);
-			int numParams = 1 + addMethodParams(mb);
-			mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, resultTypeName, numParams);
+
+			/* If we're calling a method on a class (SqlXmlExecutor) instead
+			 * of calling a method on the operand interface, then we invoke
+			 * VIRTUAL; we then have 2 args (the operand and the local field)
+			 * instead of one, i.e:
+			 *
+			 *  SqlXmlExecutor.method(operand, field)
+			 *
+			 * instead of
+			 *
+			 *  <operand>.method(field).
+			 */
+			if (xmlGen) {
+				mb.callMethod(VMOpcode.INVOKEVIRTUAL, null,
+					methodName, resultTypeName, 2);
+			}
+			else {
+				mb.callMethod(VMOpcode.INVOKEINTERFACE,
+					(String) null, methodName, resultTypeName, 1);
+			}
 
 			/*
 			** Store the result of the method call in the field, so we can re-use
@@ -659,8 +708,8 @@
 			*/
 			mb.putField(field);
 		} else {
-			int numParams = addMethodParams(mb);
-			mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, resultTypeName, numParams);
+			mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,
+				methodName, resultTypeName, 0);
 		}
 	}
 
@@ -738,25 +787,28 @@
 	}
 
     /**
-     * This method allows different operators to add
-     * primitive arguments to the generated method call,
-     * if needed.
+     * Add some additional arguments to our method call for
+     * XML related operations like XMLPARSE and XMLSERIALIZE.
      * @param mb The MethodBuilder that will make the call.
      * @return Number of parameters added.
      */
-    protected int addMethodParams(MethodBuilder mb)
+    protected int addXmlOpMethodParams(ExpressionClassBuilder acb,
+		MethodBuilder mb) throws StandardException
     {
-        if (operatorType == XMLPARSE_OP) {
-        // We push whether or not we want to preserve whitespace.
-            mb.push(((Boolean)additionalArgs[0]).booleanValue());
-            return 1;
-        }
+        if ((operatorType != XMLPARSE_OP) && (operatorType != XMLSERIALIZE_OP))
+        // nothing to do.
+            return 0;
 
         if (operatorType == XMLSERIALIZE_OP) {
         // We push the target type's JDBC type id as well as
         // the maximum width, since both are required when
         // we actually perform the operation, and both are
-        // primitive types.
+        // primitive types.  Note: we don't have to save
+        // any objects for XMLSERIALIZE because it doesn't
+        // require any XML-specific objects: it just returns
+        // the serialized version of the XML value, which we
+        // already found when the XML value was created (ex.
+        // as part of the XMLPARSE work).
             DataTypeDescriptor targetType =
                 (DataTypeDescriptor)additionalArgs[0];
             mb.push(targetType.getJDBCTypeId());
@@ -764,7 +816,21 @@
             return 2;
         }
 
-        // Default is to add zero params.
-        return 0;
+        /* Else we're here for XMLPARSE. */
+
+        // Push activation, which we use at execution time to
+        // get our saved object (which will hold objects used
+        // for parsing/serializing) back.
+        acb.pushThisAsActivation(mb);
+
+        // Push our XML object (used for parsing/serializing) as
+        // a saved object, so that we can retrieve it at execution
+        // time.  This allows us to avoid having to re-create the
+        // objects for every row in a given result set.
+        mb.push(getCompilerContext().addSavedObject(sqlxUtil));
+
+        // Push whether or not we want to preserve whitespace.
+        mb.push(((Boolean)additionalArgs[0]).booleanValue());
+        return 3;
     }
 }

Added: 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=429698&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java Tue Aug  8 08:53:29 2006
@@ -0,0 +1,246 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.execute.SqlXmlExecutor
+
+   Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.execute;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.sql.Activation;
+
+import org.apache.derby.iapi.types.BooleanDataValue;
+import org.apache.derby.iapi.types.StringDataValue;
+import org.apache.derby.iapi.types.XML;
+import org.apache.derby.iapi.types.XMLDataValue;
+import org.apache.derby.iapi.types.SqlXmlUtil;
+
+/**
+ * This class is really just an execution time "utility" that
+ * makes calls to methods on the XMLDataValue interface.  Instances
+ * of this class are generated at execution time by the various
+ * Derby XML operators--one instance for each row in the target
+ * result set--and then the appropriate operator call is made on
+ * that instance (see, for example, the generateExpression() methods
+ * in UnaryOperatorNode and BinaryOperatorNode).  When an instance
+ * of this class is instantiated, one of the arguments that can be
+ * provided is an id that is used to retrieve an already-constructed
+ * (from compilation time) instance of SqlXmlUtil from the current
+ * Activation.  When it comes time to execute the operator, this class
+ * just makes the appropriate call on the received XMLDataValue object
+ * and passes in the SqlXmlUtil, from which the XMLDataValue can
+ * retrieve compile-time objects.  The XMLDataValue can also make
+ * calls to various XML-specific utilities on the SqlXmlUtil
+ * object.
+ *
+ * Let's take an example.  Assume the statement that the user
+ * wants to execute is:
+ *
+ *   select id from xtable
+ *      where XMLEXISTS('/simple' PASSING BY REF xcol)
+ *
+ * At compilation time we will compile the expression "/simple"
+ * and store the compiled version of the query into an instance
+ * of SqlXmlUtil.  Then we will save that instance of SqlXmlUtil
+ * as an object in the statement activation, from which we will
+ * receive an id that can be used later to retrieve the object
+ * (i.e. to retrieve the SqlXmlUtil).  Then, for *each* row
+ * in xtable, we'll generate the following:
+ *
+ *  boolean result =
+ *    (new SqlXmlExecutor(activation, compileTimeObjectId)).
+ *      XMLExists("/simple", xcol);
+ *
+ * In other words, for each row we create a new instance of
+ * this class and call "XMLExists" on that instance.  Then,
+ * as seen below, we retrieve the SqlXmlUtil from the activation
+ * and pass that into a call to "XMLExists" on the XML value
+ * itself (i.e. xcol).  XMLDataValue.XMLExists() then uses the
+ * methods and objects (which include the compiled query
+ * expression for "/simple") defined on SqlXmlUtil to complete
+ * the operation.
+ * 
+ * Okay, so why do we use this execution-time SqlXmlExecutor class
+ * instead of just generating a call to XMLDataValue.XMLExists()
+ * directly?  The reason is that we only want to compile the XML
+ * query expression once per statement--and where possible we'd
+ * also like to only generate re-usable XML-specific objects
+ * once per statement, as well.  If instead we generated a call to
+ * XMLDataValue.XMLExists() directly for each row, then we would
+ * have to either pass in the expression string and have XMLDataValue
+ * compile it, or we would have to compile the expression string
+ * and then pass the compiled object into XMLDataValue--in either
+ * case, we'd end up compiling the XML query expression (and creating
+ * the corresponding XML-specific objects) once for each row in
+ * the target result set.  By using the "saveObject" functionality
+ * in Activation along with this SqlXmlExecutor class, we make
+ * it so that we only have to compile the XML query expression and
+ * create XML-specific objects once (at compile time), and then
+ * we can re-use those objects for every row in the target
+ * result set.  Yes, we're still creating an instance of this
+ * class (SqlXmlExecutor) once per row, and yes we have to fetch
+ * the appropriate SqlXmlUtil object once per row, but this is
+ * still going to be cheaper than having to re-compile the query
+ * expression and re-create XML objects for every row.
+ * 
+ * So in short, this class allows us to improve the execution-time
+ * performance of XML operators by allowing us to create XML-
+ * specific objects and compile XML query expressions once per
+ * statement, instead of once per row.
+ *
+ * One final note: the reason this class is in this package
+ * instead of the types package is that, in order to retrieve
+ * the compile-time objects, we have to use the "getSavedObject()"
+ * method on the Activation.  But the Activation class is part
+ * of the SQL layer (org.apache.derby.iapi.sql.Activation) and
+ * we want to keep the types layer independent of the SQL layer
+ * because the types can be used during recovery before the SQL
+ * system has booted.  So the next logical choices were the compile
+ * package (impl.sql.compile) or the execution package; of those,
+ * the execution package seems more appropriate since this
+ * class is only instantiated and used during execution, not
+ * during compilation.
+ */
+
+public class SqlXmlExecutor {
+
+    // The activation from which we load the compile-time XML
+    // objects (including the compiled XML query expression in
+    // case of XMLEXISTS).
+    private Activation activation;
+    private int sqlXUtilId;
+
+    // Target type and target width that were specified
+    // for an XMLSERIALIZE operator.
+    private int targetTypeId;
+    private int targetMaxWidth;
+
+    // Whether or not to preserve whitespace for XMLPARSE
+    // operator.
+    private boolean preserveWS;
+
+    /**
+     * Constructor 1: Used for XMLPARSE op.
+     * @param activation Activation from which to retrieve saved objects
+     * @param utilId Id by which we find saved objects in activation
+     * @param preserveWS Whether or not to preserve whitespace
+     */
+    public SqlXmlExecutor(Activation activation, int utilId,
+        boolean preserveWS)
+    {
+        this.activation = activation;
+        this.sqlXUtilId = utilId;
+        this.preserveWS = preserveWS;
+    }
+
+    /**
+     * Constructor 2: Used for XMLSERIALIZE op.
+     * @param targetTypeId The string type to which we want to serialize.
+     * @param targetMaxWidth The max width of the target type.
+     */
+    public SqlXmlExecutor(int targetTypeId, int targetMaxWidth)
+    {
+        this.targetTypeId = targetTypeId;
+        this.targetMaxWidth = targetMaxWidth;
+    }
+
+    /**
+     * Constructor 3: Used for XMLEXISTS ops.
+     * @param activation Activation from which to retrieve saved objects
+     * @param utilId Id by which we find saved objects in activation
+     */
+    public SqlXmlExecutor(Activation activation, int utilId)
+    {
+        this.activation = activation;
+        this.sqlXUtilId = utilId;
+    }
+
+    /**
+     * Make the call to perform an XMLPARSE operation on the
+     * received XML string and store the result in the received
+     * XMLDataValue (or if it's null, create a new one).
+     *
+     * @param xmlText String to parse
+     * @param result XMLDataValue in which to store the result
+     * @return The received XMLDataValue with its content set to
+     *  correspond to the received xmlText, if the text constitutes
+     *  a valid XML document.  If the received XMLDataValue is
+     *  null, then create a new one and set its content to
+     *  correspond to the received xmlText.
+     */
+    public XMLDataValue XMLParse(StringDataValue xmlText, XMLDataValue result)
+        throws StandardException
+    {
+        if (result == null)
+            result = new XML();
+
+        if (xmlText.isNull())
+        {
+            result.setToNull();
+            return result;
+        }
+
+        return result.XMLParse(
+            xmlText.getString(), preserveWS, getSqlXmlUtil());
+    }
+
+    /**
+     * Make the call to perform an XMLSERIALIZE operation on the
+     * received XML data value and store the result in the received
+     * StringDataValue (or if it's null, create a new one).
+     *
+     * @param xmlVal XML value to serialize
+     * @param result StringDataValue in which to store the result
+     * @return A serialized (to string) version of this XML object,
+     *  in the form of a StringDataValue object.  
+     */
+    public StringDataValue XMLSerialize(XMLDataValue xmlVal,
+        StringDataValue result) throws StandardException
+    {
+        return xmlVal.XMLSerialize(result, targetTypeId, targetMaxWidth);
+    }
+
+    /**
+     * Make the call to perform an XMLEXISTS operation on the
+     * received XML data value.
+     *
+     * @param xExpr Query expression to be evaluated
+     * @param xmlContext Context node against which to evaluate
+     *  the expression.
+     * @return True if evaluation of the query expression
+     *  against xmlContext returns at least one item; unknown if
+     *  either the xml value is NULL; false otherwise. 
+     */
+    public BooleanDataValue XMLExists(StringDataValue xExpr,
+        XMLDataValue xmlContext) throws StandardException
+    {
+        return xmlContext.XMLExists(getSqlXmlUtil());
+    }
+
+    /**
+     * Return the saved object in this.activation that corresponds to
+     * this.sqlxUtilId.  Assumption is that those fields have been
+     * set by the time we get here.
+     */
+    private SqlXmlUtil getSqlXmlUtil()
+        throws StandardException
+    {
+        return (SqlXmlUtil)
+            activation.getPreparedStatement().getSavedObject(sqlXUtilId);
+    }
+
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SqlXmlExecutor.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -1017,6 +1017,7 @@
 X0X16.S=XML syntax error; missing keyword(s): ''{0}''.
 X0X17.S=Invalid target type for XMLSERIALIZE: ''{0}''.
 X0X18.S=XML feature not supported: ''{0}''.
+X0X19.S=XML query expression must be a string literal.
 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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -1207,6 +1207,7 @@
 	String LANG_XML_KEYWORD_MISSING                                    = "X0X16.S";
 	String LANG_INVALID_XMLSERIALIZE_TYPE                              = "X0X17.S";
 	String LANG_UNSUPPORTED_XML_FEATURE                                = "X0X18.S";
+	String LANG_INVALID_XML_QUERY_EXPRESSION                           = "X0X19.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/xmlBinding.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xmlBinding.out?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xmlBinding.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/xmlBinding.out Tue Aug  8 08:53:29 2006
@@ -25,7 +25,7 @@
 2, [ roughly 40k ]
 3, [ roughly 1k ]
 4, [ roughly 1k ]
-5, [ roughly 1k ]
+5, [ roughly 0k ]
 6, [ roughly 1k ]
 7, [ roughly 0k ]
 8, NULL
@@ -44,8 +44,6 @@
 -----> Matching rows: 4
 Running XMLEXISTS with: //person/@noteTwo
 -----> Matching rows: 1
-Binding string in XMLEXISTS: PASS -- Completed without exception, as expected.
-Binding Java null string in XMLEXISTS: PASS -- Completed without exception, as expected.
-Binding SQL NULL string in XMLEXISTS: PASS -- Completed without exception, as expected.
+Parameter as first operand in XMLEXISTS: PASS -- caught expected error X0X19.
 [ End XMLEXISTS tests. ]
 [ Done. ]

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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -263,32 +263,20 @@
 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;
-1         
------
 ERROR 2200L: XMLPARSE operand is not an XML document; see next exception for details. SQLSTATE: XJ001: Java exception: 'Content is not allowed in prolog.: xxxFILTERED-SAX-EXCEPTIONxxx'.
 ij> select xmlserialize(x as char) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select xmlserialize(x as clob(10)) from t1;
 1         
 -----
 ERROR 22001: A truncation error was encountered trying to shrink CLOB '<update2> document was inserted as part of an UPDATE </updat&' to length 10.
 ij> select xmlserialize(x as char(1)) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select length(xmlserialize(x as char(1))) from t1;
-1          
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select xmlserialize(x as varchar(1)) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink VARCHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select length(xmlserialize(x as varchar(1))) from t1;
-1          
------
 ERROR 22001: A truncation error was encountered trying to shrink VARCHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> -- These checks verify that the XMLSERIALIZE result is the correct
 ----- type (the type is indicated as part of the error message).

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=429698&r1=429697&r2=429698&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 08:53:29 2006
@@ -263,32 +263,20 @@
 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;
-1         
------
 ERROR 2200L: XMLPARSE operand is not an XML document; see next exception for details. SQLSTATE: XJ001: Java exception: 'Content is not allowed in prolog.: xxxFILTERED-SAX-EXCEPTIONxxx'.
 ij> select xmlserialize(x as char) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select xmlserialize(x as clob(10)) from t1;
 1         
 -----
 ERROR 22001: A truncation error was encountered trying to shrink CLOB '<update2> document was inserted as part of an UPDATE </updat&' to length 10.
 ij> select xmlserialize(x as char(1)) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select length(xmlserialize(x as char(1))) from t1;
-1          
------
 ERROR 22001: A truncation error was encountered trying to shrink CHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select xmlserialize(x as varchar(1)) from t1;
-1   
------
 ERROR 22001: A truncation error was encountered trying to shrink VARCHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> select length(xmlserialize(x as varchar(1))) from t1;
-1          
------
 ERROR 22001: A truncation error was encountered trying to shrink VARCHAR '<update2> document was inserted as part of an UPDATE </updat&' to length 1.
 ij> -- These checks verify that the XMLSERIALIZE result is the correct
 ----- type (the type is indicated as part of the error message).
@@ -341,7 +329,7 @@
 1 row inserted/updated/deleted
 ij> -- These should fail.
 select i from t1 where xmlexists(x);
-ERROR 42X01: Syntax error: Encountered ")" at line 1, column 35.
+ERROR 42X01: Syntax error: Encountered ")" at line 2, column 35.
 ij> select i from t1 where xmlexists(i);
 ERROR 42X01: Syntax error: Encountered ")" at line 1, column 35.
 ij> select i from t1 where xmlexists('//*');

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xmlBinding.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xmlBinding.out?rev=429698&r1=429697&r2=429698&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xmlBinding.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/xmlBinding.out Tue Aug  8 08:53:29 2006
@@ -22,7 +22,7 @@
 2, [ roughly 40k ]
 3, [ roughly 1k ]
 4, [ roughly 1k ]
-5, [ roughly 1k ]
+5, [ roughly 0k ]
 6, [ roughly 1k ]
 7, [ roughly 0k ]
 8, NULL
@@ -41,8 +41,6 @@
 --> Matching rows: 4
 Running XMLEXISTS with: //person/@noteTwo
 --> Matching rows: 1
-Binding string in XMLEXISTS: PASS -- Completed without exception, as expected.
-Binding Java null string in XMLEXISTS: PASS -- Completed without exception, as expected.
-Binding SQL NULL string in XMLEXISTS: PASS -- Completed without exception, as expected.
+Parameter as first operand in XMLEXISTS: PASS -- caught expected error X0X19.
 [ End XMLEXISTS tests. ]
 [ Done. ]