Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / iapi / types / SqlXmlUtil.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/iapi/types/SqlXmlUtil.java
new file mode 100644 (file)
index 0000000..8cbe2b0
--- /dev/null
@@ -0,0 +1,805 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.iapi.types.SqlXmlUtil\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.iapi.types;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.io.Formatable;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import java.util.Properties;\r
+import java.util.ArrayList;\r
+\r
+import java.io.IOException;\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+import java.io.StringReader;\r
+\r
+// -- JDBC 3.0 JAXP API classes.\r
+\r
+import org.w3c.dom.Attr;\r
+import org.w3c.dom.Document;\r
+import org.w3c.dom.Element;\r
+import org.w3c.dom.Node;\r
+import org.w3c.dom.NodeList;\r
+import org.w3c.dom.Text;\r
+\r
+import org.xml.sax.ErrorHandler;\r
+import org.xml.sax.InputSource;\r
+import org.xml.sax.SAXException;\r
+import org.xml.sax.SAXParseException;\r
+\r
+import javax.xml.parsers.DocumentBuilder;\r
+import javax.xml.parsers.DocumentBuilderFactory;\r
+\r
+import javax.xml.transform.OutputKeys;\r
+import javax.xml.transform.TransformerException;\r
+\r
+// -- Xalan-specific classes.\r
+\r
+import org.apache.xpath.XPath;\r
+import org.apache.xpath.XPathContext;\r
+import org.apache.xpath.objects.XObject;\r
+import org.apache.xpath.objects.XNodeSet;\r
+\r
+import org.apache.xml.utils.PrefixResolverDefault;\r
+\r
+import org.apache.xalan.serialize.DOMSerializer;\r
+import org.apache.xalan.serialize.Serializer;\r
+import org.apache.xalan.serialize.SerializerFactory;\r
+import org.apache.xalan.templates.OutputProperties;\r
+\r
+/**\r
+ * This class contains "utility" methods that work with XML-specific\r
+ * objects that are only available if JAXP and/or Xalan are in\r
+ * the classpath.\r
+ *\r
+ * NOTE: This class is only compiled with JDK 1.4 and higher since\r
+ * the XML-related classes that it uses (JAXP and Xalan) are not\r
+ * part of earlier JDKs.\r
+ *\r
+ * Having a separate class for this functionality is beneficial\r
+ * for two reasons:\r
+ *\r
+ *    1. Allows us to allocate XML objects and compile an XML\r
+ *       query expression a single time per statement, instead of\r
+ *       having to do it for every row against which the query\r
+ *       is evaluated.  An instance of this class is created at\r
+ *       compile time and then passed (using "saved objects")\r
+ *       to the appropriate operator implementation method in\r
+ *       XML.java; see SqlXmlExecutor.java for more about the\r
+ *       role this class plays in "saved object" processing.\r
+ *\r
+ *    2. By keeping all XML-specific references in this one class, \r
+ *       we have a single "point of entry" to the XML objects--namely,\r
+ *       the constructor for this class.  Thus, if we always make\r
+ *       sure to check for the required XML classes _before_ calling\r
+ *       this class's constructor, we can detect early on whether\r
+ *       some classes (ex. Xalan) are missing, and can throw a friendly\r
+ *       error up front, instead of a ClassNotFoundException somewhere\r
+ *       deeper in the execution codepath.  The initial check for the\r
+ *       required XML classes can be found in XML.checkXMLRequirements().\r
+ *\r
+ *       Note that we don't want to put references to XML-specific\r
+ *       objects directly into XML.java because that class (XML.java) is\r
+ *       instantiated anytime a table with an XML column is referenced.\r
+ *       That would mean that if a user tried to select a non-XML column\r
+ *       (ex. integer) from a table that had at least one XML column in\r
+ *       it, the user would have to have JAXP and Xalan classes in\r
+ *       his/her classpath--which we don't want.  Instead, by keeping\r
+ *       all XML-specific objects in this one class, and then only\r
+ *       instantiating this class when an XML operator is used (either\r
+ *       implicitly or explicitly), we make it so that the user is only\r
+ *       required to have XML-specific classes in his/her classpath\r
+ *       _if_ s/he is trying to access or operate on XML values.\r
+ */\r
+\r
+public class SqlXmlUtil implements Formatable\r
+{\r
+    // Used to parse a string into an XML value (DOM); checks\r
+    // the well-formedness of the string while parsing.\r
+    private DocumentBuilder dBuilder;\r
+\r
+    // Used to serialize an XML value according the standard\r
+    // XML serialization rules.\r
+    private Serializer serializer;\r
+\r
+    // Classes used to compile and execute an XPath expression\r
+    // against Xalan.\r
+    private XPath query;\r
+    private XPathContext xpContext;\r
+\r
+    // Used to recompile the XPath expression when this formatable\r
+    // object is reconstructed.  e.g.:  SPS \r
+    private String queryExpr;\r
+    private String opName;\r
+    private boolean recompileQuery;\r
+    \r
+    /**\r
+     * Constructor: Initializes objects required for parsing\r
+     * and serializing XML values.  Since most XML operations\r
+     * that require XML-specific classes perform both parsing\r
+     * and serialization at some point, we just initialize the\r
+     * objects up front.\r
+     */\r
+    public SqlXmlUtil() throws StandardException\r
+    {\r
+        try {\r
+\r
+            /* Note: Use of DocumentBuilderFactory means that we get\r
+             * whatever XML parser is the "default" for the JVM in\r
+             * use--and thus, we don't have to hard-code the parser\r
+             * name, nor do we have to require that the user have a\r
+             * specific parser in his/her classpath.\r
+             *\r
+             * This DocumentBuilder is currently used for parsing\r
+             * (esp. XMLPARSE), and the SQL/XML spec says that XMLPARSE\r
+             * should NOT perform validation (SQL/XML[2006], 6.15:\r
+             * "Perform a non-validating parse of a string to produce\r
+             * an XML value.").   So we disable validation here, and\r
+             * we also make the parser namespace aware.\r
+             *\r
+             * At some point in the future we will probably want to add\r
+             * support for the XMLVALIDATE function--but until then, user\r
+             * is unable to validate the XML values s/he inserts.\r
+             *\r
+             * Note that, even with validation turned off, XMLPARSE\r
+             * _will_ still check the well-formedness of the values,\r
+             * and it _will_ still process DTDs to get default values,\r
+             * etc--but that's it; no validation errors will be thrown.\r
+             */\r
+\r
+            DocumentBuilderFactory dBF = null;\r
+            try {\r
+\r
+                dBF = DocumentBuilderFactory.newInstance();\r
+                       //Added by Jeff Huang\r
+                       //TODO: FIXIT\r
+            } catch (Throwable e) {\r
+\r
+                /* We assume that if we get an error creating the\r
+                 * DocumentBuilderFactory, it's because there's no\r
+                 * JAXP implementation.  This can happen in the\r
+                 * (admittedly unlikely) case where the classpath\r
+                 * contains the JAXP _interfaces_ (ex. via xml-apis.jar)\r
+                 * and the Xalan classes but does not actually\r
+                 * contain a JAXP _implementation_.  In that case the\r
+                 * check in XML.checkXMLRequirements() will pass\r
+                 * and this class (SqlXmlUtil) will be instantiated\r
+                 * successfully--which is how we get to this constructor.\r
+                 * But then attempts to create a DocumentBuilderFactory\r
+                 * will fail, bringing us here.  Note that we can't\r
+                 * check for a valid JAXP implementation in the\r
+                 * XML.checkXMLRequirements() method because we\r
+                 * always want to allow the XML.java class to be\r
+                 * instantiated, even if the required XML classes\r
+                 * are not present--and that means that it (the\r
+                 * XML class) cannot reference DocumentBuilder nor\r
+                 * any of the JAXP classes directly.\r
+                 */\r
+                 throw StandardException.newException(\r
+                     SQLState.LANG_MISSING_XML_CLASSES, "JAXP");\r
+\r
+            }\r
+\r
+            dBF.setValidating(false);\r
+            dBF.setNamespaceAware(true);\r
+\r
+            // Load document builder that can be used for parsing XML.\r
+            dBuilder = dBF.newDocumentBuilder();\r
+            dBuilder.setErrorHandler(new XMLErrorHandler());\r
+\r
+            // Load serializer for serializing XML into string according\r
+            // XML serialization rules.\r
+            loadSerializer();\r
+\r
+        } catch (StandardException se) {\r
+\r
+            // Just rethrow it.\r
+            throw se;\r
+\r
+        } catch (Throwable t) {\r
+\r
+            /* Must be something caused by JAXP or Xalan; wrap it in a\r
+             * StandardException and rethrow it. Note: we catch "Throwable"\r
+             * here to catch as many external errors as possible in order\r
+             * to minimize the chance of an uncaught JAXP/Xalan error (such\r
+             * as a NullPointerException) causing Derby to fail in a more\r
+             * serious way.  In particular, an uncaught Java exception\r
+             * like NPE can result in Derby throwing "ERROR 40XT0: An\r
+             * internal error was identified by RawStore module" for all\r
+             * statements on the connection after the failure--which we\r
+             * clearly don't want.  If we catch the error and wrap it,\r
+             * though, the statement will fail but Derby will continue to\r
+             * run as normal.\r
+             */ \r
+            throw StandardException.newException(\r
+                SQLState.LANG_UNEXPECTED_XML_EXCEPTION, t, t.getMessage());\r
+\r
+        }\r
+\r
+        // At construction time we don't have an XML query expression\r
+        // to compile.  If one is required, we'll load/compile it later.\r
+        query = null;\r
+    }\r
+\r
+    /**\r
+     * Take the received string, which is an XML query expression,\r
+     * compile it, and store the compiled query locally.  Note\r
+     * that for now, we only support XPath because that's what\r
+     * Xalan supports.\r
+     *\r
+     * @param queryExpr The XPath expression to compile\r
+     */\r
+    public void compileXQExpr(String queryExpr, String opName)\r
+        throws StandardException\r
+    {\r
+        try {\r
+\r
+            /* The following XPath constructor compiles the expression\r
+             * as part of the construction process.  We have to pass\r
+             * in a PrefixResolver object in order to avoid NPEs when\r
+             * invalid/unknown functions are used, so we just create\r
+             * a dummy one, which means prefixes will not be resolved\r
+             * in the query (Xalan will just throw an error if a prefix\r
+             * is used).  In the future we may want to revisit this\r
+             * to make it easier for users to query based on namespaces.\r
+             */\r
+            query = new XPath(queryExpr, null,\r
+                new PrefixResolverDefault(dBuilder.newDocument()),\r
+                XPath.SELECT);\r
+            \r
+            this.queryExpr = queryExpr;\r
+            this.opName = opName;\r
+            this.recompileQuery = false;\r
+\r
+        } catch (Throwable te) {\r
+\r
+            /* Something went wrong during compilation of the\r
+             * expression; wrap the error and re-throw it.\r
+             * Note: we catch "Throwable" here to catch as many\r
+             * Xalan-produced errors as possible in order to\r
+             * minimize the chance of an uncaught Xalan error\r
+             * (such as a NullPointerException) causing Derby\r
+             * to fail in a more serious way.  In particular, an\r
+             * uncaught Java exception like NPE can result in\r
+             * Derby throwing "ERROR 40XT0: An internal error was\r
+             * identified by RawStore module" for all statements on\r
+             * the connection after the failure--which we clearly\r
+             * don't want.  If we catch the error and wrap it,\r
+             * though, the statement will fail but Derby will\r
+             * continue to run as normal. \r
+             */\r
+            throw StandardException.newException(\r
+                SQLState.LANG_XML_QUERY_ERROR, te, opName, te.getMessage());\r
+\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Take a string representing an XML value and serialize it\r
+     * according SQL/XML serialization rules.  Right now, we perform\r
+     * this serialization by first parsing the string into a JAXP\r
+     * Document object, and then applying the serialization semantics\r
+     * to that Document.  That seems a bit inefficient, but neither\r
+     * Xalan nor JAXP provides a more direct way to do this.\r
+     *\r
+     * @param xmlAsText String version of XML on which to perform\r
+     *   serialization.\r
+     * @return A properly serialized version of xmlAsText.\r
+     */\r
+    protected String serializeToString(String xmlAsText)\r
+        throws Exception\r
+    {\r
+        ArrayList aList = new ArrayList();\r
+\r
+        /* The call to dBuilder.parse() is a call to an external\r
+         * (w.r.t. to Derby) JAXP parser.  If the received XML\r
+         * text references an external DTD, then the JAXP parser\r
+         * will try to read that external DTD.  Thus we wrap the\r
+         * call to parse inside a privileged action to make sure\r
+         * that the JAXP parser has the required permissions for\r
+         * reading the DTD file.\r
+         */\r
+        try {\r
+\r
+            final InputSource is = new InputSource(new StringReader(xmlAsText));\r
+            aList.add(java.security.AccessController.doPrivileged(\r
+                new java.security.PrivilegedExceptionAction()\r
+                {\r
+                    public Object run() throws IOException, SAXException\r
+                    {\r
+                        return dBuilder.parse(is);\r
+                    }\r
+                }));\r
+\r
+        } catch (java.security.PrivilegedActionException pae) {\r
+\r
+            /* Unwrap the privileged exception so that the user can\r
+             * see what the underlying error is. For example, it could\r
+             * be an i/o error from parsing the XML value, which can\r
+             * happen if the XML value references an external DTD file\r
+             * but the JAXP parser hits an i/o error when trying to read\r
+             * the DTD.  In that case we want to throw the i/o error\r
+             * itself so that it does not appear as a security exception\r
+             * to the user.\r
+             */\r
+            throw pae.getException();\r
+\r
+        }\r
+\r
+        /* The second argument in the following call is for\r
+         * catching cases where we have a top-level (parentless)\r
+         * attribute node--but since we just created the list\r
+         * with a single Document node, we already we know we\r
+         * don't have a top-level attribute node in the list,\r
+         * so we don't have to worry.  Hence the "null" here.\r
+         */\r
+        return serializeToString(aList, null);\r
+    }\r
+\r
+    /**\r
+     * Take an array list (sequence) of XML nodes and/or string values\r
+     * and serialize that entire list according to SQL/XML serialization\r
+     * rules, which ultimately point to XML serialization rules as\r
+     * defined by w3c.  As part of that serialization process we have\r
+     * to first "normalize" the sequence.  We do that by iterating through\r
+     * the list and performing the steps for "sequence normalization" as\r
+     * defined here:\r
+     *\r
+     * http://www.w3.org/TR/xslt-xquery-serialization/#serdm\r
+     *\r
+     * This method primarily focuses on taking the steps for normalization;\r
+     * for the rest of the serialization work, we just make calls on the\r
+     * DOMSerializer class provided by Xalan.\r
+     *\r
+     * @param items List of items to serialize\r
+     * @param xmlVal XMLDataValue into which the serialized string\r
+     *  returned by this method is ultimately going to be stored.\r
+     *  This is used for keeping track of XML values that represent\r
+     *  sequences having top-level (parentless) attribute nodes.\r
+     * @return Single string holding the serialized version of the\r
+     *  normalized sequence created from the items in the received\r
+     *  list.\r
+     */\r
+    protected String serializeToString(ArrayList items,\r
+        XMLDataValue xmlVal) throws java.io.IOException\r
+    {\r
+        if ((items == null) || (items.size() == 0))\r
+        // nothing to do; return empty sequence.\r
+            return "";\r
+\r
+        java.io.StringWriter sWriter = new java.io.StringWriter();\r
+\r
+        // Serializer should have been set by now.\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(serializer != null,\r
+                "Tried to serialize with uninitialized XML serializer.");\r
+        }\r
+\r
+        serializer.setWriter(sWriter);\r
+        DOMSerializer dSer = serializer.asDOMSerializer();\r
+\r
+        int sz = items.size();\r
+        Object obj = null;\r
+\r
+        /* Step 1: Empty sequence.  If we have an empty sequence then we\r
+         * won't ever enter the for loop and the call to sWriter.toString()\r
+         * at the end of this method will return an empty string, as\r
+         * required.  Otherwise, for a non-empty sequence our "items"\r
+         * list already corresponds to "S1".\r
+         */\r
+\r
+        // Iterate through the list and serialize each item.\r
+        boolean lastItemWasString = false;\r
+        for (int i = 0; i < sz; i++)\r
+        {\r
+            obj = items.get(i);\r
+            // if it's a string, then this corresponds to some atomic\r
+            // value, so just echo the string as it is.\r
+            if (obj instanceof String)\r
+            {\r
+                /* Step 2: Atomic values.  If "obj" is a string then it\r
+                 * corresponds to some atomic value whose "lexical\r
+                 * representation" is obj.  So we just take that.\r
+                 */\r
+\r
+                if (lastItemWasString)\r
+                {\r
+                    /* Step 3: Adjacent strings.  If we have multiple adjacent\r
+                     * strings then concatenate them with a single space\r
+                     * between them.\r
+                     */\r
+                    sWriter.write(" ");\r
+                }\r
+\r
+                /* Step 4: Create a Text node from the adjacent strings.\r
+                 * Since we're just going to serialize the Text node back\r
+                 * into a string, we short-cut this step by skipping the\r
+                 * creation of the Text node and just writing the string\r
+                 * out directly to our serialized stream.\r
+                 */\r
+                sWriter.write((String)obj);\r
+                lastItemWasString = true;\r
+            }\r
+            else if (obj instanceof Attr)\r
+            {\r
+                /* Step 7a: Attribute nodes.  If there is an Attribute node\r
+                 * node in the sequence then we have to throw a serialization\r
+                 * error.  NOTE: The rules say we also have to throw an error\r
+                 * for Namespace nodes, but JAXP doesn't define a "Namespace"\r
+                 * object per se; it just defines namespace prefixes and URIs\r
+                 * on other Nodes.  So we just check for attributes.  If we\r
+                 * find one then we take note of the fact that the result has\r
+                 * a parentless attribute node and later, if the user calls\r
+                 * XMLSERIALIZE on the received XMLDataValue we'll throw the\r
+                 * error as required.  Note that we currently only get here\r
+                 * for the XMLQUERY operator, which means we're serializing\r
+                 * a result sequence returned from Xalan and we're going to\r
+                 * store the serialized version into a Derby XML value.  In\r
+                 * that case the serialization is an internal operation--and\r
+                 * since the user didn't ask for it, we don't want to throw\r
+                 * the serialization error here.  If we did, then whenever an\r
+                 * XMLQUERY operation returned a result sequence with a top-\r
+                 * level attribute in it, the user would see a serialization\r
+                 * error. That's not correct since it is technically okay for\r
+                 * the XMLQUERY operation to return a sequence with an attribute\r
+                 * node; it's just not okay for a user to explicitly try to\r
+                 * serialize that sequence. So instead of throwing the error\r
+                 * here, we just take note of the fact that the sequence has\r
+                 * a top-level attribute.  Then later, IF the user makes an\r
+                 * explicit call to serialize the sequence, we'll throw the\r
+                 * appropriate error (see XML.XMLSerialize()).\r
+                 */\r
+                if (xmlVal != null)\r
+                    xmlVal.markAsHavingTopLevelAttr();\r
+                dSer.serialize((Node)obj);\r
+                lastItemWasString = false;\r
+            }\r
+            else\r
+            { // We have a Node, so try to serialize it.\r
+                Node n = (Node)obj;\r
+                if (n instanceof Text)\r
+                {\r
+                    /* Step 6: Combine adjacent text nodes into a single\r
+                     * text node.  Since we're just going to serialize the\r
+                     * Text node back into a string, we short-cut this step\r
+                     * by skipping the creation of a new Text node and just\r
+                     * writing the text value out directly to our serialized\r
+                     * stream.  Step 6 also says that empty text nodes should\r
+                     * be dropped--but if the text node is empty, the call\r
+                     * to getNodeValue() will return an empty string and\r
+                     * thus we've effectively "dropped" the text node from\r
+                     * the serialized result.  Note: it'd be cleaner to just\r
+                     * call "serialize()" on the Text node like we do for\r
+                     * all other Nodes, but Xalan doesn't allow that.  So\r
+                     * use the getNodeValue() method instead.\r
+                     */\r
+                    sWriter.write(n.getNodeValue());\r
+                }\r
+                else\r
+                {\r
+                    /* Steps 5 and 7b: Copy all non-attribute, non-text\r
+                     * nodes to the "normalized sequence" and then serialize\r
+                     * that normalized sequence.  We short-cut this by\r
+                     * just letting Xalan do the serialization for every\r
+                     * Node in the current list of items that wasn't\r
+                     * "serialized" as an atomic value, attribute, or\r
+                     * text node.\r
+                     */\r
+                    dSer.serialize(n);\r
+                }\r
+\r
+                lastItemWasString = false;\r
+            }\r
+        }\r
+\r
+        /* At this point sWriter holds the serialized version of the\r
+         * normalized sequence that corresponds to the received list\r
+         * of items.  So that's what we return.\r
+         */\r
+        sWriter.flush();\r
+        return sWriter.toString();\r
+    }\r
+\r
+    /**\r
+     * Evaluate this object's compiled XML query expression against\r
+     * the received xmlContext.  Then if returnResults is false,\r
+     * return an empty sequence (ArrayList) if evaluation yields\r
+     * at least one item and return null if evaluation yields zero\r
+     * items (the caller can then just check for null to see if the\r
+     * query returned any items).  If returnResults is true, then return\r
+     * return a sequence (ArrayList) containing all items returned\r
+     * from evaluation of the expression.  This array list can contain\r
+     * any combination of atomic values and XML nodes; it may also\r
+     * be empty.\r
+     *\r
+     * Assumption here is that the query expression has already been\r
+     * compiled and is stored in this.query.\r
+     *\r
+     * @param xmlContext The XML value against which to evaluate\r
+     *  the stored (compiled) query expression\r
+     * @param returnResults Whether or not to return the actual\r
+     *  results of the query\r
+     * @param resultXType The qualified XML type of the result\r
+     *  of evaluating the expression, if returnResults is true.\r
+     *  If the result is a sequence of exactly one Document node\r
+     *  then this will be XML(DOCUMENT(ANY)); else it will be\r
+     *  XML(SEQUENCE).  If returnResults is false, this value\r
+     *  is ignored.\r
+     * @return If returnResults is false then return an empty\r
+     *  ArrayList if evaluation returned at least one item and return\r
+     *  null otherwise.  If returnResults is true then return an\r
+     *  array list containing all of the result items and return\r
+     *  the qualified XML type via the resultXType parameter.\r
+     * @exception Exception thrown on error (and turned into a\r
+     *  StandardException by the caller).\r
+     */\r
+    protected ArrayList evalXQExpression(XMLDataValue xmlContext,\r
+        boolean returnResults, int [] resultXType) throws Exception\r
+    {\r
+        // if this object is in an SPS, we need to recompile the query\r
+        if (recompileQuery)\r
+        {\r
+               compileXQExpr(queryExpr, opName);\r
+        }\r
+\r
+        // Make sure we have a compiled query.\r
+        if (SanityManager.DEBUG) {\r
+            SanityManager.ASSERT(\r
+                (query != null) && (query.getExpression() != null),\r
+                "Failed to locate compiled XML query expression.");\r
+        }\r
+\r
+        /* Create a DOM node from the xmlContext, since that's how\r
+         * we feed the context to Xalan.  We do this by creating\r
+         * a Document node using DocumentBuilder, which means that\r
+         * the serialized form of the context node must be a string\r
+         * value that is parse-able by DocumentBuilder--i.e. it must\r
+         * constitute a valid XML document.  If that's true then\r
+         * the context item's qualified type will be DOC_ANY.\r
+         */\r
+        if (xmlContext.getXType() != XML.XML_DOC_ANY)\r
+        {\r
+            throw StandardException.newException(\r
+                SQLState.LANG_INVALID_XML_CONTEXT_ITEM,\r
+                (returnResults ? "XMLQUERY" : "XMLEXISTS"));\r
+        } \r
+\r
+        Document docNode = null;\r
+        docNode = dBuilder.parse(\r
+            new InputSource(\r
+                new StringReader(xmlContext.getString())));\r
+\r
+        // Evaluate the expresion using Xalan.\r
+        getXPathContext();\r
+        xpContext.reset();\r
+        XObject xOb = query.execute(xpContext, docNode, null);\r
+\r
+        if (!returnResults)\r
+        {\r
+            // We don't want to return the actual results, we just\r
+            // want to know if there was at least one item in the\r
+            // result sequence.\r
+            if ((xOb instanceof XNodeSet) &&\r
+                (((XNodeSet)xOb).nodelist().getLength() > 0))\r
+            { // If we have a sequence (XNodeSet) of length greater\r
+              // than zero, then we know that at least one item\r
+              // "exists" in the result so return a non-null list.\r
+                return new ArrayList(0);\r
+            }\r
+            else if (!(xOb instanceof XNodeSet))\r
+            // we have a single atomic value, which means the result is\r
+            // non-empty.  So return a non-null list.\r
+                return new ArrayList(0);\r
+            else {\r
+            // return null; caller will take this to mean we have an\r
+            // an empty sequence.\r
+                return null;\r
+            }\r
+        }\r
+\r
+        // Else process the results.\r
+        NodeList nodeList = null;\r
+        int numItems = 0;\r
+        if (!(xOb instanceof XNodeSet))\r
+        // then we only have a single (probably atomic) item.\r
+            numItems = 1;\r
+        else {\r
+            nodeList = xOb.nodelist();\r
+            numItems = nodeList.getLength();\r
+        }\r
+\r
+        // Return a list of the items contained in the query results.\r
+        ArrayList itemRefs = new ArrayList();\r
+        if (nodeList == null)\r
+        // result is a single, non-node value (ex. it's an atomic number);\r
+        // in this case, just take the string value.\r
+            itemRefs.add(xOb.str());\r
+        else {\r
+            for (int i = 0; i < numItems; i++)\r
+                itemRefs.add(nodeList.item(i));\r
+        }\r
+\r
+        nodeList = null;\r
+\r
+        /* Indicate what kind of XML result value we have.  If\r
+         * we have a sequence of exactly one Document then it\r
+         * is XMLPARSE-able and so we consider it to be of type\r
+         * XML_DOC_ANY (which means we can store it in a Derby\r
+         * XML column).\r
+         */\r
+        if ((numItems == 1) && (itemRefs.get(0) instanceof Document))\r
+            resultXType[0] = XML.XML_DOC_ANY;\r
+        else\r
+            resultXType[0] = XML.XML_SEQUENCE;\r
+\r
+        return itemRefs;\r
+    }\r
+\r
+    /* ****\r
+     * Helper classes and methods.\r
+     * */\r
+\r
+    /**\r
+     * Create and return an instance of Xalan's XPathContext\r
+     * that can be used to compile an XPath expression.\r
+     */\r
+    private XPathContext getXPathContext()\r
+    {\r
+        if (xpContext == null)\r
+            xpContext = new XPathContext();\r
+\r
+        return xpContext;\r
+    }\r
+\r
+    /**\r
+     * Create an instance of Xalan serializer for the sake of\r
+     * serializing an XML value according the SQL/XML specification\r
+     * for serialization.\r
+     */\r
+    private void loadSerializer() throws java.io.IOException\r
+    {\r
+        java.io.StringWriter sWriter = new java.io.StringWriter();\r
+\r
+        // Set serialization properties.\r
+        Properties props = OutputProperties.getDefaultMethodProperties("xml");\r
+\r
+        // SQL/XML[2006] 10.15:General Rules:6 says method is "xml".\r
+        props.setProperty(OutputKeys.METHOD, "xml");\r
+\r
+        /* Since the XMLSERIALIZE operator doesn't currently support\r
+         * the DOCUMENT nor CONTENT keywords, SQL/XML spec says that\r
+         * the default is CONTENT (6.7:Syntax Rules:2.a).  Further,\r
+         * since the XMLSERIALIZE operator doesn't currently support the\r
+         * <XML declaration option> syntax, the SQL/XML spec says\r
+         * that the default for that option is "Unknown" (6.7:General\r
+         * Rules:2.f).  Put those together and that in turn means that\r
+         * the value of "OMIT XML DECLARATION" must be "Yes", as\r
+         * stated in section 10.15:General Rules:8.c.  SO, that's what\r
+         * we set here.\r
+         *\r
+         * NOTE: currently the only way to view the contents of an\r
+         * XML column is by using an explicit XMLSERIALIZE operator.\r
+         * This means that if an XML document is stored and it\r
+         * begins with an XML declaration, the user will never be\r
+         * able to _see_ that declaration after inserting the doc\r
+         * because, as explained above, our current support for\r
+         * XMLSERIALIZE dictates that the declaration must be\r
+         * omitted.  Similarly, other transformations that may\r
+         * occur from serialization (ex. entity replacement,\r
+         * attribute order, single-to-double quotes, etc)) will\r
+         * always be in effect for the string returned to the user;\r
+         * the original form of the XML document, if different\r
+         * from the serialized version, is not currently retrievable.\r
+         */\r
+        props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");\r
+\r
+        // We serialize everything as UTF-8 to match what we\r
+        // store on disk.\r
+        props.setProperty(OutputKeys.ENCODING, "UTF-8");\r
+\r
+        // Load the serializer with the correct properties.\r
+        serializer = SerializerFactory.getSerializer(props);\r
+        return;\r
+    }\r
+\r
+    /* ****\r
+     * Formatable interface implementation\r
+     * */\r
+\r
+    /** \r
+     * @see java.io.Externalizable#writeExternal \r
+     * \r
+     * @exception IOException on error\r
+     */\r
+    public void writeExternal(ObjectOutput out) \r
+        throws IOException\r
+    {\r
+        // query may be null\r
+        if (query == null)\r
+        {\r
+            out.writeBoolean(false);\r
+        }\r
+        else\r
+        {\r
+            out.writeBoolean(true);\r
+            out.writeObject(queryExpr);\r
+            out.writeObject(opName);\r
+        }\r
+    }\r
+\r
+    /** \r
+     * @see java.io.Externalizable#readExternal \r
+     *\r
+     * @exception IOException on error\r
+     * @exception ClassNotFoundException on error\r
+     */\r
+    public void readExternal(ObjectInput in) \r
+        throws IOException, ClassNotFoundException\r
+    {\r
+        if (in.readBoolean())\r
+        {\r
+            queryExpr = (String)in.readObject();\r
+            opName = (String)in.readObject();\r
+            recompileQuery = true;\r
+           }\r
+    }\r
+\r
+    /**\r
+     * Get the formatID which corresponds to this class.\r
+     *\r
+     * @return the formatID of this class\r
+     */\r
+    public int getTypeFormatId()\r
+    { \r
+        return StoredFormatIds.SQL_XML_UTIL_V01_ID;\r
+    }\r
+\r
+    /*\r
+     ** The XMLErrorHandler class is just a generic implementation\r
+     ** of the ErrorHandler interface.  It allows us to catch\r
+     ** and process XML parsing errors in a graceful manner.\r
+     */\r
+    private class XMLErrorHandler implements ErrorHandler\r
+    {\r
+        public void error (SAXParseException exception)\r
+            throws SAXException\r
+        {\r
+            throw new SAXException (exception);\r
+        }\r
+\r
+        public void fatalError (SAXParseException exception)\r
+            throws SAXException\r
+        {\r
+            throw new SAXException (exception);\r
+        }\r
+\r
+        public void warning (SAXParseException exception)\r
+            throws SAXException\r
+        {\r
+            throw new SAXException (exception);\r
+        }\r
+    }\r
+}\r