com.pivotal.gemfirexd.internal.iapi.types.SqlXmlUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of snappydata-store-core Show documentation
Show all versions of snappydata-store-core Show documentation
TIBCO ComputeDB store based off Pivotal GemFireXD
/*
Derby - Class com.pivotal.gemfirexd.internal.iapi.types.SqlXmlUtil
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to you 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.
*/
/*
* Changes for GemFireXD distributed data platform (some marked by "GemStone changes")
*
* Portions Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* 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. See accompanying
* LICENSE file.
*/
package com.pivotal.gemfirexd.internal.iapi.types;
import com.pivotal.gemfirexd.internal.iapi.error.StandardException;
import com.pivotal.gemfirexd.internal.iapi.reference.SQLState;
import com.pivotal.gemfirexd.internal.iapi.services.io.Formatable;
import com.pivotal.gemfirexd.internal.shared.common.StoredFormatIds;
import java.util.List;
import java.util.ArrayList;
import java.io.IOException;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.StringReader;
// -- JDBC 3.0 JAXP API classes.
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;
/* (original imports)
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.xml.utils.PrefixResolverDefault;
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. The initial check for the
* required XML classes can be found in XML.checkXMLRequirements().
*
* 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 final class SqlXmlUtil implements Formatable {
// Used to parse a string into an XML value (DOM); checks
// the well-formedness of the string while parsing.
private DocumentBuilder dBuilder;
// GemStone changes BEGIN
// most functionality now moved into SqlXmlHelper implementations
// that will provide the implementation depending on available ones
private final com.pivotal.gemfirexd.internal.engine.types
.SqlXmlHelper xmlHelper;
/* (original code)
// 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;
*/
// GemStone changes END
// Used to recompile the XPath expression when this formatable
// object is reconstructed. e.g.: SPS
private String queryExpr;
private String opName;
private boolean recompileQuery;
/**
* 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 = null;
try {
dBF = DocumentBuilderFactory.newInstance();
} catch (Throwable e) {
/* We assume that if we get an error creating the
* DocumentBuilderFactory, it's because there's no
* JAXP implementation. This can happen in the
* (admittedly unlikely) case where the classpath
* contains the JAXP _interfaces_ (ex. via xml-apis.jar)
* and the Xalan classes but does not actually
* contain a JAXP _implementation_. In that case the
* check in XML.checkXMLRequirements() will pass
* and this class (SqlXmlUtil) will be instantiated
* successfully--which is how we get to this constructor.
* But then attempts to create a DocumentBuilderFactory
* will fail, bringing us here. Note that we can't
* check for a valid JAXP implementation in the
* XML.checkXMLRequirements() method because we
* always want to allow the XML.java class to be
* instantiated, even if the required XML classes
* are not present--and that means that it (the
* XML class) cannot reference DocumentBuilder nor
* any of the JAXP classes directly.
*/
throw StandardException.newException(
SQLState.LANG_MISSING_XML_CLASSES, "JAXP");
}
dBF.setValidating(false);
dBF.setNamespaceAware(true);
// Load document builder that can be used for parsing XML.
dBuilder = dBF.newDocumentBuilder();
dBuilder.setErrorHandler(new XMLErrorHandler());
// GemStone changes BEGIN
this.xmlHelper = com.pivotal.gemfirexd.internal.engine.types
.SqlXmlHelperFactory.newInstance();
/* (original code)
// Load serializer for serializing XML into string according
// XML serialization rules.
loadSerializer();
*/
// GemStone changes END
} catch (StandardException se) {
// Just rethrow it.
throw se;
} catch (Throwable t) {
/* Must be something caused by JAXP or Xalan; wrap it in a
* StandardException and rethrow it. Note: we catch "Throwable"
* here to catch as many external errors as possible in order
* to minimize the chance of an uncaught JAXP/Xalan error (such
* as a NullPointerException) causing Derby to fail in a more
* serious way. In particular, an uncaught Java exception
* like NPE can result in Derby throwing "ERROR 40XT0: An
* internal error was identified by RawStore module" for all
* statements on the connection after the failure--which we
* clearly don't want. If we catch the error and wrap it,
* though, the statement will fail but Derby will continue to
* run as normal.
*/
throw StandardException.newException(
SQLState.LANG_UNEXPECTED_XML_EXCEPTION, t, t.getMessage());
}
}
/**
* 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, String opName)
throws StandardException
{
this.xmlHelper.compileXQExpr(queryExpr, opName, this.dBuilder);
this.queryExpr = queryExpr;
this.opName = opName;
this.recompileQuery = false;
}
/**
* 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.
*/
public String serializeToString(String xmlAsText)
throws Exception
{
ArrayList