Return-Path: Delivered-To: apmail-cocoon-cvs-archive@www.apache.org Received: (qmail 7934 invoked from network); 5 May 2005 18:32:47 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 5 May 2005 18:32:47 -0000 Received: (qmail 18930 invoked by uid 500); 5 May 2005 18:35:10 -0000 Delivered-To: apmail-cocoon-cvs-archive@cocoon.apache.org Received: (qmail 18865 invoked by uid 500); 5 May 2005 18:35:09 -0000 Mailing-List: contact cvs-help@cocoon.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@cocoon.apache.org list-help: list-unsubscribe: List-Post: Delivered-To: mailing list cvs@cocoon.apache.org Received: (qmail 18805 invoked by uid 99); 5 May 2005 18:35:08 -0000 X-ASF-Spam-Status: No, hits=0.2 required=10.0 tests=NO_REAL_NAME X-Spam-Check-By: apache.org Received: from minotaur.apache.org (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.28) with SMTP; Thu, 05 May 2005 11:35:03 -0700 Received: (qmail 7844 invoked by uid 65534); 5 May 2005 18:32:34 -0000 Message-ID: <20050505183234.7842.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: svn commit: r168374 - /cocoon/branches/BRANCH_2_1_X/src/blocks/databases/java/org/apache/cocoon/transformation/SQLTransformer.java /cocoon/branches/BRANCH_2_1_X/status.xml Date: Thu, 05 May 2005 18:32:34 -0000 To: cvs@cocoon.apache.org From: vgritsenko@apache.org X-Mailer: svnmailer-1.0.0-dev X-Virus-Checked: Checked X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: vgritsenko Date: Thu May 5 11:32:33 2005 New Revision: 168374 URL: http://svn.apache.org/viewcvs?rev=3D168374&view=3Drev Log: implement namespace handling, connection sharing, refactoring Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/databases/java/org/apache/cocoo= n/transformation/SQLTransformer.java cocoon/branches/BRANCH_2_1_X/status.xml Modified: cocoon/branches/BRANCH_2_1_X/src/blocks/databases/java/org/apache= /cocoon/transformation/SQLTransformer.java URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/src/blocks/= databases/java/org/apache/cocoon/transformation/SQLTransformer.java?rev=3D1= 68374&r1=3D168373&r2=3D168374&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- cocoon/branches/BRANCH_2_1_X/src/blocks/databases/java/org/apache/cocoo= n/transformation/SQLTransformer.java (original) +++ cocoon/branches/BRANCH_2_1_X/src/blocks/databases/java/org/apache/cocoo= n/transformation/SQLTransformer.java Thu May 5 11:32:33 2005 @@ -79,13 +79,16 @@ * It can be used in the sitemap pipeline as follows: * * <map:transform type=3D"sql"> + * + * <map:parameter name=3D"own-connection" value=3D"..."/> * * <map:parameter name=3D"use-connection" value=3D"..."/> * * <map:parameter name=3D"dburl" value=3D"..."/> * <map:parameter name=3D"username" value=3D"..."/> * <map:parameter name=3D"password" value=3D"..."/> - * + * + * * <map:parameter name=3D"show-nr-or-rows" value=3D"false"/> * <map:parameter name=3D"doc-element" value=3D"rowset"/> * <map:parameter name=3D"row-element" value=3D"row"/> @@ -99,8 +102,9 @@ *

