Return-Path: Delivered-To: apmail-cocoon-dev-archive@www.apache.org Received: (qmail 79891 invoked from network); 18 Nov 2006 18:57:06 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 18 Nov 2006 18:57:06 -0000 Received: (qmail 33714 invoked by uid 500); 18 Nov 2006 18:57:14 -0000 Delivered-To: apmail-cocoon-dev-archive@cocoon.apache.org Received: (qmail 33660 invoked by uid 500); 18 Nov 2006 18:57:14 -0000 Mailing-List: contact dev-help@cocoon.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@cocoon.apache.org List-Id: Delivered-To: mailing list dev@cocoon.apache.org Received: (qmail 33649 invoked by uid 99); 18 Nov 2006 18:57:14 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 18 Nov 2006 10:57:14 -0800 X-ASF-Spam-Status: No, hits=2.0 required=10.0 tests=RCVD_IN_BL_SPAMCOP_NET,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (herse.apache.org: domain of gwk@home.nl designates 213.51.146.200 as permitted sender) Received: from [213.51.146.200] (HELO smtpq1.tilbu1.nb.home.nl) (213.51.146.200) by apache.org (qpsmtpd/0.29) with ESMTP; Sat, 18 Nov 2006 10:56:58 -0800 Received: from [213.51.146.189] (port=40346 helo=smtp2.tilbu1.nb.home.nl) by smtpq1.tilbu1.nb.home.nl with esmtp (Exim 4.30) id 1GlVMi-0001dt-Op; Sat, 18 Nov 2006 19:56:36 +0100 Received: from cp412192-b.dbsch1.nb.home.nl ([84.27.64.39]:51249 helo=jannet1) by smtp2.tilbu1.nb.home.nl with esmtp (Exim 4.30) id 1GlVMg-0001my-9U; Sat, 18 Nov 2006 19:56:34 +0100 From: "Geurt Wisselink" To: , References: <455F303A.6080907@danhertz.com> In-Reply-To: <455F303A.6080907@danhertz.com> Subject: RE: SQL Transformer Bug? Date: Sat, 18 Nov 2006 19:56:32 +0100 Message-ID: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_002B_01C70B4B.A5080F10" X-Mailer: Microsoft Office Outlook 12.0 Thread-Index: AccLK/oMQLp/HrIyRbi1cjv8UqTR3gAFbfUQ Content-Language: en-gb X-AtHome-MailScanner-Information: Neem contact op met support@home.nl voor meer informatie X-AtHome-MailScanner: Found to be clean X-Virus-Checked: Checked by ClamAV on apache.org This is a multipart message in MIME format. ------=_NextPart_000_002B_01C70B4B.A5080F10 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Dear Dan, I ran into the same problem and ended up modifying the transformer. I returned the modified version to the cocoon development group. I added two options to work with xml. The first was the original foreseen sql:xml construct. Basically it works like this: INSERT INTO mytable (nodeset) VALUES ('John SmithLondon'); In this way a string is created with the XML content in side. The second thing I added was the capability to work with xml variables by means of the sql:in-xml-parameter. It works like the standard in-parameter but is tailored to work with XML content. This works like: John SmithLondon INSERT INTO mytable (nodeset) VALUES (?); The modified SQLTransformer is added as attachment to this mail. Just put it src\blocks\databases\java\org\apache\cocoon\transformation, and rerun build. This last option is the best for last XML blocks, because the data is streamed to the database engine, instead of embedding it into a SQL query. I hope this helps. Kind regards, Geurt Wisselink -----Original Message----- From: Dan Hertz [mailto:dan@danhertz.com] Sent: 18 November 2006 17:10 To: dev@cocoon.apache.org Subject: SQL Transformer Bug? I'm hoping someone can help me troubleshoot why I can't insert an xml nodeset into my database using the SQL Transformer. All I end up with is the text() values concatenated together -- no elements or attribute nodes. For example: INSERT INTO mytable (nodeset) VALUES ('John SmithLondon'); would insert: 1JohnSmithLondon into my database. If I plug this query into my sql editor, I correctly get: John SmithLondon inserted into the database. What am I doing wrong? Thanks! ------=_NextPart_000_002B_01C70B4B.A5080F10 Content-Type: text/java; name="SQLTransformer.java" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="SQLTransformer.java" /*=0A= * Licensed to the Apache Software Foundation (ASF) under one or more=0A= * contributor license agreements. See the NOTICE file distributed with=0A= * this work for additional information regarding copyright ownership.=0A= * The ASF licenses this file to You under the Apache License, Version = 2.0=0A= * (the "License"); you may not use this file except in compliance with=0A= * the License. You may obtain a copy of the License at=0A= *=0A= * http://www.apache.org/licenses/LICENSE-2.0=0A= *=0A= * Unless required by applicable law or agreed to in writing, software=0A= * distributed under the License is distributed on an "AS IS" BASIS,=0A= * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or = implied.=0A= * See the License for the specific language governing permissions and=0A= * limitations under the License.=0A= */=0A= package org.apache.cocoon.transformation;=0A= =0A= import java.io.InputStream;=0A= import java.io.IOException;=0A= import java.io.Reader;=0A= import java.io.StringReader;=0A= import java.lang.reflect.Field;=0A= import java.sql.CallableStatement;=0A= import java.sql.Clob;=0A= import java.sql.Connection;=0A= import java.sql.DriverManager;=0A= import java.sql.PreparedStatement;=0A= import java.sql.ResultSet;=0A= import java.sql.ResultSetMetaData;=0A= import java.sql.SQLException;=0A= import java.util.HashMap;=0A= import java.util.Iterator;=0A= import java.util.Map;=0A= import java.util.Properties;=0A= import java.util.TreeMap;=0A= import java.util.List;=0A= import java.util.ArrayList;=0A= =0A= import org.apache.avalon.excalibur.datasource.DataSourceComponent;=0A= import org.apache.avalon.framework.configuration.Configuration;=0A= import org.apache.avalon.framework.configuration.ConfigurationException;=0A= import org.apache.avalon.framework.logger.AbstractLogEnabled;=0A= import org.apache.avalon.framework.parameters.Parameters;=0A= import org.apache.avalon.framework.service.ServiceException;=0A= import org.apache.avalon.framework.service.ServiceManager;=0A= import org.apache.avalon.framework.service.ServiceSelector;=0A= import org.apache.cocoon.ProcessingException;=0A= import org.apache.cocoon.components.sax.XMLDeserializer;=0A= import org.apache.cocoon.components.sax.XMLSerializer;=0A= import org.apache.cocoon.environment.SourceResolver;=0A= import org.apache.cocoon.transformation.helpers.TextRecorder;=0A= import org.apache.cocoon.xml.IncludeXMLConsumer;=0A= import org.apache.commons.lang.StringEscapeUtils;=0A= import org.apache.commons.lang.StringUtils;=0A= import org.apache.excalibur.xml.sax.SAXParser;=0A= import org.xml.sax.Attributes;=0A= import org.xml.sax.InputSource;=0A= import org.xml.sax.SAXException;=0A= import org.xml.sax.helpers.AttributesImpl;=0A= =0A= /**=0A= * The SQLTransformer can be plugged into a pipeline to = transform=0A= * SAX events into updated or queries and responses to/from a SQL = interface.=0A= *=0A= *

=0A= * It is declared and configured as follows:=0A= *

=0A=
 * <map:transformers default=3D"...">=0A=
 *   <map:transformer name=3D"sql" =
src=3D"org.apache.cocoon.transformation.SQLTransformer">=0A=
 *     <old-driver>false</old-driver>=0A=
 *     <connection-attempts>5</connection-attempts>=0A=
 *     <connection-waittime>5000</connection-waittime>=0A=
 *   </map:transformer>=0A=
 * </map:transformers>=0A=
 * 
=0A= *

=0A= *=0A= *

=0A= * It can be used in the sitemap pipeline as follows:=0A= * =0A= * <map:transform type=3D"sql">=0A= * =0A= * <map:parameter name=3D"own-connection" value=3D"..."/>=0A= * =0A= * <map:parameter name=3D"use-connection" value=3D"..."/>=0A= * =0A= * <map:parameter name=3D"dburl" value=3D"..."/>=0A= * <map:parameter name=3D"username" value=3D"..."/>=0A= * <map:parameter name=3D"password" value=3D"..."/>=0A= *=0A= * =0A= * <map:parameter name=3D"show-nr-or-rows" value=3D"false"/>=0A= * <map:parameter name=3D"doc-element" value=3D"rowset"/>=0A= * <map:parameter name=3D"row-element" value=3D"row"/>=0A= * <map:parameter name=3D"namespace-uri" = value=3D"http://apache.org/cocoon/SQL/2.0"/>=0A= * <map:parameter name=3D"namespace-prefix" value=3D"sql"/>=0A= * <map:parameter name=3D"clob-encoding" value=3D""/>=0A= * </map:transform>=0A= * =0A= *

=0A= *=0A= *

=0A= * The following DTD is valid:=0A= * =0A= * <!ENTITY % param = "(own-connection?,(use-connection|(dburl,username,password))?,show-nr-or-= rows?,doc-element?,row-element?,namespace-uri?,namespace-prefix?,clob-enc= oding?)">
=0A= * <!ELEMENT execute-query = (query,(in-parameter|in-xml-parameter|out-parameter)*,execute-query?, = %param;)>
=0A= * <!ELEMENT own-connection (#PCDATA)>
=0A= * <!ELEMENT use-connection (#PCDATA)>
=0A= * <!ELEMENT query (#PCDATA | substitute-value | ancestor-value | = escape-string| xml)*>
=0A= * <!ATTLIST query name CDATA #IMPLIED isstoredprocedure (true|false) = "false" isupdate (true|false) "false">
=0A= * <!ELEMENT substitute-value EMPTY>
=0A= * <!ATTLIST substitute-value name CDATA #REQUIRED>
=0A= * <!ELEMENT ancestor-value EMPTY>
=0A= * <!ATTLIST ancestor-value name CDATA #REQUIRED level CDATA = #REQUIRED>
=0A= * <!ELEMENT in-parameter EMPTY>
=0A= * <!ATTLIST in-parameter nr CDATA #REQUIRED type CDATA = #REQUIRED>
=0A= * <!ELEMENT in-xml-parameter EMPTY>
=0A= * <!ATTLIST in-xml-parameter nr CDATA #REQUIRED type CDATA = #REQUIRED>
=0A= * <!ELEMENT out-parameter EMPTY>
=0A= * <!ATTLIST out-parameter nr CDATA #REQUIRED name CDATA #REQUIRED = type CDATA #REQUIRED>
=0A= * <!ELEMENT escape-string (#PCDATA)>
=0A= * <!ELEMENT xml (#PCDATA)>
=0A= *
=0A= *

=0A= *=0A= *

=0A= * Each query can override default transformer parameters. Nested = queries do not inherit parent=0A= * query parameters, but only transformer parameters. Each query can = have connection to different=0A= * database, directly or using the connection pool. If database = connection parameters are the same=0A= * as for any of the ancestor queries, nested query will re-use ancestor = query connection.=0A= *

=0A= *=0A= *

=0A= * Connection sharing between queries can be disabled, globally or on = per-query basis, using=0A= * own-connection parameter.=0A= *

=0A= *=0A= *

=0A= * By default, CLOBs are read from the database using getSubString, so = that character=0A= * decoding is performed by the database. Using = clob-encoding parameter,=0A= * this behavior can be overrided, so that data is read as byte stream = and decoded using=0A= * specified character encoding.=0A= *

=0A= *=0A= *

=0A= * Inserting of XML data can be done by using the new sql:xml or = SQL:in-xml-parameter tags.=0A= * - sql:xml must be used like sql:escape-string=0A= * - sql:in-xml-parameter must be used like sql:in-parameter.=0A= *

=0A= *=0A= * @author Carsten Ziegeler=0A= * @author Donald Ball=0A= * @author Giacomo Pati=0A= * (PWR Organisation & Entwicklung)=0A= * @author Sven = Beauprez=0A= * @author Alfio = Saglimbeni=0A= * @author Philipp Hahn=0A= * @author Vadim Gritsenko=0A= * @version $Id: SQLTransformer.java 433543 2006-08-22 06:22:54Z = crossley $=0A= */=0A= public class SQLTransformer extends AbstractSAXTransformer {=0A= =0A= private static final int BUFFER_SIZE =3D 1024;=0A= =0A= /** The SQL transformer namespace */=0A= public static final String NAMESPACE =3D = "http://apache.org/cocoon/SQL/2.0";=0A= =0A= // The SQL trasformer namespace element names=0A= public static final String MAGIC_EXECUTE_QUERY =3D "execute-query";=0A= private static final String MAGIC_OWN_CONNECTION =3D = "own-connection";=0A= public static final String MAGIC_CONNECTION =3D "use-connection";=0A= public static final String MAGIC_DBURL =3D "dburl";=0A= public static final String MAGIC_USERNAME =3D "username";=0A= public static final String MAGIC_PROP =3D "prop";=0A= public static final String MAGIC_PASSWORD =3D "password";=0A= public static final String MAGIC_NR_OF_ROWS =3D "show-nr-of-rows";=0A= public static final String MAGIC_QUERY =3D "query";=0A= public static final String MAGIC_VALUE =3D "value";=0A= public static final String MAGIC_COLUMN_CASE =3D "column-case";=0A= public static final String MAGIC_DOC_ELEMENT =3D "doc-element";=0A= public static final String MAGIC_ROW_ELEMENT =3D "row-element";=0A= public static final String MAGIC_IN_PARAMETER =3D "in-parameter";=0A= public static final String MAGIC_IN_PARAMETER_NR_ATTRIBUTE =3D "nr";=0A= public static final String MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE =3D = "value";=0A= public static final String MAGIC_OUT_PARAMETER =3D "out-parameter";=0A= public static final String MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE =3D = "name";=0A= public static final String MAGIC_OUT_PARAMETER_NR_ATTRIBUTE =3D "nr";=0A= public static final String MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE =3D = "type";=0A= public static final String MAGIC_ESCAPE_STRING =3D "escape-string";=0A= public static final String MAGIC_XML =3D "xml";=0A= public static final String MAGIC_IN_XML_PARAMETER =3D = "in-xml-parameter";=0A= public static final String MAGIC_ERROR =3D "error";=0A= =0A= public static final String MAGIC_NS_URI_ELEMENT =3D "namespace-uri";=0A= public static final String MAGIC_NS_PREFIX_ELEMENT =3D = "namespace-prefix";=0A= =0A= public static final String MAGIC_ANCESTOR_VALUE =3D "ancestor-value";=0A= public static final String MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE =3D = "level";=0A= public static final String MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE =3D = "name";=0A= public static final String MAGIC_SUBSTITUTE_VALUE =3D = "substitute-value";=0A= public static final String MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE =3D = "name";=0A= public static final String MAGIC_NAME_ATTRIBUTE =3D "name";=0A= public static final String MAGIC_STORED_PROCEDURE_ATTRIBUTE =3D = "isstoredprocedure";=0A= public static final String MAGIC_UPDATE_ATTRIBUTE =3D "isupdate";=0A= public static final String CLOB_ENCODING =3D "clob-encoding";=0A= =0A= // The states we are allowed to be in=0A= protected static final int STATE_OUTSIDE =3D 0;=0A= protected static final int STATE_INSIDE_EXECUTE_QUERY_ELEMENT =3D 1;=0A= protected static final int STATE_INSIDE_VALUE_ELEMENT =3D 2;=0A= protected static final int STATE_INSIDE_QUERY_ELEMENT =3D 3;=0A= protected static final int STATE_INSIDE_ANCESTOR_VALUE_ELEMENT =3D 4;=0A= protected static final int STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT =3D = 5;=0A= protected static final int STATE_INSIDE_IN_PARAMETER_ELEMENT =3D 6;=0A= protected static final int STATE_INSIDE_OUT_PARAMETER_ELEMENT =3D 7;=0A= protected static final int STATE_INSIDE_ESCAPE_STRING =3D 8;=0A= protected static final int STATE_INSIDE_XML =3D 9;=0A= protected static final int STATE_INSIDE_IN_XML_PARAMETER_ELEMENT =3D = 10;=0A= =0A= //=0A= // Configuration=0A= //=0A= =0A= /** Is the old-driver turned on? (default is off) */=0A= protected boolean oldDriver;=0A= =0A= /** How many connection attempts to do? (default is 5 times) */=0A= protected int connectAttempts;=0A= =0A= /** How long wait between connection attempts? (default is 5000 ms) = */=0A= protected int connectWaittime;=0A= =0A= //=0A= // State=0A= //=0A= =0A= /** The current query we are working on */=0A= protected Query query;=0A= =0A= /** The current state of the event receiving FSM */=0A= protected int state;=0A= =0A= /** The datasource component selector */=0A= protected ServiceSelector datasources;=0A= =0A= /** The "name" of the connection shared by top level queries (if = configuration allows) */=0A= protected String connName;=0A= =0A= /** The connection shared by top level queries (if configuration = allows) */=0A= protected Connection conn;=0A= =0A= // Used to parse XML from database.=0A= protected XMLSerializer compiler;=0A= protected XMLDeserializer interpreter;=0A= protected SAXParser parser;=0A= =0A= /**=0A= * Constructor=0A= */=0A= public SQLTransformer() {=0A= super.defaultNamespaceURI =3D NAMESPACE;=0A= }=0A= =0A= //=0A= // Lifecycle Methods=0A= //=0A= =0A= /**=0A= * Serviceable=0A= */=0A= public void service(ServiceManager manager) throws ServiceException {=0A= super.service(manager);=0A= try {=0A= this.datasources =3D (ServiceSelector) = manager.lookup(DataSourceComponent.ROLE + "Selector");=0A= } catch (ServiceException e) {=0A= getLogger().warn("DataSource component selector is not = available.", e);=0A= }=0A= }=0A= =0A= /**=0A= * Configure transformer. Supported configuration elements:=0A= *
    =0A= *
  • old-driver
  • =0A= *
  • connect-attempts
  • =0A= *
  • connect-waittime
  • =0A= *
=0A= */=0A= public void configure(Configuration conf) throws = ConfigurationException {=0A= super.configure(conf);=0A= =0A= this.oldDriver =3D = conf.getChild("old-driver").getValueAsBoolean(false);=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("Value for old-driver is " + = this.oldDriver);=0A= }=0A= =0A= this.connectAttempts =3D = conf.getChild("connect-attempts").getValueAsInteger(5);=0A= this.connectWaittime =3D = conf.getChild("connect-waittime").getValueAsInteger(5000);=0A= }=0A= =0A= /**=0A= * Setup for the current request.=0A= */=0A= public void setup(SourceResolver resolver, Map objectModel,=0A= String source, Parameters parameters)=0A= throws ProcessingException, SAXException, IOException {=0A= super.setup(resolver, objectModel, source, parameters);=0A= =0A= // Setup instance variables=0A= this.state =3D SQLTransformer.STATE_OUTSIDE;=0A= this.connName =3D name(super.parameters);=0A= }=0A= =0A= /**=0A= * Recycle this component=0A= */=0A= public void recycle() {=0A= this.query =3D null;=0A= try {=0A= // Close the connection used by all top level queries=0A= if (this.conn !=3D null) {=0A= this.conn.close();=0A= this.conn =3D null;=0A= }=0A= } catch (SQLException e) {=0A= getLogger().info("Could not close connection", e);=0A= }=0A= this.connName =3D null;=0A= =0A= this.manager.release(this.parser);=0A= this.parser =3D null;=0A= this.manager.release(this.compiler);=0A= this.compiler =3D null;=0A= this.manager.release(this.interpreter);=0A= this.interpreter =3D null;=0A= =0A= super.recycle();=0A= }=0A= =0A= /**=0A= * Dispose=0A= */=0A= public void dispose() {=0A= if (this.datasources !=3D null) {=0A= this.manager.release(this.datasources);=0A= this.datasources =3D null;=0A= }=0A= super.dispose();=0A= }=0A= =0A= /**=0A= * Return attribute value.=0A= * First try non-namespaced attribute, then try this transformer = namespace.=0A= * @param name local attribute name=0A= */=0A= private String getAttributeValue(Attributes attr, String name) {=0A= String value =3D attr.getValue("", name);=0A= if (value =3D=3D null) {=0A= value =3D attr.getValue(this.namespaceURI, name);=0A= }=0A= =0A= return value;=0A= }=0A= =0A= //=0A= // SAX Events Handlers=0A= //=0A= =0A= protected static void throwIllegalStateException(String message) {=0A= throw new IllegalStateException("Illegal state: " + message);=0A= }=0A= =0A= /** <execute-query> */=0A= protected void startExecuteQueryElement() {=0A= switch (state) {=0A= case SQLTransformer.STATE_OUTSIDE:=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= // Create root query (if query =3D=3D null), or child = query=0A= this.query =3D new Query(this.query);=0A= = this.query.enableLogging(getLogger().getChildLogger("query"));=0A= state =3D = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start = execute query element");=0A= }=0A= }=0A= =0A= /** <*> */=0A= protected void startValueElement(String name)=0A= throws SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= this.stack.push(name);=0A= startTextRecording();=0A= state =3D SQLTransformer.STATE_INSIDE_VALUE_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start value = element: " + name);=0A= }=0A= }=0A= =0A= /** <query> */=0A= protected void startQueryElement(Attributes attributes)=0A= throws SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= startTextRecording();=0A= state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;=0A= =0A= String isUpdate =3D attributes.getValue("", = SQLTransformer.MAGIC_UPDATE_ATTRIBUTE);=0A= if (isUpdate !=3D null && = !isUpdate.equalsIgnoreCase("false")) {=0A= query.setUpdate(true);=0A= }=0A= =0A= String isProcedure =3D attributes.getValue("", = SQLTransformer.MAGIC_STORED_PROCEDURE_ATTRIBUTE);=0A= if (isProcedure !=3D null && = !isProcedure.equalsIgnoreCase("false")) {=0A= query.setStoredProcedure(true);=0A= }=0A= =0A= String name =3D attributes.getValue("", = SQLTransformer.MAGIC_NAME_ATTRIBUTE);=0A= if (name !=3D null) {=0A= query.setName(name);=0A= }=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start query = element");=0A= }=0A= }=0A= =0A= /** </query> */=0A= protected void endQueryElement()=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:=0A= final String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= query.addQueryPart(value);=0A= }=0A= state =3D = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a stop query = element");=0A= }=0A= }=0A= =0A= /** </*> */=0A= protected void endValueElement()=0A= throws SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_VALUE_ELEMENT:=0A= final String name =3D (String) this.stack.pop();=0A= final String value =3D endTextRecording();=0A= query.setParameter(name, value);=0A= this.state =3D = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting an end value = element");=0A= }=0A= }=0A= =0A= /** </execute-query> */=0A= protected void endExecuteQueryElement() throws SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= if (query.parent =3D=3D null) {=0A= query.executeQuery();=0A= query =3D null;=0A= state =3D SQLTransformer.STATE_OUTSIDE;=0A= } else {=0A= query.parent.addNestedQuery(query);=0A= query =3D query.parent;=0A= state =3D = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= }=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting an end execute = query element");=0A= }=0A= }=0A= =0A= /** <ancestor-value> */=0A= protected void startAncestorValueElement(Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:=0A= int level =3D 0;=0A= try {=0A= level =3D = Integer.parseInt(getAttributeValue(attributes, = SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE));=0A= } catch (Exception e) {=0A= getLogger().debug("Invalid or missing value for " + = SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE + " attribute", e);=0A= throwIllegalStateException("Ancestor value elements = must have a " +=0A= = SQLTransformer.MAGIC_ANCESTOR_VALUE_LEVEL_ATTRIBUTE + " attribute");=0A= }=0A= =0A= String name =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE);=0A= if (name =3D=3D null) {=0A= throwIllegalStateException("Ancestor value elements = must have a " +=0A= = SQLTransformer.MAGIC_ANCESTOR_VALUE_NAME_ATTRIBUTE + " attribute");=0A= }=0A= =0A= final String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= query.addQueryPart(value);=0A= }=0A= query.addQueryPart(new AncestorValue(level, name));=0A= startTextRecording();=0A= =0A= state =3D = SQLTransformer.STATE_INSIDE_ANCESTOR_VALUE_ELEMENT;=0A= break;=0A= default:=0A= throwIllegalStateException("Not expecting a start = ancestor value element");=0A= }=0A= }=0A= =0A= /** </ancestor-value> */=0A= protected void endAncestorValueElement() {=0A= state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;=0A= }=0A= =0A= /** <substitute-value> */=0A= protected void startSubstituteValueElement(Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:=0A= String name =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE);=0A= if (name =3D=3D null) {=0A= throwIllegalStateException("Substitute value = elements must have a " +=0A= = SQLTransformer.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE + " attribute");=0A= }=0A= String substitute =3D parameters.getParameter(name, = null);=0A= // Escape single quote=0A= substitute =3D StringEscapeUtils.escapeSql(substitute);=0A= =0A= final String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= query.addQueryPart(value);=0A= }=0A= query.addQueryPart(substitute);=0A= startTextRecording();=0A= =0A= state =3D = SQLTransformer.STATE_INSIDE_SUBSTITUTE_VALUE_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start = substitute value element");=0A= }=0A= }=0A= =0A= /** </substitute-value> */=0A= protected void endSubstituteValueElement() {=0A= state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;=0A= }=0A= =0A= /** <escape-string> */=0A= protected void startEscapeStringElement(Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:=0A= final String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= query.addQueryPart(value);=0A= }=0A= startTextRecording();=0A= =0A= state =3D SQLTransformer.STATE_INSIDE_ESCAPE_STRING;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start = escape-string element");=0A= }=0A= }=0A= =0A= /** </escape-string> */=0A= protected void endEscapeStringElement()=0A= throws SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_ESCAPE_STRING:=0A= String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= value =3D StringEscapeUtils.escapeSql(value);=0A= value =3D StringUtils.replace(value, "\\", "\\\\");=0A= query.addQueryPart(value);=0A= }=0A= startTextRecording();=0A= state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a end = escape-string element");=0A= }=0A= }=0A= =0A= /** <xml> */=0A= protected void startXmlElement(Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT:=0A= final String value =3D endTextRecording();=0A= if (value.length() > 0) {=0A= query.addQueryPart(value);=0A= }=0A= startSerializedXMLRecording( null);=0A= =0A= state =3D SQLTransformer.STATE_INSIDE_XML;=0A= //this.getLogger().info("startXmlElement: ");=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start = escape-string element");=0A= }=0A= }=0A= =0A= /** </xml> */=0A= protected void endXmlElement()=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_XML:=0A= String value =3D endSerializedXMLRecording();=0A= //this.getLogger().info("endXmlElement: "+value);=0A= if (value.length() > 0) {=0A= /*value =3D StringUtils.replace(value, "&", "&");=0A= value =3D StringUtils.replace(value, "<", "<");=0A= value =3D StringUtils.replace(value, ">", ">");*/=0A= value =3D StringEscapeUtils.escapeSql(value);=0A= query.addQueryPart(value);=0A= }=0A= startTextRecording();=0A= state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a end = escape-string element");=0A= }=0A= }=0A= =0A= /** <xml> */=0A= protected void startInXmlParameterElement(Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= String nr =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_IN_PARAMETER_NR_ATTRIBUTE);=0A= this.stack.push(nr);=0A= startSerializedXMLRecording( null);=0A= =0A= state =3D = SQLTransformer.STATE_INSIDE_IN_XML_PARAMETER_ELEMENT;=0A= //this.getLogger().info("startXmlElement: ");=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a start = escape-string element");=0A= }=0A= }=0A= =0A= /** </xml> */=0A= protected void endInXmlParameterElement()=0A= throws ProcessingException, SAXException {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_IN_XML_PARAMETER_ELEMENT:=0A= String value =3D endSerializedXMLRecording();=0A= //this.getLogger().info("endXmlElement: "+value);=0A= if (value.length() > 0) {=0A= int position =3D = Integer.parseInt((String)this.stack.pop());=0A= query.setInXmlParameter(position, value);=0A= }=0A= state =3D = SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting a end = escape-string element");=0A= }=0A= }=0A= =0A= /** <in-parameter> */=0A= protected void startInParameterElement(Attributes attributes) {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= String nr =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_IN_PARAMETER_NR_ATTRIBUTE);=0A= String value =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE);=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("IN PARAMETER NR " + nr + "; VALUE = " + value);=0A= }=0A= =0A= int position =3D Integer.parseInt(nr);=0A= query.setInParameter(position, value);=0A= state =3D = SQLTransformer.STATE_INSIDE_IN_PARAMETER_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting an = in-parameter element");=0A= }=0A= }=0A= =0A= /** </in-parameter> */=0A= protected void endInParameterElement() {=0A= state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= }=0A= =0A= /** <out-parameter> */=0A= protected void startOutParameterElement(Attributes attributes) {=0A= switch (state) {=0A= case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT:=0A= String name =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE);=0A= String nr =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_OUT_PARAMETER_NR_ATTRIBUTE);=0A= String type =3D getAttributeValue(attributes, = SQLTransformer.MAGIC_OUT_PARAMETER_TYPE_ATTRIBUTE);=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("OUT PARAMETER NAME" + name + ";NR = " + nr + "; TYPE " + type);=0A= }=0A= =0A= int position =3D Integer.parseInt(nr);=0A= query.setOutParameter(position, type, name);=0A= state =3D = SQLTransformer.STATE_INSIDE_OUT_PARAMETER_ELEMENT;=0A= break;=0A= =0A= default:=0A= throwIllegalStateException("Not expecting an = out-parameter element");=0A= }=0A= }=0A= =0A= /** </out-parameter> */=0A= protected void endOutParameterElement() {=0A= state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT;=0A= }=0A= =0A= /**=0A= * ContentHandler method=0A= */=0A= public void startTransformingElement(String uri, String name, String = raw, Attributes attributes)=0A= throws ProcessingException, SAXException {=0A= if (name.equals(SQLTransformer.MAGIC_EXECUTE_QUERY)) {=0A= startExecuteQueryElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_QUERY)) {=0A= startQueryElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_ANCESTOR_VALUE)) {=0A= startAncestorValueElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_SUBSTITUTE_VALUE)) {=0A= startSubstituteValueElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_IN_PARAMETER)) {=0A= startInParameterElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_OUT_PARAMETER)) {=0A= startOutParameterElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_ESCAPE_STRING)) {=0A= startEscapeStringElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_XML)) {=0A= startXmlElement(attributes);=0A= } else if (name.equals(SQLTransformer.MAGIC_IN_XML_PARAMETER)) {=0A= startInXmlParameterElement(attributes);=0A= } else {=0A= startValueElement(name);=0A= }=0A= }=0A= =0A= /**=0A= * ContentHandler method=0A= */=0A= public void endTransformingElement(String uri, String name, String = raw)=0A= throws ProcessingException, IOException, SAXException {=0A= if (name.equals(SQLTransformer.MAGIC_EXECUTE_QUERY)) {=0A= endExecuteQueryElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_QUERY)) {=0A= endQueryElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_ANCESTOR_VALUE)) {=0A= endAncestorValueElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_SUBSTITUTE_VALUE)) {=0A= endSubstituteValueElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_IN_PARAMETER)) {=0A= endInParameterElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_OUT_PARAMETER)) {=0A= endOutParameterElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_ESCAPE_STRING)) {=0A= endEscapeStringElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_XML)) {=0A= endXmlElement();=0A= } else if (name.equals(SQLTransformer.MAGIC_IN_XML_PARAMETER)) {=0A= endInXmlParameterElement();=0A= } else {=0A= endValueElement();=0A= }=0A= }=0A= =0A= //=0A= // Helper methods for the Query=0A= //=0A= =0A= /**=0A= * Qualifies an element name by giving it a prefix.=0A= * @param name the element name=0A= * @param prefix the prefix to qualify with=0A= * @return a namespace qualified name that is correct=0A= */=0A= protected String nsQualify(String name, String prefix) {=0A= if (StringUtils.isEmpty(name)) {=0A= return name;=0A= }=0A= =0A= if (StringUtils.isNotEmpty(prefix)) {=0A= return prefix + ":" + name;=0A= }=0A= =0A= return name;=0A= }=0A= =0A= /**=0A= * Helper method for generating SAX events=0A= */=0A= protected void start(String uri, String prefix, String name, = Attributes attr)=0A= throws SAXException {=0A= try {=0A= super.startTransformingElement(uri, name, nsQualify(name, = prefix), attr);=0A= } catch (IOException e) {=0A= throw new SAXException(e);=0A= } catch (ProcessingException e) {=0A= throw new SAXException(e);=0A= }=0A= }=0A= =0A= /**=0A= * Helper method for generating SAX events=0A= */=0A= protected void end(String uri, String prefix, String name) throws = SAXException {=0A= try {=0A= super.endTransformingElement(uri, name, nsQualify(name, = prefix));=0A= } catch (IOException e) {=0A= throw new SAXException(e);=0A= } catch (ProcessingException e) {=0A= throw new SAXException(e);=0A= }=0A= }=0A= =0A= /**=0A= * Helper method for generating SAX events=0A= */=0A= protected void data(String data) throws SAXException {=0A= if (data !=3D null) {=0A= super.characters(data.toCharArray(), 0, data.length());=0A= }=0A= }=0A= =0A= /**=0A= * Get 'name' for the connection which can be obtained using provided=0A= * connection parameters.=0A= */=0A= private String name(Parameters params) {=0A= final boolean ownConnection =3D = params.getParameterAsBoolean(SQLTransformer.MAGIC_OWN_CONNECTION, false);=0A= if (ownConnection) {=0A= return null;=0A= }=0A= =0A= final String datasourceName =3D = params.getParameter(SQLTransformer.MAGIC_CONNECTION, null);=0A= if (datasourceName !=3D null) {=0A= return "ds:" + datasourceName;=0A= }=0A= =0A= final String dburl =3D = params.getParameter(SQLTransformer.MAGIC_DBURL, null);=0A= if (dburl !=3D null) {=0A= final String username =3D = params.getParameter(SQLTransformer.MAGIC_USERNAME, null);=0A= final String password =3D = params.getParameter(SQLTransformer.MAGIC_PASSWORD, null);=0A= =0A= if (username =3D=3D null || password =3D=3D null) {=0A= return "db:@" + dburl;=0A= } else {=0A= return "db:" + username + ":" + password + "@" + dburl;=0A= }=0A= }=0A= =0A= // Nothing configured=0A= return "";=0A= }=0A= =0A= /**=0A= * Open database connection using provided parameters.=0A= * Return null if neither datasource nor jndi URL configured.=0A= */=0A= private Connection open(Parameters params) throws SQLException {=0A= Connection result =3D null;=0A= =0A= // First check datasource name parameter=0A= final String datasourceName =3D = params.getParameter(SQLTransformer.MAGIC_CONNECTION, null);=0A= if (datasourceName !=3D null) {=0A= // Use datasource components=0A= if (this.datasources =3D=3D null) {=0A= throw new SQLException("Unable to get connection from = datasource '" + datasourceName + "': " +=0A= "No datasources configured in = cocoon.xconf.");=0A= }=0A= =0A= DataSourceComponent datasource =3D null;=0A= try {=0A= datasource =3D (DataSourceComponent) = this.datasources.select(datasourceName);=0A= for (int i =3D 0; i < this.connectAttempts && result = =3D=3D null; i++) {=0A= try {=0A= result =3D datasource.getConnection();=0A= } catch (SQLException e) {=0A= if (i + 1 < this.connectAttempts) {=0A= final long waittime =3D this.connectWaittime;=0A= // Log exception if debug enabled.=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().info("Unable to get = connection; waiting " +=0A= waittime + "ms to try = again.", e);=0A= } else {=0A= getLogger().info("Unable to get = connection; waiting " +=0A= waittime + "ms to try = again.");=0A= }=0A= try {=0A= Thread.sleep(waittime);=0A= } catch (InterruptedException ex) {=0A= /* ignored */=0A= }=0A= }=0A= }=0A= }=0A= } catch (ServiceException e) {=0A= throw new SQLException("Unable to get connection from = datasource '" + datasourceName + "': " +=0A= "No such datasource.");=0A= } finally {=0A= if (datasource !=3D null) {=0A= this.datasources.release(datasource);=0A= }=0A= }=0A= =0A= if (result =3D=3D null) {=0A= throw new SQLException("Failed to obtain connection from = datasource '" + datasourceName + "'. " +=0A= "Made " + this.connectAttempts + = " attempts with "=0A= + this.connectWaittime + "ms = interval");=0A= }=0A= } else {=0A= // Then, check connection URL parameter=0A= final String dburl =3D = params.getParameter(SQLTransformer.MAGIC_DBURL, null);=0A= if (dburl !=3D null) {=0A= final String username =3D = params.getParameter(SQLTransformer.MAGIC_USERNAME, null);=0A= final String password =3D = params.getParameter(SQLTransformer.MAGIC_PASSWORD, null);=0A= final String prop =3D = params.getParameter(SQLTransformer.MAGIC_PROP, null);=0A= =0A= if (username =3D=3D null || password =3D=3D null) {=0A= result =3D DriverManager.getConnection(dburl);=0A= } else {=0A= if (prop =3D=3D null) {=0A= result =3D DriverManager.getConnection(dburl, = username, password);=0A= } else {=0A= Properties props =3D new Properties();=0A= props.put("user", username );=0A= props.put("password", password);=0A= int proppos =3D prop.indexOf('=3D');=0A= if (proppos > 0) {=0A= String propname =3D prop.substring(0, proppos);=0A= String propvalue =3D prop.substring(proppos+1);=0A= props.put(propname, propvalue);=0A= }=0A= result =3D DriverManager.getConnection(dburl, props);=0A= }=0A= }=0A= } else {=0A= // Nothing configured=0A= }=0A= }=0A= =0A= return result;=0A= }=0A= =0A= /**=0A= * Attempt to parse string value=0A= */=0A= private void stream(String value) throws ServiceException, = SAXException, IOException {=0A= try {=0A= // Strip off the XML Declaration if there is one!=0A= if (value.startsWith("") + 2);=0A= }=0A= =0A= // Lookup components=0A= if (this.parser =3D=3D null) {=0A= this.parser =3D (SAXParser) = manager.lookup(SAXParser.ROLE);=0A= }=0A= if (this.compiler =3D=3D null) {=0A= this.compiler =3D (XMLSerializer) = manager.lookup(XMLSerializer.ROLE);=0A= }=0A= if (this.interpreter =3D=3D null) {=0A= this.interpreter =3D (XMLDeserializer) = manager.lookup(XMLDeserializer.ROLE);=0A= }=0A= =0A= this.parser.parse(new InputSource(new StringReader("" = + value + "")),=0A= this.compiler);=0A= =0A= IncludeXMLConsumer filter =3D new IncludeXMLConsumer(this, = this);=0A= filter.setIgnoreRootElement(true);=0A= =0A= this.interpreter.setConsumer(filter);=0A= this.interpreter.deserialize(this.compiler.getSAXFragment());=0A= } finally {=0A= // otherwise serializer won't be reset=0A= if (this.compiler !=3D null) {=0A= manager.release(this.compiler);=0A= this.compiler =3D null;=0A= }=0A= }=0A= }=0A= =0A= /**=0A= * One of the queries in the query tree formed from nested queries.=0A= */=0A= private class Query extends AbstractLogEnabled {=0A= =0A= /** Parent query, or null for top level query */=0A= protected Query parent;=0A= =0A= /** Nested sub-queries we have. */=0A= protected final List nested =3D new ArrayList();=0A= =0A= /** The parts of the query */=0A= protected final List parts =3D new ArrayList();=0A= =0A= //=0A= // Query Configuration=0A= //=0A= =0A= /** Name of the query */=0A= protected String name;=0A= =0A= /** If this query is actually an update (insert, update, delete) = */=0A= protected boolean isUpdate;=0A= =0A= /** If this query is actually a stored procedure */=0A= protected boolean isStoredProcedure;=0A= =0A= /** Query configuration parameters */=0A= protected Parameters params;=0A= =0A= /** The namespace uri of the XML output. Defaults to {@link = SQLTransformer#namespaceURI}. */=0A= protected String outUri;=0A= =0A= /** The namespace prefix of the XML output. Defaults to 'sql'. */=0A= protected String outPrefix;=0A= =0A= /** rowset element name */=0A= protected String rowsetElement;=0A= =0A= /** row element name */=0A= protected String rowElement;=0A= =0A= /** number of rows attribute name */=0A= protected String nrOfRowsAttr =3D "nrofrows";=0A= =0A= /** Query name attribute name */=0A= protected String nameAttr =3D "name";=0A= =0A= /** Handling of case of column names in results */=0A= protected int columnCase;=0A= =0A= /** Registered IN parameters */=0A= protected Map inParameters;=0A= =0A= /** Registered IN XML parameters */=0A= protected Map inXmlParameters;=0A= =0A= /** Registered OUT parameters */=0A= protected Map outParameters;=0A= =0A= /** Mapping out parameters - objectModel */=0A= protected Map outParametersNames;=0A= =0A= /** Check if nr of rows need to be written out. */=0A= protected boolean showNrOfRows;=0A= =0A= /** Encoding we use for CLOB field */=0A= protected String clobEncoding;=0A= =0A= //=0A= // Query State=0A= //=0A= =0A= /** The connection */=0A= protected Connection conn;=0A= =0A= /** The 'name' of the connection */=0A= protected String connName;=0A= =0A= /** Is it our own connection? */=0A= protected boolean ownConn;=0A= =0A= /** Prepared statement */=0A= protected PreparedStatement pst;=0A= =0A= /** Callable statement */=0A= protected CallableStatement cst;=0A= =0A= /** The results, of course */=0A= protected ResultSet rs;=0A= =0A= /** And the results' metadata */=0A= protected ResultSetMetaData md;=0A= =0A= /** If it is an update/etc, the return value (num rows modified) = */=0A= protected int rv =3D -1;=0A= =0A= =0A= protected Query(Query parent) {=0A= this.parent =3D parent;=0A= this.params =3D new Parameters();=0A= this.params.merge(SQLTransformer.this.parameters);=0A= }=0A= =0A= /** Add nested sub-query. */=0A= protected void addNestedQuery(Query query) {=0A= nested.add(query);=0A= }=0A= =0A= protected void addQueryPart(Object value) {=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("Adding query part \"" + value + "\"");=0A= }=0A= parts.add(value);=0A= }=0A= =0A= protected String getName() {=0A= return name;=0A= }=0A= =0A= protected void setName(String name) {=0A= this.name =3D name;=0A= }=0A= =0A= protected void setParameter(String name, String value) {=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("Adding parameter name {" + name + "} = value {" + value + "}");=0A= }=0A= params.setParameter(name, value);=0A= }=0A= =0A= protected void setUpdate(boolean flag) {=0A= isUpdate =3D flag;=0A= }=0A= =0A= protected void setStoredProcedure(boolean flag) {=0A= isStoredProcedure =3D flag;=0A= }=0A= =0A= protected void setInParameter(int pos, String val) {=0A= if (inParameters =3D=3D null) {=0A= inParameters =3D new HashMap();=0A= }=0A= inParameters.put(new Integer(pos), val);=0A= }=0A= =0A= protected void setInXmlParameter(int pos, String val) {=0A= if (inXmlParameters =3D=3D null) {=0A= inXmlParameters =3D new HashMap();=0A= }=0A= inXmlParameters.put(new Integer(pos), val);=0A= }=0A= =0A= protected void setOutParameter(int pos, String type, String = name) {=0A= if (outParameters =3D=3D null) {=0A= // make sure output parameters are ordered=0A= outParameters =3D new TreeMap();=0A= outParametersNames =3D new HashMap();=0A= }=0A= outParameters.put(new Integer(pos), type);=0A= outParametersNames.put(new Integer(pos), name);=0A= }=0A= =0A= private void setColumnCase(String columnCase) {=0A= if (columnCase.equals("lowercase")) {=0A= this.columnCase =3D -1;=0A= } else if (columnCase.equals("uppercase")) {=0A= this.columnCase =3D +1;=0A= } else if (columnCase.equals("preserve")) {=0A= // Do nothing=0A= this.columnCase =3D 0;=0A= } else {=0A= getLogger().warn("[" + columnCase + "] is not a valid = value for . " +=0A= "Column name retrieved from database = will be used.");=0A= }=0A= }=0A= =0A= private void registerInParameters() throws SQLException {=0A= if (inParameters =3D=3D null) {=0A= return;=0A= }=0A= =0A= Iterator i =3D inParameters.keySet().iterator();=0A= while (i.hasNext()) {=0A= Integer counter =3D (Integer) i.next();=0A= String value =3D (String) inParameters.get(counter);=0A= try {=0A= pst.setObject(counter.intValue(), value);=0A= } catch (SQLException e) {=0A= getLogger().error("Caught a SQLException", e);=0A= throw e;=0A= }=0A= }=0A= }=0A= =0A= private void registerInXmlParameters() throws SQLException {=0A= if (inXmlParameters =3D=3D null) {=0A= return;=0A= }=0A= =0A= Iterator i =3D inXmlParameters.keySet().iterator();=0A= while (i.hasNext()) {=0A= Integer counter =3D (Integer) i.next();=0A= String value =3D (String) inXmlParameters.get(counter);=0A= try {=0A= //XMLType xt =3D XMLType.createXML(conn, value);=0A= //pst.setObject(counter.intValue(), xt);=0A= pst.setString(counter.intValue(), value);=0A= } catch (SQLException e) {=0A= getLogger().error("Caught a SQLException", e);=0A= throw e;=0A= }=0A= }=0A= }=0A= =0A= private void registerOutParameters(CallableStatement cst) throws = SQLException {=0A= if (outParameters =3D=3D null) {=0A= return;=0A= }=0A= =0A= Iterator i =3D outParameters.keySet().iterator();=0A= while (i.hasNext()) {=0A= Integer counter =3D (Integer) i.next();=0A= String type =3D (String) outParameters.get(counter);=0A= =0A= int index =3D type.lastIndexOf(".");=0A= String className, fieldName;=0A= if (index =3D=3D -1) {=0A= getLogger().error("Invalid SQLType: " + type, null);=0A= throw new SQLException("Invalid SQLType: " + type);=0A= }=0A= className =3D type.substring(0, index);=0A= fieldName =3D type.substring(index + 1, type.length());=0A= =0A= try {=0A= Class clss =3D Class.forName(className);=0A= Field fld =3D clss.getField(fieldName);=0A= cst.registerOutParameter(counter.intValue(), = fld.getInt(fieldName));=0A= } catch (Exception e) {=0A= // Lots of different exceptions to catch=0A= getLogger().error("Invalid SQLType: " + className + = "." + fieldName, e);=0A= }=0A= }=0A= }=0A= =0A= /**=0A= * Open database connection=0A= */=0A= private void open() throws SQLException {=0A= this.connName =3D SQLTransformer.this.name(this.params);=0A= =0A= // Check first if connection sharing disabled=0A= if (this.connName =3D=3D null) {=0A= this.conn =3D SQLTransformer.this.open(this.params);=0A= this.ownConn =3D true;=0A= return;=0A= }=0A= =0A= // Iterate through parent queries and get appropriate = connection=0A= Query query =3D this.parent;=0A= while (query !=3D null) {=0A= if (this.connName.equals(query.connName)) {=0A= this.conn =3D query.conn;=0A= this.ownConn =3D false;=0A= return;=0A= }=0A= query =3D query.parent;=0A= }=0A= =0A= // Check 'global' connection=0A= if (this.connName.equals(SQLTransformer.this.connName)) {=0A= // Use SQLTransformer configuration: it has same = connection parameters=0A= if (SQLTransformer.this.conn =3D=3D null) {=0A= SQLTransformer.this.conn =3D = SQLTransformer.this.open(SQLTransformer.this.parameters);=0A= }=0A= =0A= this.conn =3D SQLTransformer.this.conn;=0A= this.ownConn =3D false;=0A= return;=0A= }=0A= =0A= // Create own connection=0A= this.conn =3D SQLTransformer.this.open(this.params);=0A= this.ownConn =3D true;=0A= }=0A= =0A= /**=0A= * This will be the meat of SQLTransformer, where the query is = run.=0A= */=0A= protected void executeQuery() throws SAXException {=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("Executing query " + this);=0A= }=0A= =0A= this.outUri =3D = this.params.getParameter(SQLTransformer.MAGIC_NS_URI_ELEMENT, = SQLTransformer.this.namespaceURI);=0A= this.outPrefix =3D = this.params.getParameter(SQLTransformer.MAGIC_NS_PREFIX_ELEMENT, "sql");=0A= this.rowsetElement =3D = this.params.getParameter(SQLTransformer.MAGIC_DOC_ELEMENT, "rowset");=0A= this.rowElement =3D = this.params.getParameter(SQLTransformer.MAGIC_ROW_ELEMENT, "row");=0A= =0A= this.showNrOfRows =3D = parameters.getParameterAsBoolean(SQLTransformer.MAGIC_NR_OF_ROWS, false);=0A= this.clobEncoding =3D = parameters.getParameter(SQLTransformer.CLOB_ENCODING, "");=0A= if (this.clobEncoding.length() =3D=3D 0) {=0A= this.clobEncoding =3D null;=0A= }=0A= =0A= // Start prefix mapping for output namespace, only if it's = not mapped yet=0A= final String prefix =3D = SQLTransformer.this.findPrefixMapping(this.outUri);=0A= if (prefix =3D=3D null) {=0A= SQLTransformer.this.startPrefixMapping(this.outPrefix, = this.outUri);=0A= } else {=0A= this.outPrefix =3D prefix;=0A= }=0A= =0A= boolean success =3D false;=0A= try {=0A= try {=0A= open();=0A= execute();=0A= success =3D true;=0A= } catch (SQLException e) {=0A= getLogger().info("Failed to execute query " + this, = e);=0A= start(this.rowsetElement, EMPTY_ATTRIBUTES);=0A= start(MAGIC_ERROR, EMPTY_ATTRIBUTES);=0A= data(e.getMessage());=0A= end(MAGIC_ERROR);=0A= end(this.rowsetElement);=0A= }=0A= =0A= if (success) {=0A= AttributesImpl attr =3D new AttributesImpl();=0A= if (showNrOfRows) {=0A= attr.addAttribute("", this.nrOfRowsAttr, = this.nrOfRowsAttr, "CDATA", String.valueOf(getNrOfRows()));=0A= }=0A= String name =3D getName();=0A= if (name !=3D null) {=0A= attr.addAttribute("", this.nameAttr, = this.nameAttr, "CDATA", name);=0A= }=0A= start(this.rowsetElement, attr);=0A= =0A= // Serialize stored procedure output parameters=0A= if (isStoredProcedure) {=0A= serializeStoredProcedure();=0A= }=0A= =0A= // Serialize result set=0A= while (next()) {=0A= start(this.rowElement, EMPTY_ATTRIBUTES);=0A= serializeRow();=0A= for (Iterator i =3D this.nested.iterator(); = i.hasNext();) {=0A= ((Query) i.next()).executeQuery();=0A= }=0A= end(this.rowElement);=0A= }=0A= =0A= end(this.rowsetElement);=0A= }=0A= } catch (SQLException e) {=0A= getLogger().debug("Exception in executeQuery()", e);=0A= throw new SAXException(e);=0A= } finally {=0A= close();=0A= }=0A= =0A= if (prefix =3D=3D null) {=0A= SQLTransformer.this.endPrefixMapping(this.outPrefix);=0A= }=0A= }=0A= =0A= /**=0A= * Execute the query. Connection must be set already.=0A= */=0A= private void execute() throws SQLException {=0A= = setColumnCase(params.getParameter(SQLTransformer.MAGIC_COLUMN_CASE, = "lowercase"));=0A= =0A= // Construct query string=0A= StringBuffer sb =3D new StringBuffer();=0A= for (Iterator i =3D parts.iterator(); i.hasNext();) {=0A= Object object =3D i.next();=0A= if (object instanceof String) {=0A= sb.append((String) object);=0A= } else if (object instanceof AncestorValue) {=0A= // Do a lookup into the ancestors' result's values=0A= AncestorValue av =3D (AncestorValue) object;=0A= Query query =3D this;=0A= for (int k =3D av.level; k > 0; k--) {=0A= query =3D query.parent;=0A= }=0A= sb.append(query.getColumnValue(av.name));=0A= }=0A= }=0A= =0A= String query =3D StringUtils.replace(sb.toString().trim(), = "\r", " ", -1);=0A= // Test, if this is an update (by comparing with select)=0A= if (!isStoredProcedure && !isUpdate) {=0A= if (query.length() > 6 && !query.substring(0, = 6).equalsIgnoreCase("SELECT")) {=0A= isUpdate =3D true;=0A= }=0A= }=0A= =0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("Executing " + query);=0A= }=0A= if (!isStoredProcedure) {=0A= if (oldDriver) {=0A= pst =3D conn.prepareStatement(query);=0A= } else {=0A= pst =3D conn.prepareStatement(query,=0A= = ResultSet.TYPE_SCROLL_INSENSITIVE,=0A= = ResultSet.CONCUR_READ_ONLY);=0A= }=0A= } else {=0A= if (oldDriver) {=0A= cst =3D conn.prepareCall(query);=0A= } else {=0A= cst =3D conn.prepareCall(query,=0A= = ResultSet.TYPE_SCROLL_INSENSITIVE,=0A= ResultSet.CONCUR_READ_ONLY);=0A= }=0A= registerOutParameters(cst);=0A= pst =3D cst;=0A= }=0A= =0A= registerInParameters();=0A= registerInXmlParameters();=0A= boolean result =3D pst.execute();=0A= if (result) {=0A= rs =3D pst.getResultSet();=0A= md =3D rs.getMetaData();=0A= } else {=0A= rv =3D pst.getUpdateCount();=0A= }=0A= }=0A= =0A= protected int getNrOfRows() throws SQLException {=0A= int nr =3D 0;=0A= =0A= if (rs !=3D null) {=0A= if (oldDriver) {=0A= nr =3D -1;=0A= } else {=0A= try {=0A= rs.last();=0A= nr =3D rs.getRow();=0A= rs.beforeFirst();=0A= } catch (NullPointerException e) {=0A= // A NullPointerException here crashes a whole = lot of C2 --=0A= // catching it so it won't do any harm for now, = but seems like it should be solved seriously=0A= getLogger().error("NPE while getting the nr of = rows", e);=0A= }=0A= }=0A= } else {=0A= if (outParameters !=3D null) {=0A= nr =3D outParameters.size();=0A= }=0A= }=0A= return nr;=0A= }=0A= =0A= protected String getColumnValue(ResultSet rs, int i) throws = SQLException {=0A= final int type =3D rs.getMetaData().getColumnType(i);=0A= if (type =3D=3D java.sql.Types.DOUBLE) {=0A= return getStringValue(rs.getBigDecimal(i));=0A= } else if (type =3D=3D java.sql.Types.CLOB) {=0A= return getStringValue(rs.getClob(i));=0A= } else {=0A= return getStringValue(rs.getObject(i));=0A= }=0A= }=0A= =0A= // fix not applied here because there is no metadata from Name = -> number and coltype=0A= // for a given "name" versus number. That being said this = shouldn't be an issue=0A= // as this function is only called for ancestor lookups.=0A= protected String getColumnValue(String name) throws SQLException = {=0A= //noinspection UnnecessaryLocalVariable=0A= String retval =3D getStringValue(rs.getObject(name));=0A= // if (rs.getMetaData().getColumnType( name ) =3D=3D = java.sql.Types.DOUBLE)=0A= // retval =3D transformer.getStringValue( rs.getBigDecimal( = name ) );=0A= return retval;=0A= }=0A= =0A= protected boolean next() throws SQLException {=0A= // If rv is not -1, then an SQL insert, update, etc, has=0A= // happened (see JDBC docs - return codes for executeUpdate)=0A= if (rv !=3D -1) {=0A= // Output row with return code. Once.=0A= return true;=0A= }=0A= =0A= if (rs !=3D null && rs.next()) {=0A= // Have next row=0A= return true;=0A= }=0A= =0A= while (pst.getMoreResults()) {=0A= rs =3D pst.getResultSet();=0A= md =3D rs.getMetaData();=0A= if (rs.next()) {=0A= // Have next row in next result set=0A= return true;=0A= }=0A= }=0A= =0A= // Nothing left=0A= return false;=0A= }=0A= =0A= /**=0A= * Closes all the resources, ignores (but logs) exceptions.=0A= */=0A= protected void close() {=0A= if (rs !=3D null) {=0A= try {=0A= rs.close();=0A= } catch (SQLException e) {=0A= getLogger().info("Unable to close the result set.", = e);=0A= }=0A= // This prevents us from using the resultset again.=0A= rs =3D null;=0A= }=0A= =0A= if (pst !=3D null && pst !=3D cst) {=0A= try {=0A= pst.close();=0A= } catch (SQLException e) {=0A= getLogger().info("Unable to close the statement.", = e);=0A= }=0A= }=0A= // Prevent using pst again.=0A= pst =3D null;=0A= =0A= if (cst !=3D null) {=0A= try {=0A= cst.close();=0A= } catch (SQLException e) {=0A= getLogger().info("Unable to close the statement.", = e);=0A= }=0A= // Prevent using cst again.=0A= cst =3D null;=0A= }=0A= =0A= try {=0A= if (ownConn && conn !=3D null) {=0A= conn.close();=0A= }=0A= } catch (SQLException e) {=0A= getLogger().info("Unable to close the connection", e);=0A= }=0A= // Prevent using conn again.=0A= conn =3D null;=0A= }=0A= =0A= protected void serializeData(String value)=0A= throws SQLException, SAXException {=0A= if (value !=3D null) {=0A= value =3D value.trim();=0A= // Could this be XML ?=0A= if (value.length() > 0 && value.charAt(0) =3D=3D '<') {=0A= try {=0A= stream(value);=0A= } catch (Exception ignored) {=0A= // FIXME: bad coding "catch(Exception)"=0A= // If an exception occured the data was not = (valid) xml=0A= data(value);=0A= }=0A= } else {=0A= data(value);=0A= }=0A= }=0A= }=0A= =0A= protected void serializeRow()=0A= throws SQLException, SAXException {=0A= if (rv !=3D -1) {=0A= start("returncode", EMPTY_ATTRIBUTES);=0A= serializeData(String.valueOf(rv));=0A= end("returncode");=0A= // We only want the return code shown once.=0A= // Reset rv so next() returns false next time.=0A= rv =3D -1;=0A= } else {=0A= for (int i =3D 1; i <=3D md.getColumnCount(); i++) {=0A= String columnName =3D = getColumnName(md.getColumnName(i));=0A= start(columnName, EMPTY_ATTRIBUTES);=0A= serializeData(getColumnValue(rs, i));=0A= end(columnName);=0A= }=0A= }=0A= }=0A= =0A= private void serializeResultSet(ResultSet rs) throws = SQLException, SAXException {=0A= final ResultSetMetaData md =3D rs.getMetaData();=0A= final int n =3D md.getColumnCount();=0A= =0A= // Get column names=0A= final String[] columns =3D new String[n + 1];=0A= for (int i =3D 1; i <=3D n; i++) {=0A= columns[i] =3D getColumnName(md.getColumnName(i));=0A= }=0A= =0A= // Process rows=0A= while (rs.next()) {=0A= start(rowElement, EMPTY_ATTRIBUTES);=0A= for (int i =3D 1; i <=3D n; i++) {=0A= start(columns[i], EMPTY_ATTRIBUTES);=0A= serializeData(getColumnValue(rs, i));=0A= end(columns[i]);=0A= }=0A= end(this.rowElement);=0A= }=0A= }=0A= =0A= protected void serializeStoredProcedure()=0A= throws SQLException, SAXException {=0A= if (outParametersNames =3D=3D null || cst =3D=3D null) {=0A= return;=0A= }=0A= =0A= Iterator itOutKeys =3D outParameters.keySet().iterator();=0A= while (itOutKeys.hasNext()) {=0A= final Integer counter =3D (Integer) itOutKeys.next();=0A= try {=0A= final Object obj =3D = cst.getObject(counter.intValue());=0A= final String name =3D (String) = outParametersNames.get(counter);=0A= start(name, EMPTY_ATTRIBUTES);=0A= =0A= if (!(obj instanceof ResultSet)) {=0A= serializeData(getStringValue(obj));=0A= } else {=0A= final ResultSet rs =3D (ResultSet) obj;=0A= try {=0A= serializeResultSet(rs);=0A= } finally {=0A= try {=0A= rs.close();=0A= } catch (SQLException e) { /* ignored */ }=0A= }=0A= }=0A= =0A= end(name);=0A= } catch (SQLException e) {=0A= getLogger().error("Caught a SQLException", e);=0A= throw e;=0A= }=0A= }=0A= }=0A= =0A= private String getColumnName(String columnName) {=0A= switch (this.columnCase) {=0A= case -1:=0A= columnName =3D columnName.toLowerCase();=0A= break;=0A= case +1:=0A= columnName =3D columnName.toUpperCase();=0A= break;=0A= default:=0A= // Do nothing=0A= }=0A= return columnName;=0A= }=0A= =0A= /**=0A= * Convert object to string represenation=0A= */=0A= private String getStringValue(Object object) throws SQLException = {=0A= if (object instanceof byte[]) {=0A= // FIXME Encoding?=0A= return new String((byte[]) object);=0A= }=0A= =0A= if (object instanceof char[]) {=0A= return new String((char[]) object);=0A= }=0A= =0A= // Old behavior: Read bytes & decode=0A= if (object instanceof Clob && this.clobEncoding !=3D null) {=0A= Clob clob =3D (Clob) object;=0A= StringBuffer buffer =3D new StringBuffer();=0A= /*The original code (below) does not work correctly with = bulgarian, russian, chinese, etc=0A= InputStream is =3D clob.getAsciiStream();=0A= try {=0A= byte[] bytes =3D new byte[BUFFER_SIZE];=0A= int n;=0A= while ((n =3D is.read(bytes)) > -1) {=0A= buffer.append(new String(bytes, 0, n, = this.clobEncoding));=0A= }=0A= } catch (IOException e) {=0A= throw new SQLException("Error reading stream from = CLOB");=0A= } */=0A= try {=0A= int blocksize =3D 10000;=0A= long length =3D clob.length();=0A= long nMax =3D length/blocksize;=0A= int n;=0A= for (n=3D0;n 0) {=0A= String sText =3D clob.getSubString(nMax*blocksize+1, = lastblocksize);=0A= buffer.append( sText);=0A= }=0A= } catch (Exception e) {=0A= throw new SQLException("Error reading stream from = CLOB");=0A= }=0A= return buffer.toString();=0A= }=0A= =0A= // Correct behavior: Read character data=0A= if (object instanceof Clob) {=0A= Clob clob =3D (Clob) object;=0A= StringBuffer buffer =3D new StringBuffer();=0A= Reader cs =3D clob.getCharacterStream();=0A= try {=0A= char[] chars =3D new char[BUFFER_SIZE];=0A= int n;=0A= while ((n =3D cs.read(chars)) > -1) {=0A= buffer.append(chars, 0, n);=0A= }=0A= } catch (IOException e) {=0A= throw new SQLException("Error reading stream from = CLOB");=0A= }=0A= return buffer.toString();=0A= }=0A= =0A= if (object !=3D null) {=0A= return object.toString();=0A= }=0A= =0A= return "";=0A= }=0A= =0A= private void start(String name, Attributes attr)=0A= throws SAXException {=0A= SQLTransformer.this.start(this.outUri, this.outPrefix, name, = attr);=0A= }=0A= =0A= private void end(String name) throws SAXException {=0A= SQLTransformer.this.end(this.outUri, this.outPrefix, name);=0A= }=0A= =0A= private void data(String data) throws SAXException {=0A= SQLTransformer.this.data(data);=0A= }=0A= }=0A= =0A= private static class AncestorValue {=0A= protected int level;=0A= protected String name;=0A= =0A= protected AncestorValue(int level, String name) {=0A= this.level =3D level;=0A= this.name =3D name;=0A= }=0A= =0A= public String toString() {=0A= return "";=0A= }=0A= }=0A= =0A= /**=0A= * Stop recording of text and return the recorded information.=0A= * @return The String, trimmed.=0A= *=0A= * NB. SQLTransformer needs to have a special version of this method=0A= * It needs the TextRecorder to not trim whitespace from the queries = it is building=0A= *=0A= */=0A= public String endTextRecording()=0A= throws SAXException {=0A= sendEndPrefixMapping();=0A= =0A= TextRecorder recorder =3D (TextRecorder) removeRecorder();=0A= String text =3D recorder.getAllText();=0A= if (getLogger().isDebugEnabled()) {=0A= getLogger().debug("End text recording. Text=3D" + text);=0A= }=0A= return text;=0A= }=0A= =0A= }=0A= ------=_NextPart_000_002B_01C70B4B.A5080F10--