* The following DTD is valid: * - * <!ENTITY % param "((use-connection|(dburl,username,password))?,show= -nr-or-rows?,doc-element?,row-element?,namespace-uri?,namespace-prefix?,clo= b-encoding?)">
+ * <!ENTITY % param "(own-connection?,(use-connection|(dburl,username,= password))?,show-nr-or-rows?,doc-element?,row-element?,namespace-uri?,names= pace-prefix?,clob-encoding?)">
* <!ELEMENT execute-query (query,(in-parameter|out-parameter)*,execute= -query?, %param;)>
+ * <!ELEMENT own-connection (#PCDATA)>
* <!ELEMENT use-connection (#PCDATA)>
* <!ELEMENT query (#PCDATA | substitute-value | ancestor-value | escap= e-string)*>
* <!ATTLIST query name CDATA #IMPLIED isstoredprocedure (true|false) "= false" isupdate (true|false) "false">
@@ -116,6 +120,18 @@ *
*

* + *

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

+ * + *

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

+ * * @author Carsten Ziegeler * @author Donald Ball * @author Giacomo Pati @@ -134,6 +150,7 @@ =20 // The SQL trasformer namespace element names public static final String MAGIC_EXECUTE_QUERY =3D "execute-query"; + private static final String MAGIC_OWN_CONNECTION =3D "own-connection"; public static final String MAGIC_CONNECTION =3D "use-connection"; public static final String MAGIC_DBURL =3D "dburl"; public static final String MAGIC_USERNAME =3D "username"; @@ -199,25 +216,16 @@ protected Query query; =20 /** The current state of the event receiving FSM */ - protected int current_state; - - /** Check if nr of rows need to be written out. */ - protected boolean showNrOfRows; - - /** The namespace uri of the XML output. Defaults to {@link #namespace= URI}. */ - protected String outUri; + protected int state; =20 - /** The namespace prefix of the XML output. Defaults to 'sql'. */ - protected String outPrefix; + /** The datasource component selector */ + protected ServiceSelector datasources; =20 - /** The database selector */ - protected ServiceSelector dbSelector; + /** The "name" of the connection shared by top level queries (if confi= guration allows) */ + protected String connName; =20 - /** Encoding we use for CLOB field */ - protected String clobEncoding; - - /** The connection used by all top level queries */ - protected Connection connection; + /** The connection shared by top level queries (if configuration allow= s) */ + protected Connection conn; =20 // Used to parse XML from database. protected XMLSerializer compiler; @@ -231,15 +239,19 @@ super.defaultNamespaceURI =3D NAMESPACE; } =20 + // + // Lifecycle Methods + // + /** * Serviceable */ public void service(ServiceManager manager) throws ServiceException { super.service(manager); try { - this.dbSelector =3D (ServiceSelector) manager.lookup(DataSourc= eComponent.ROLE + "Selector"); - } catch (ServiceException cme) { - getLogger().warn("Could not get the DataSource Selector", cme); + this.datasources =3D (ServiceSelector) manager.lookup(DataSour= ceComponent.ROLE + "Selector"); + } catch (ServiceException e) { + getLogger().warn("DataSource component selector is not availab= le.", e); } } =20 @@ -264,22 +276,33 @@ } =20 /** + * Setup for the current request. + */ + public void setup(SourceResolver resolver, Map objectModel, + String source, Parameters parameters) + throws ProcessingException, SAXException, IOException { + super.setup(resolver, objectModel, source, parameters); + + // Setup instance variables + this.state =3D SQLTransformer.STATE_OUTSIDE; + this.connName =3D name(super.parameters); + } + + /** * Recycle this component */ public void recycle() { + this.query =3D null; try { // Close the connection used by all top level queries - if (this.connection !=3D null) { - this.connection.close(); - this.connection =3D null; + if (this.conn !=3D null) { + this.conn.close(); + this.conn =3D null; } } catch (SQLException e) { - getLogger().warn("Could not close the connection", e); + getLogger().info("Could not close connection", e); } - - this.query =3D null; - this.outUri =3D null; - this.outPrefix =3D null; + this.connName =3D null; =20 this.manager.release(this.parser); this.parser =3D null; @@ -295,37 +318,11 @@ * Dispose */ public void dispose() { - if (this.dbSelector !=3D null) { - this.manager.release(this.dbSelector); - this.dbSelector =3D null; - } - } - - /** - * Setup for the current request. - */ - public void setup(SourceResolver resolver, Map objectModel, - String source, Parameters parameters) - throws ProcessingException, SAXException, IOException { - super.setup(resolver, objectModel, source, parameters); - - // Setup instance variables - this.current_state =3D SQLTransformer.STATE_OUTSIDE; - - this.showNrOfRows =3D parameters.getParameterAsBoolean(SQLTransfor= mer.MAGIC_NR_OF_ROWS, false); - this.clobEncoding =3D parameters.getParameter(SQLTransformer.CLOB_= ENCODING, ""); - - if (getLogger().isDebugEnabled()) { - if (this.parameters.getParameter(SQLTransformer.MAGIC_CONNECTI= ON, null) !=3D null) { - getLogger().debug("CONNECTION: " + this.parameters.getPara= meter(SQLTransformer.MAGIC_CONNECTION, null)); - } else { - getLogger().debug("DBURL: " + parameters.getParameter(SQLT= ransformer.MAGIC_DBURL, null)); - getLogger().debug("USERNAME: " + parameters.getParameter(S= QLTransformer.MAGIC_USERNAME, null)); - } - getLogger().debug("DOC-ELEMENT: " + parameters.getParameter(SQ= LTransformer.MAGIC_DOC_ELEMENT, "rowset")); - getLogger().debug("ROW-ELEMENT: " + parameters.getParameter(SQ= LTransformer.MAGIC_ROW_ELEMENT, "row")); - getLogger().debug("Using CLOB encoding: " + clobEncoding); + if (this.datasources !=3D null) { + this.manager.release(this.datasources); + this.datasources =3D null; } + super.dispose(); } =20 /** @@ -342,98 +339,9 @@ return value; } =20 - /** - * This will be the meat of SQLTransformer, where the query is run. - */ - protected void executeQuery(Query query) - throws SAXException { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Executing query " + query); - } - - this.outUri =3D query.properties.getParameter(SQLTransformer.MAGIC= _NS_URI_ELEMENT, super.namespaceURI); - this.outPrefix =3D query.properties.getParameter(SQLTransformer.MA= GIC_NS_PREFIX_ELEMENT, "sql"); - - // Start prefix mapping for output namespace - // only if its URI is not empty, and if it is not this transformer= namespace. - final boolean startPrefixMapping =3D !"".equals(this.outUri) && !n= amespaceURI.equals(this.outUri); - if (startPrefixMapping) { - super.startPrefixMapping(this.outPrefix, this.outUri); - } - - boolean success =3D false; - Connection conn =3D null; - try { - try { - if (query.parent =3D=3D null) { - if (this.connection =3D=3D null) { - // The first top level execute-query - this.connection =3D query.getConnection(); - } - // Reuse the global connection for all top level queri= es - conn =3D this.connection; - } else { - // Sub queries are always executed in an own connection - conn =3D query.getConnection(); - } - - query.setConnection(conn); - query.execute(); - success =3D true; - } catch (SQLException e) { - getLogger().info("Failed to execute query " + query, e); - start(query.rowset_name, EMPTY_ATTRIBUTES); - start(MAGIC_ERROR, EMPTY_ATTRIBUTES); - data(e.getMessage()); - end(MAGIC_ERROR); - end(query.rowset_name); - } - - if (success) { - AttributesImpl attr =3D new AttributesImpl(); - if (this.showNrOfRows) { - attr.addAttribute("", query.nr_of_rows, query.nr_of_ro= ws, "CDATA", String.valueOf(query.getNrOfRows())); - } - String name =3D query.getName(); - if (name !=3D null) { - attr.addAttribute("", query.name_attribute, query.name= _attribute, "CDATA", name); - } - start(query.rowset_name, attr); - - if (!query.isStoredProcedure()) { - while (query.next()) { - start(query.row_name, EMPTY_ATTRIBUTES); - query.serializeRow(this.manager); - for (Iterator i =3D query.nested(); i.hasNext();) { - executeQuery((Query) i.next()); - } - end(query.row_name); - } - } else { - query.serializeStoredProcedure(this.manager); - } - - end(query.rowset_name); - } - } catch (SQLException e) { - getLogger().debug("Exception in executeQuery()", e); - throw new SAXException(e); - } finally { - query.close(); - if (query.parent !=3D null) { - try { - // Close the connection used by a sub query - conn.close(); - } catch (SQLException e) { - getLogger().warn("Unable to close JDBC connection", e); - } - } - } - - if (startPrefixMapping) { - super.endPrefixMapping(this.outPrefix); - } - } + // + // SAX Events Handlers + // =20 protected static void throwIllegalStateException(String message) { throw new IllegalStateException("Illegal state: " + message); @@ -441,13 +349,13 @@ =20 /** <execute-query> */ protected void startExecuteQueryElement() { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_OUTSIDE: case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: // Create root query (if query =3D=3D null), or child query - this.query =3D new Query(this, this.query); + this.query =3D new Query(this.query); this.query.enableLogging(getLogger().getChildLogger("query= ")); - current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUER= Y_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMEN= T; break; =20 default: @@ -458,11 +366,11 @@ /** <*> */ protected void startValueElement(String name) throws SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: this.stack.push(name); startTextRecording(); - current_state =3D SQLTransformer.STATE_INSIDE_VALUE_ELEMEN= T; + state =3D SQLTransformer.STATE_INSIDE_VALUE_ELEMENT; break; =20 default: @@ -473,10 +381,10 @@ /** <query> */ protected void startQueryElement(Attributes attributes) throws SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: startTextRecording(); - current_state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMEN= T; + state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; =20 String isUpdate =3D attributes.getValue("", SQLTransformer= .MAGIC_UPDATE_ATTRIBUTE); if (isUpdate !=3D null && !isUpdate.equalsIgnoreCase("fals= e")) { @@ -502,13 +410,13 @@ /** </query> */ protected void endQueryElement() throws ProcessingException, SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: final String value =3D endTextRecording(); if (value.length() > 0) { query.addQueryPart(value); } - current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUER= Y_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMEN= T; break; =20 default: @@ -519,12 +427,12 @@ /** </*> */ protected void endValueElement() throws SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_VALUE_ELEMENT: final String name =3D (String) this.stack.pop(); final String value =3D endTextRecording(); query.setParameter(name, value); - this.current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE= _QUERY_ELEMENT; + this.state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_E= LEMENT; break; =20 default: @@ -534,16 +442,16 @@ =20 /** </execute-query> */ protected void endExecuteQueryElement() throws SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: if (query.parent =3D=3D null) { - executeQuery(query); + query.executeQuery(); query =3D null; - current_state =3D SQLTransformer.STATE_OUTSIDE; + state =3D SQLTransformer.STATE_OUTSIDE; } else { query.parent.addNestedQuery(query); query =3D query.parent; - current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE_= QUERY_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_EL= EMENT; } break; =20 @@ -555,7 +463,7 @@ /** <ancestor-value> */ protected void startAncestorValueElement(Attributes attributes) throws ProcessingException, SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: int level =3D 0; try { @@ -579,7 +487,7 @@ query.addQueryPart(new AncestorValue(level, name)); startTextRecording(); =20 - current_state =3D SQLTransformer.STATE_INSIDE_ANCESTOR_VAL= UE_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_ANCESTOR_VALUE_ELEME= NT; break; default: throwIllegalStateException("Not expecting a start ancestor= value element"); @@ -588,13 +496,13 @@ =20 /** </ancestor-value> */ protected void endAncestorValueElement() { - current_state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; } =20 /** <substitute-value> */ protected void startSubstituteValueElement(Attributes attributes) throws ProcessingException, SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: String name =3D getAttributeValue(attributes, SQLTransform= er.MAGIC_SUBSTITUTE_VALUE_NAME_ATTRIBUTE); if (name =3D=3D null) { @@ -612,7 +520,7 @@ query.addQueryPart(substitute); startTextRecording(); =20 - current_state =3D SQLTransformer.STATE_INSIDE_SUBSTITUTE_V= ALUE_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_SUBSTITUTE_VALUE_ELE= MENT; break; =20 default: @@ -622,13 +530,13 @@ =20 /** </substitute-value> */ protected void endSubstituteValueElement() { - current_state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; } =20 /** <escape-string> */ protected void startEscapeStringElement(Attributes attributes) throws ProcessingException, SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_QUERY_ELEMENT: final String value =3D endTextRecording(); if (value.length() > 0) { @@ -636,7 +544,7 @@ } startTextRecording(); =20 - current_state =3D SQLTransformer.STATE_INSIDE_ESCAPE_STRIN= G; + state =3D SQLTransformer.STATE_INSIDE_ESCAPE_STRING; break; =20 default: @@ -647,7 +555,7 @@ /** </escape-string> */ protected void endEscapeStringElement() throws SAXException { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_ESCAPE_STRING: String value =3D endTextRecording(); if (value.length() > 0) { @@ -656,7 +564,7 @@ query.addQueryPart(value); } startTextRecording(); - current_state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMEN= T; + state =3D SQLTransformer.STATE_INSIDE_QUERY_ELEMENT; break; =20 default: @@ -666,7 +574,7 @@ =20 /** <in-parameter> */ protected void startInParameterElement(Attributes attributes) { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: String nr =3D getAttributeValue(attributes, SQLTransformer= .MAGIC_IN_PARAMETER_NR_ATTRIBUTE); String value =3D getAttributeValue(attributes, SQLTransfor= mer.MAGIC_IN_PARAMETER_VALUE_ATTRIBUTE); @@ -676,7 +584,7 @@ =20 int position =3D Integer.parseInt(nr); query.setInParameter(position, value); - current_state =3D SQLTransformer.STATE_INSIDE_IN_PARAMETER= _ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_IN_PARAMETER_ELEMENT; break; =20 default: @@ -686,12 +594,12 @@ =20 /** </in-parameter> */ protected void endInParameterElement() { - current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMEN= T; + state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; } =20 /** <out-parameter> */ protected void startOutParameterElement(Attributes attributes) { - switch (current_state) { + switch (state) { case SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT: String name =3D getAttributeValue(attributes, SQLTransform= er.MAGIC_OUT_PARAMETER_NAME_ATTRIBUTE); String nr =3D getAttributeValue(attributes, SQLTransformer= .MAGIC_OUT_PARAMETER_NR_ATTRIBUTE); @@ -702,7 +610,7 @@ =20 int position =3D Integer.parseInt(nr); query.setOutParameter(position, type, name); - current_state =3D SQLTransformer.STATE_INSIDE_OUT_PARAMETE= R_ELEMENT; + state =3D SQLTransformer.STATE_INSIDE_OUT_PARAMETER_ELEMEN= T; break; =20 default: @@ -712,25 +620,7 @@ =20 /** </out-parameter> */ protected void endOutParameterElement() { - current_state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMEN= T; - } - - /** - * Qualifies an element name by giving it a prefix. - * @param name the element name - * @param prefix the prefix to qualify with - * @return a namespace qualified name that is correct - */ - protected String nsQualify(String name, String prefix) { - if (StringUtils.isEmpty(name)) { - return name; - } - - if (StringUtils.isNotEmpty(prefix)) { - return prefix + ":" + name; - } - - return name; + state =3D SQLTransformer.STATE_INSIDE_EXECUTE_QUERY_ELEMENT; } =20 /** @@ -781,13 +671,35 @@ } } =20 + // + // Helper methods for the Query + // + + /** + * Qualifies an element name by giving it a prefix. + * @param name the element name + * @param prefix the prefix to qualify with + * @return a namespace qualified name that is correct + */ + protected String nsQualify(String name, String prefix) { + if (StringUtils.isEmpty(name)) { + return name; + } + + if (StringUtils.isNotEmpty(prefix)) { + return prefix + ":" + name; + } + + return name; + } + /** * Helper method for generating SAX events */ - protected void start(String name, Attributes attr) + protected void start(String uri, String prefix, String name, Attribute= s attr) throws SAXException { try { - super.startTransformingElement(outUri, name, nsQualify(name, o= utPrefix), attr); + super.startTransformingElement(uri, name, nsQualify(name, pref= ix), attr); } catch (IOException e) { throw new SAXException(e); } catch (ProcessingException e) { @@ -798,9 +710,9 @@ /** * Helper method for generating SAX events */ - protected void end(String name) throws SAXException { + protected void end(String uri, String prefix, String name) throws SAXE= xception { try { - super.endTransformingElement(outUri, name, nsQualify(name, out= Prefix)); + super.endTransformingElement(uri, name, nsQualify(name, prefix= )); } catch (IOException e) { throw new SAXException(e); } catch (ProcessingException e) { @@ -818,99 +730,251 @@ } =20 /** - * Convert object to string represenation + * Get 'name' for the connection which can be obtained using provided + * connection parameters. */ - protected static String getStringValue(Object object) { - if (object instanceof byte[]) { - // FIXME Encoding? - return new String((byte[]) object); - } else if (object instanceof char[]) { - return new String((char[]) object); - } else if (object !=3D null) { - return object.toString(); + private String name(Parameters params) { + final boolean ownConnection =3D params.getParameterAsBoolean(SQLTr= ansformer.MAGIC_OWN_CONNECTION, false); + if (ownConnection) { + return null; + } + + final String datasourceName =3D params.getParameter(SQLTransformer= .MAGIC_CONNECTION, null); + if (datasourceName !=3D null) { + return "ds:" + datasourceName; + } + + final String dburl =3D params.getParameter(SQLTransformer.MAGIC_DB= URL, null); + if (dburl !=3D null) { + final String username =3D params.getParameter(SQLTransformer.M= AGIC_USERNAME, null); + final String password =3D params.getParameter(SQLTransformer.M= AGIC_PASSWORD, null); + + if (username =3D=3D null || password =3D=3D null) { + return "db:@" + dburl; + } else { + return "db:" + username + ":" + password + "@" + dburl; + } } =20 + // Nothing configured return ""; } =20 /** + * Open database connection using provided parameters. + * Return null if neither datasource nor jndi URL configured. + */ + private Connection open(Parameters params) throws SQLException { + Connection result =3D null; + + // First check datasource name parameter + final String datasourceName =3D params.getParameter(SQLTransformer= .MAGIC_CONNECTION, null); + if (datasourceName !=3D null) { + // Use datasource components + if (this.datasources =3D=3D null) { + throw new SQLException("Unable to get connection from data= source '" + datasourceName + "': " + + "No datasources configured in cocoo= n=2Exconf."); + } + + DataSourceComponent datasource =3D null; + try { + datasource =3D (DataSourceComponent) this.datasources.sele= ct(datasourceName); + for (int i =3D 0; i < this.connectAttempts && result =3D= =3D null; i++) { + try { + result =3D datasource.getConnection(); + } catch (Exception e) { + final long waittime =3D this.connectWaittime; + getLogger().debug("Unable to get connection; waiti= ng " + + waittime + "ms to try again."); + try { + Thread.sleep(waittime); + } catch (InterruptedException ignored) { + } + } + } + } catch (ServiceException e) { + throw new SQLException("Unable to get connection from data= source '" + datasourceName + "': " + + "No such datasource."); + } finally { + if (datasource !=3D null) { + this.datasources.release(datasource); + } + } + + if (result =3D=3D null) { + throw new SQLException("Failed to obtain connection from d= atasource '" + datasourceName + "'. " + + "Made " + this.connectAttempts + " = attempts with " + + this.connectWaittime + "ms interv= al"); + } + } else { + // Then, check connection URL parameter + final String dburl =3D params.getParameter(SQLTransformer.MAGI= C_DBURL, null); + if (dburl !=3D null) { + final String username =3D params.getParameter(SQLTransform= er.MAGIC_USERNAME, null); + final String password =3D params.getParameter(SQLTransform= er.MAGIC_PASSWORD, null); + + if (username =3D=3D null || password =3D=3D null) { + result =3D DriverManager.getConnection(dburl); + } else { + result =3D DriverManager.getConnection(dburl, username= , password); + } + } else { + // Nothing configured + } + } + + return result; + } + + /** + * Attempt to parse string value + */ + private void stream(String value) throws ServiceException, SAXExceptio= n, IOException { + try { + // Strip off the XML Declaration if there is one! + if (value.startsWith("") + 2); + } + + // Lookup components + if (this.parser =3D=3D null) { + this.parser =3D (SAXParser) manager.lookup(SAXParser.ROLE); + } + if (this.compiler =3D=3D null) { + this.compiler =3D (XMLSerializer) manager.lookup(XMLSerial= izer.ROLE); + } + if (this.interpreter =3D=3D null) { + this.interpreter =3D (XMLDeserializer) manager.lookup(XMLD= eserializer.ROLE); + } + + this.parser.parse(new InputSource(new StringReader("" + = value + "")), + this.compiler); + + IncludeXMLConsumer filter =3D new IncludeXMLConsumer(this, thi= s); + filter.setIgnoreRootElement(true); + + this.interpreter.setConsumer(filter); + this.interpreter.deserialize(this.compiler.getSAXFragment()); + } finally { + // otherwise serializer won't be reset + if (this.compiler !=3D null) { + manager.release(this.compiler); + this.compiler =3D null; + } + } + } + + /** * One of the queries in the query tree formed from nested queries. */ - class Query extends AbstractLogEnabled { - /** Who's your daddy? */ - protected SQLTransformer transformer; + private class Query extends AbstractLogEnabled { =20 /** Parent query, or null for top level query */ protected Query parent; =20 /** Nested sub-queries we have. */ - protected List nested =3D new ArrayList(); + protected final List nested =3D new ArrayList(); =20 - /** SQL configuration information */ - protected Parameters properties; + /** The parts of the query */ + protected final List parts =3D new ArrayList(); =20 - /** Dummy static variables for the moment **/ - protected String rowset_name; - protected String row_name; - protected String nr_of_rows =3D "nrofrows"; - protected String name_attribute =3D "name"; + // + // Query Configuration + // =20 - /** The connection */ - protected Connection conn; + /** Name of the query */ + protected String name; =20 - /** And the statements */ - protected PreparedStatement pst; - protected CallableStatement cst; + /** If this query is actually an update (insert, update, delete) */ + protected boolean isUpdate; =20 - /** The results, of course */ - protected ResultSet rs; + /** If this query is actually a stored procedure */ + protected boolean isStoredProcedure; =20 - /** And the results' metadata */ - protected ResultSetMetaData md; + /** Query configuration parameters */ + protected Parameters params; =20 - /** If this query is actually an update (insert, update, delete) */ - protected boolean isupdate; + /** The namespace uri of the XML output. Defaults to {@link SQLTra= nsformer#namespaceURI}. */ + protected String outUri; =20 - /** If this query is actually a stored procedure */ - protected boolean isstoredprocedure; + /** The namespace prefix of the XML output. Defaults to 'sql'. */ + protected String outPrefix; =20 - /** Name of the query */ - protected String name; + /** rowset element name */ + protected String rowsetElement; =20 - /** If it is an update/etc, the return value (num rows modified) */ - protected int rv =3D -1; + /** row element name */ + protected String rowElement; =20 - /** The parts of the query */ - protected List query_parts =3D new ArrayList(); + /** number of rows attribute name */ + protected String nrOfRowsAttr =3D "nrofrows"; + + /** Query name attribute name */ + protected String nameAttr =3D "name"; =20 - /** In parameters */ + /** Handling of case of column names in results */ + protected int columnCase; + + /** Registered IN parameters */ protected HashMap inParameters; =20 - /** Out parameters */ + /** Registered OUT parameters */ protected HashMap outParameters; =20 /** Mapping out parameters - objectModel */ protected HashMap outParametersNames; =20 - /** Handling of case of column names in results */ - protected int columnCase; + /** Check if nr of rows need to be written out. */ + protected boolean showNrOfRows; =20 + /** Encoding we use for CLOB field */ + protected String clobEncoding; =20 - protected Query(SQLTransformer transformer, Query parent) { - this.transformer =3D transformer; - this.parent =3D parent; - this.properties =3D new Parameters(); - this.properties.merge(transformer.parameters); - } + // + // Query State + // + + /** The connection */ + protected Connection conn; + + /** The 'name' of the connection */ + protected String connName; + + /** Is it our own connection? */ + protected boolean ownConn; + + /** Prepared statement */ + protected PreparedStatement pst; + + /** Callable statement */ + protected CallableStatement cst; =20 - /** Return iterator over nested sub-queries. */ - protected Iterator nested() { - return this.nested.iterator(); + /** The results, of course */ + protected ResultSet rs; + + /** And the results' metadata */ + protected ResultSetMetaData md; + + /** If it is an update/etc, the return value (num rows modified) */ + protected int rv =3D -1; + + + protected Query(Query parent) { + this.parent =3D parent; + this.params =3D new Parameters(); + this.params.merge(SQLTransformer.this.parameters); } =20 /** Add nested sub-query. */ protected void addNestedQuery(Query query) { - this.nested.add(query); + nested.add(query); + } + + protected void addQueryPart(Object value) { + if (getLogger().isDebugEnabled()) { + getLogger().debug("Adding query part \"" + value + "\""); + } + parts.add(value); } =20 protected String getName() { @@ -925,19 +989,15 @@ if (getLogger().isDebugEnabled()) { getLogger().debug("Adding parameter name {" + name + "} va= lue {" + value + "}"); } - properties.setParameter(name, value); + params.setParameter(name, value); } =20 protected void setUpdate(boolean flag) { - isupdate =3D flag; + isUpdate =3D flag; } =20 protected void setStoredProcedure(boolean flag) { - isstoredprocedure =3D flag; - } - - protected boolean isStoredProcedure() { - return isstoredprocedure; + isStoredProcedure =3D flag; } =20 protected void setInParameter(int pos, String val) { @@ -956,7 +1016,7 @@ outParametersNames.put(new Integer(pos), name); } =20 - protected void setColumnCase(String columnCase) { + private void setColumnCase(String columnCase) { if (columnCase.equals("lowercase")) { this.columnCase =3D -1; } else if (columnCase.equals("uppercase")) { @@ -970,7 +1030,7 @@ } } =20 - private void registerInParameters(PreparedStatement pst) throws SQ= LException { + private void registerInParameters() throws SQLException { if (inParameters =3D=3D null) { return; } @@ -1018,83 +1078,133 @@ } } =20 - protected void setConnection(Connection conn) { - this.conn =3D conn; + /** + * Open database connection + */ + private void open() throws SQLException { + this.connName =3D SQLTransformer.this.name(this.params); + + // Check first if connection sharing disabled + if (this.connName =3D=3D null) { + this.conn =3D SQLTransformer.this.open(this.params); + this.ownConn =3D true; + return; + } + + // Iterate through parent queries and get appropriate connecti= on + Query query =3D this.parent; + while (query !=3D null) { + if (this.connName.equals(query.connName)) { + this.conn =3D query.conn; + this.ownConn =3D false; + return; + } + query =3D query.parent; + } + + // Check 'global' connection + if (this.connName.equals(SQLTransformer.this.connName)) { + // Use SQLTransformer configuration: it has same connectio= n parameters + if (SQLTransformer.this.conn =3D=3D null) { + SQLTransformer.this.conn =3D SQLTransformer.this.open(= SQLTransformer.this.parameters); + } + + this.conn =3D SQLTransformer.this.conn; + this.ownConn =3D false; + return; + } + + // Create own connection + this.conn =3D SQLTransformer.this.open(this.params); + this.ownConn =3D true; } =20 /** - * Get a Connection. Made this a separate method to separate the l= ogic from the actual execution. + * This will be the meat of SQLTransformer, where the query is run. */ - protected Connection getConnection() throws SQLException { - Connection result =3D null; + protected void executeQuery() throws SAXException { + if (getLogger().isDebugEnabled()) { + getLogger().debug("Executing query " + this); + } =20 - final String connection =3D properties.getParameter(SQLTransfo= rmer.MAGIC_CONNECTION, null); - if (connection !=3D null) { - // Use datasource components - if (this.transformer.dbSelector =3D=3D null) { - throw new SQLException("Failed to obtain connection fr= om datasource '" + connection + "'. " + - "No datasources configured in c= ocoon.xconf."); - } + this.outUri =3D this.params.getParameter(SQLTransformer.MAGIC_= NS_URI_ELEMENT, SQLTransformer.this.namespaceURI); + this.outPrefix =3D this.params.getParameter(SQLTransformer.MAG= IC_NS_PREFIX_ELEMENT, "sql"); =20 - DataSourceComponent datasource =3D null; + this.showNrOfRows =3D parameters.getParameterAsBoolean(SQLTran= sformer.MAGIC_NR_OF_ROWS, false); + this.clobEncoding =3D parameters.getParameter(SQLTransformer.C= LOB_ENCODING, ""); + + // Start prefix mapping for output namespace, only if it's not= mapped yet + final String prefix =3D SQLTransformer.this.findPrefixMapping(= this.outUri); + if (prefix =3D=3D null) { + SQLTransformer.this.startPrefixMapping(this.outPrefix, thi= s=2EoutUri); + } else { + this.outPrefix =3D prefix; + } + + boolean success =3D false; + try { try { - datasource =3D (DataSourceComponent) this.transformer.= dbSelector.select(connection); - for (int i =3D 0; i < transformer.connectAttempts && r= esult =3D=3D null; i++) { - try { - result =3D datasource.getConnection(); - } catch (Exception e) { - final long waittime =3D transformer.connectWai= ttime; - getLogger().debug("Unable to get connection; w= aiting " + - waittime + "ms to try aga= in."); - try { - Thread.sleep(waittime); - } catch (InterruptedException ignored) { - } - } + open(); + execute(); + success =3D true; + } catch (SQLException e) { + getLogger().info("Failed to execute query " + this, e); + start(this.rowsetElement, EMPTY_ATTRIBUTES); + start(MAGIC_ERROR, EMPTY_ATTRIBUTES); + data(e.getMessage()); + end(MAGIC_ERROR); + end(this.rowsetElement); + } + + if (success) { + AttributesImpl attr =3D new AttributesImpl(); + if (this.showNrOfRows) { + attr.addAttribute("", this.nrOfRowsAttr, this.nrOf= RowsAttr, "CDATA", String.valueOf(getNrOfRows())); } - } catch (ServiceException cme) { - getLogger().error("Could not use connection: " + conne= ction, cme); - } finally { - if (datasource !=3D null) { - this.transformer.dbSelector.release(datasource); + String name =3D getName(); + if (name !=3D null) { + attr.addAttribute("", this.nameAttr, this.nameAttr= , "CDATA", name); } - } + start(this.rowsetElement, attr); =20 - if (result =3D=3D null) { - throw new SQLException("Failed to obtain connection fr= om datasource '" + connection + "'. " + - "Made " + transformer.connectAt= tempts + " attempts with " - + transformer.connectWaittime += "ms interval"); - } - } else { - // Create connection manually - final String dburl =3D properties.getParameter(SQLTransfor= mer.MAGIC_DBURL, null); - final String username =3D properties.getParameter(SQLTrans= former.MAGIC_USERNAME, null); - final String password =3D properties.getParameter(SQLTrans= former.MAGIC_PASSWORD, null); + if (!isStoredProcedure) { + while (next()) { + start(this.rowElement, EMPTY_ATTRIBUTES); + serializeRow(); + for (Iterator i =3D this.nested.iterator(); i.= hasNext();) { + ((Query) i.next()).executeQuery(); + } + end(this.rowElement); + } + } else { + serializeStoredProcedure(); + } =20 - if (username =3D=3D null || password =3D=3D null) { - result =3D DriverManager.getConnection(dburl); - } else { - result =3D DriverManager.getConnection(dburl, username= , password); + end(this.rowsetElement); } + } catch (SQLException e) { + getLogger().debug("Exception in executeQuery()", e); + throw new SAXException(e); + } finally { + close(); } =20 - return result; + if (prefix =3D=3D null) { + SQLTransformer.this.endPrefixMapping(this.outPrefix); + } } =20 /** * Execute the query. Connection must be set already. */ - protected void execute() throws SQLException { - if (this.conn =3D=3D null) { - throw new SQLException("A connection must be set before ex= ecuting a query"); - } - - this.rowset_name =3D properties.getParameter(SQLTransformer.MA= GIC_DOC_ELEMENT, "rowset"); - this.row_name =3D properties.getParameter(SQLTransformer.MAGIC= _ROW_ELEMENT, "row"); - setColumnCase(properties.getParameter(SQLTransformer.MAGIC_COL= UMN_CASE, "lowercase")); + private void execute() throws SQLException { + this.rowsetElement =3D params.getParameter(SQLTransformer.MAGI= C_DOC_ELEMENT, "rowset"); + this.rowElement =3D params.getParameter(SQLTransformer.MAGIC_R= OW_ELEMENT, "row"); + setColumnCase(params.getParameter(SQLTransformer.MAGIC_COLUMN_= CASE, "lowercase")); =20 + // Construct query string StringBuffer sb =3D new StringBuffer(); - for (Iterator i =3D query_parts.iterator(); i.hasNext();) { + for (Iterator i =3D parts.iterator(); i.hasNext();) { Object object =3D i.next(); if (object instanceof String) { sb.append((String) object); @@ -1111,49 +1221,42 @@ =20 String query =3D StringUtils.replace(sb.toString().trim(), "\r= ", " ", -1); // Test, if this is an update (by comparing with select) - if (!isstoredprocedure && !isupdate) { + if (!isStoredProcedure && !isUpdate) { if (query.length() > 6 && !query.substring(0, 6).equalsIgn= oreCase("SELECT")) { - isupdate =3D true; + isUpdate =3D true; } } + if (getLogger().isDebugEnabled()) { getLogger().debug("Executing " + query); } - - try { - if (!isstoredprocedure) { - if (oldDriver) { - pst =3D conn.prepareStatement(query); - } else { - pst =3D conn.prepareStatement(query, - ResultSet.TYPE_SCROLL_= INSENSITIVE, - ResultSet.CONCUR_READ_= ONLY); - } + if (!isStoredProcedure) { + if (oldDriver) { + pst =3D conn.prepareStatement(query); } else { - if (oldDriver) { - cst =3D conn.prepareCall(query); - } else { - cst =3D conn.prepareCall(query, - ResultSet.TYPE_SCROLL_INSEN= SITIVE, - ResultSet.CONCUR_READ_ONLY); - } - registerOutParameters(cst); - pst =3D cst; + pst =3D conn.prepareStatement(query, + ResultSet.TYPE_SCROLL_INSE= NSITIVE, + ResultSet.CONCUR_READ_ONLY= ); } - - registerInParameters(pst); - boolean result =3D pst.execute(); - if (result) { - rs =3D pst.getResultSet(); - md =3D rs.getMetaData(); + } else { + if (oldDriver) { + cst =3D conn.prepareCall(query); } else { - rv =3D pst.getUpdateCount(); - } - } catch (SQLException e) { - getLogger().error("Caught a SQLException", e); - throw e; - } finally { - // Connection is not closed here, but later on. See bug #1= 2173. + cst =3D conn.prepareCall(query, + ResultSet.TYPE_SCROLL_INSENSITI= VE, + ResultSet.CONCUR_READ_ONLY); + } + registerOutParameters(cst); + pst =3D cst; + } + + registerInParameters(); + boolean result =3D pst.execute(); + if (result) { + rs =3D pst.getResultSet(); + md =3D rs.getMetaData(); + } else { + rv =3D pst.getUpdateCount(); } } =20 @@ -1186,7 +1289,7 @@ String retval; =20 if (rs.getMetaData().getColumnType(i) =3D=3D java.sql.Types.DO= UBLE) { - retval =3D SQLTransformer.getStringValue(rs.getBigDecimal(= i)); + retval =3D getStringValue(rs.getBigDecimal(i)); } else if (rs.getMetaData().getColumnType(i) =3D=3D java.sql.T= ypes.CLOB) { Clob clob =3D rs.getClob(i); InputStream inputStream =3D clob.getAsciiStream(); @@ -1194,7 +1297,7 @@ StringBuffer buffer =3D new StringBuffer(); try { while (inputStream.read(readByte) > -1) { - String string =3D new String(readByte, clobEncodin= g); + String string =3D new String(readByte, this.clobEn= coding); buffer.append(string); } } catch (IOException e) { @@ -1202,7 +1305,7 @@ } retval =3D buffer.toString(); } else { - retval =3D SQLTransformer.getStringValue(rs.getObject(i)); + retval =3D getStringValue(rs.getObject(i)); } return retval; } @@ -1211,25 +1314,20 @@ // for a given "name" versus number. That being said this shouldn= 't be an issue // as this function is only called for ancestor lookups. protected String getColumnValue(String name) throws SQLException { - String retval =3D SQLTransformer.getStringValue(rs.getObject(n= ame)); + String retval =3D getStringValue(rs.getObject(name)); // if (rs.getMetaData().getColumnType( name ) =3D=3D 8) // retval =3D transformer.getStringValue( rs.getBigDecimal( na= me ) ); return retval; } =20 protected boolean next() throws SQLException { - // if rv is not -1, then an SQL insert, update, etc, has + // If rv is not -1, then an SQL insert, update, etc, has // happened (see JDBC docs - return codes for executeUpdate) if (rv !=3D -1) { return false; } =20 - try { - if (rs =3D=3D null || !rs.next()) { - return false; - } - } catch (NullPointerException e) { - getLogger().debug("NullPointerException, returning false."= , e); + if (rs =3D=3D null || !rs.next()) { return false; } =20 @@ -1240,118 +1338,84 @@ * Closes all the resources, ignores (but logs) exceptions. */ protected void close() { - try { - if (rs !=3D null) { - try { - rs.close(); - } catch (NullPointerException e) { - getLogger().debug("NullPointer while closing the r= esultset.", e); - } catch (SQLException e) { - getLogger().info("SQLException while closing the R= esultSet.", e); - } - // This prevents us from using the resultset again. - rs =3D null; + if (rs !=3D null) { + try { + rs.close(); + } catch (SQLException e) { + getLogger().info("Unable to close the result set.", e); } + // This prevents us from using the resultset again. + rs =3D null; + } =20 - if (pst !=3D null && pst !=3D cst) { - try { - pst.close(); - } catch (SQLException e) { - getLogger().info("SQLException while closing the S= tatement.", e); - } + if (pst !=3D null && pst !=3D cst) { + try { + pst.close(); + } catch (SQLException e) { + getLogger().info("Unable to close the statement.", e); } - // Prevent using pst again. - pst =3D null; + } + // Prevent using pst again. + pst =3D null; =20 - if (cst !=3D null) { - try { - cst.close(); - } catch (SQLException e) { - getLogger().info("SQLException while closing the S= tatement.", e); - } + if (cst !=3D null) { + try { + cst.close(); + } catch (SQLException e) { + getLogger().info("Unable to close the statement.", e); } // Prevent using cst again. cst =3D null; - } finally { - // Prevent using conn again. - conn =3D null; } - } =20 - protected void addQueryPart(Object value) { - if (getLogger().isDebugEnabled()) { - getLogger().debug("Adding query part \"" + value + "\""); + try { + if (ownConn && conn !=3D null) { + conn.close(); + } + } catch (SQLException e) { + getLogger().info("Unable to close the connection", e); } - query_parts.add(value); + // Prevent using conn again. + conn =3D null; } =20 - protected void serializeData(ServiceManager manager, String value) + protected void serializeData(String value) throws SQLException, SAXException { if (value !=3D null) { value =3D value.trim(); // Could this be XML ? if (value.length() > 0 && value.charAt(0) =3D=3D '<') { try { - String stripped =3D value; - - // Strip off the XML Declaration if there is one! - if (stripped.startsWith("") + 2); - } - - if (transformer.parser =3D=3D null) { - transformer.parser =3D (SAXParser) manager.loo= kup(SAXParser.ROLE); - } - if (transformer.compiler =3D=3D null) { - transformer.compiler =3D (XMLSerializer) manag= er.lookup(XMLSerializer.ROLE); - } - if (transformer.interpreter =3D=3D null) { - transformer.interpreter =3D (XMLDeserializer) = manager.lookup(XMLDeserializer.ROLE); - } - - transformer.parser.parse(new InputSource(new Strin= gReader("" + stripped + "")), - transformer.compiler); - - IncludeXMLConsumer filter =3D new IncludeXMLConsum= er(transformer, transformer); - filter.setIgnoreRootElement(true); - - transformer.interpreter.setConsumer(filter); - transformer.interpreter.deserialize(transformer.co= mpiler.getSAXFragment()); - } catch (Exception local) { + stream(value); + } catch (Exception ignored) { // FIXME: bad coding "catch(Exception)" - // if an exception occured the data was not xml - transformer.data(value); - } finally { - // otherwise serializer won't be reset - if (transformer.compiler !=3D null) { - manager.release(transformer.compiler); - transformer.compiler =3D null; - } + // If an exception occured the data was not (valid= ) xml + data(value); } } else { - transformer.data(value); + data(value); } } } =20 - protected void serializeRow(ServiceManager manager) + protected void serializeRow() throws SQLException, SAXException { - if (!isupdate && !isstoredprocedure) { + if (!isUpdate && !isStoredProcedure) { for (int i =3D 1; i <=3D md.getColumnCount(); i++) { String columnName =3D getColumnName(md.getColumnName(i= )); - transformer.start(columnName, EMPTY_ATTRIBUTES); - serializeData(manager, getColumnValue(i)); - transformer.end(columnName); - } - } else if (isupdate && !isstoredprocedure) { - transformer.start("returncode", EMPTY_ATTRIBUTES); - serializeData(manager, String.valueOf(rv)); - transformer.end("returncode"); + start(columnName, EMPTY_ATTRIBUTES); + serializeData(getColumnValue(i)); + end(columnName); + } + } else if (isUpdate && !isStoredProcedure) { + start("returncode", EMPTY_ATTRIBUTES); + serializeData(String.valueOf(rv)); + end("returncode"); rv =3D -1; // we only want the return code shown once. } } =20 - protected void serializeStoredProcedure(ServiceManager manager) + protected void serializeStoredProcedure() throws SQLException, SAXException { if (outParametersNames =3D=3D null || cst =3D=3D null) { return; @@ -1364,34 +1428,34 @@ try { Object obj =3D cst.getObject(counter.intValue()); if (!(obj instanceof ResultSet)) { - transformer.start((String) outParametersNames.get(= counter), EMPTY_ATTRIBUTES); - serializeData(manager, SQLTransformer.getStringVal= ue(obj)); - transformer.end((String) outParametersNames.get(co= unter)); + start((String) outParametersNames.get(counter), EM= PTY_ATTRIBUTES); + serializeData(getStringValue(obj)); + end((String) outParametersNames.get(counter)); } else { ResultSet rs =3D (ResultSet) obj; try { - transformer.start((String) outParametersNames.= get(counter), EMPTY_ATTRIBUTES); + start((String) outParametersNames.get(counter)= , EMPTY_ATTRIBUTES); ResultSetMetaData md =3D rs.getMetaData(); while (rs.next()) { - transformer.start(this.row_name, EMPTY_ATT= RIBUTES); + start(this.rowElement, EMPTY_ATTRIBUTES); for (int i =3D 1; i <=3D md.getColumnCount= (); i++) { String columnName =3D getColumnName(md= .getColumnName(i)); - transformer.start(columnName, EMPTY_AT= TRIBUTES); + start(columnName, EMPTY_ATTRIBUTES); if (md.getColumnType(i) =3D=3D 8) { /= / prevent nasty exponent notation - serializeData(manager, SQLTransfor= mer.getStringValue(rs.getBigDecimal(i))); + serializeData(getStringValue(rs.ge= tBigDecimal(i))); } else { - serializeData(manager, SQLTransfor= mer.getStringValue(rs.getObject(i))); + serializeData(getStringValue(rs.ge= tObject(i))); } - transformer.end(columnName); + end(columnName); } - transformer.end(this.row_name); + end(this.rowElement); } } finally { try { rs.close(); } catch (SQLException ignored) { } } - transformer.end((String) outParametersNames.get(co= unter)); + end((String) outParametersNames.get(counter)); } } catch (SQLException e) { getLogger().error("Caught a SQLException", e); @@ -1412,6 +1476,35 @@ // Do nothing } return columnName; + } + + /** + * Convert object to string represenation + */ + private String getStringValue(Object object) { + if (object instanceof byte[]) { + // FIXME Encoding? + return new String((byte[]) object); + } else if (object instanceof char[]) { + return new String((char[]) object); + } else if (object !=3D null) { + return object.toString(); + } + + return ""; + } + + private void start(String name, Attributes attr) + throws SAXException { + SQLTransformer.this.start(this.outUri, this.outPrefix, name, a= ttr); + } + + private void end(String name) throws SAXException { + SQLTransformer.this.end(this.outUri, this.outPrefix, name); + } + + private void data(String data) throws SAXException { + SQLTransformer.this.data(data); } } =20 Modified: cocoon/branches/BRANCH_2_1_X/status.xml URL: http://svn.apache.org/viewcvs/cocoon/branches/BRANCH_2_1_X/status.xml?= rev=3D168374&r1=3D168373&r2=3D168374&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- cocoon/branches/BRANCH_2_1_X/status.xml (original) +++ cocoon/branches/BRANCH_2_1_X/status.xml Thu May 5 11:32:33 2005 @@ -196,6 +196,17 @@ =20 + + Databases: SQLTransformer: Each query can now have connection with o= wn + database connection configuration parameters. Queries with same conf= iguration + will share single database connection. You can force queries to crea= te private + connection using own-connection configuration parameter. + + + Databases: SQLTransformer: Each query can now have own output namesp= ace and + prefix. If desired output namespace already in use, existing prefix = will be + used. + Databases: SQLTransformer: Support multiple nested queries within on= e query.