Peter, Kosh,

I've got a new iteration of the stored procedure support for
esql. (Kosh, I will mail you the necessary files separately because
you indicated that you have problems with CVS).

Bob, I've CC'ed you since you might be interested to try the
<esql:results from-column=""/> feature.


Since the next release is due in a couple of days I don't want to
commit these changes right now unless I hear success stories from
you. The DBMS I use on a regulary basis does not support most of
what's in this patch so I rely on you to send bug reports (and
fixes!). Diff is against today's CVS HEAD as usual.

The attributes to <esql:call/> have been renamed to be a bit more
XMLish (needsQuery -> needs-query, resultsetFromObject ->
resultset-from-object) 

* use <esql:call/> instead of <esql:query/>, for stored procedures,
  use either DBMS specific syntax or JDBC escape syntax "{? = foo(?)}"

* if driver requires to use the "executeQuery()" method instead of
  the "execute()" method (like e.g. INFORMIX does), set
  'needs-query="true"' attribute to <esql:call/>

* if a result set is returned through the (only) return parameter of
  a stored procedure, one can use e.g. 'resultset-from-object="1"' as
  attribute to <esql:call/> to automatically use this result set. For
  a more general alternative see further below.

* <esql:call-results/> (child of <esql:execute-query/>) may contain
  code that will always be executed whether the call returned a
  resultset or not.

* all <esql:get-xxx/> tags accept new attribute 'from-call="yes"' to
  indicate that the value is retrieved from the CallableStatement
  rather than the current ResultSet.

* Retrieve a ResultSet from any column and use it like the result of a
  nested query by e.g. <esql:results from-column="1"/>. Of course the
  column needs to return a result that is castable to ResultSet.


Example:

              <esql:call>{? = 
foo(<esql:parameter><xsp:expr>1</xsp:expr></esql:parameter>)}</esql:call>
              <esql:call-results>
                 <esql:results from-column="1" from-call="true">
                      <esql:row-results>
                         <esql:get-string column="1"/>
                      </esql:row-results>
                 </esql:results>
              </esql:call-results>

Disclaimer:
I have only tested a fraction of these modifications as the DBMS I use
does not support the other variants. I have, however, tried to ensure
that the resulting code compiles well. Please try this code and report
failures (preferably with fixes :-) and successes to me and cocoon-dev

        Chris.

-- 
C h r i s t i a n       H a u l
[EMAIL PROTECTED]
    fingerprint: 99B0 1D9D 7919 644A 4837  7D73 FEF9 6856 335A 9E08
? esql.patch
Index: EsqlQuery.java
===================================================================
RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/language/markup/xsp/EsqlQuery.java,v
retrieving revision 1.2
diff -r1.2 EsqlQuery.java
12a13
> import java.sql.CallableStatement;
32a34
>   private boolean resultSetValid = false;
47a50,57
>   public EsqlQuery( ResultSet aResultSet ) {
>     this.connection = null;
>     this.statement = null;
>     this.query = null;
>     this.resultSetValid = true;
>     this.hasResultSet = (this.resultSet != null);
>   }
> 
120a131,143
> 
>   public CallableStatement prepareCall() throws SQLException {
>     switch(limitMethod) {
>       case EsqlConnection.LIMIT_METHOD_JDBC:
>         preparedStatement = connection.prepareCall( getQueryString(), 
>ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
>         break;
>       default:
>         preparedStatement = connection.prepareCall( getQueryString() );
>     };
>     statement = preparedStatement; 
>     return((CallableStatement)preparedStatement);
>   }
> 
124a148,151
>   public CallableStatement getCallableStatement() {
>     return((CallableStatement) preparedStatement);
>   }
> 
174,180c201,239
<     if (preparedStatement != null) {
<       hasResultSet = preparedStatement.execute();
<     }
<     else {
<       hasResultSet = statement.execute( getQueryString() );
<     }
<     return(hasResultSet);
---
>       return this.execute(false);
>   }
> 
>   /**
>    * some brain dead DBMSs (Oracle) return their result sets for
>    * callable statements through the some (i.e. the first) returned
>    * object.  
>    */
>   public boolean execute( int resultSetFromObject ) throws SQLException {
>       hasResultSet = this.execute(false);
>       resultSet = (ResultSet) ((CallableStatement) preparedStatement).getObject(1);
>       resultSetValid = true;
>       return hasResultSet;
>   }
> 
>   /**
>    * some other brain dead DBMSs (Informix) don't like their callable
>    * statements to be 'execute'd but require 'executeQuery' instead.
>    */
>   public boolean execute( boolean needsQuery ) throws SQLException {
>       if ( needsQuery ) {
>           if (preparedStatement != null) {
>               resultSet = preparedStatement.executeQuery();
>           }
>           else {
>               resultSet = statement.executeQuery( getQueryString() );
>           }
>           hasResultSet = (resultSet != null);
>           resultSetValid = true;
>       } else {
>           if (preparedStatement != null) {
>               hasResultSet = preparedStatement.execute();
>           }
>           else {
>               hasResultSet = statement.execute( getQueryString() );
>           }
>           resultSetValid = false;
>       }
>       return(hasResultSet);
212,213c271,275
<     resultSet = statement.getResultSet();
<     resultSetMetaData = resultSet.getMetaData();
---
>     if ( resultSetValid ) {
>         resultSetMetaData = resultSet.getMetaData();
>     } else {
>         resultSet = statement.getResultSet();
>     }
Index: java/esql.xsl
===================================================================
RCS file: 
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl,v
retrieving revision 1.4
diff -r1.4 esql.xsl
207a208
>       <xsp:include>java.sql.CallableStatement</xsp:include>
440c441,443
<   <xsl:variable name="query"><xsl:call-template 
name="get-nested-string"><xsl:with-param name="content" 
select="esql:query"/></xsl:call-template></xsl:variable>
---
> 
>   <xsl:variable name="query"><xsl:choose><xsl:when 
>test="esql:query"><xsl:call-template name="get-nested-string"><xsl:with-param 
>name="content" select="esql:query"/></xsl:call-template></xsl:when><xsl:when 
>test="esql:call"><xsl:call-template name="get-nested-string"><xsl:with-param 
>name="content" 
>select="esql:call"/></xsl:call-template></xsl:when></xsl:choose></xsl:variable>
> 
462a466,505
>         <xsl:when test="esql:call">
>           try {
>             _esql_query.prepareCall();
>           } catch (SQLException _esql_exception_<xsl:value-of 
>select="generate-id(.)"/>) {
>             throw new RuntimeException("Error preparing statement: " + 
>_esql_query.getQueryString() + ": "+_esql_exception_<xsl:value-of 
>select="generate-id(.)"/>.getMessage());
>           }
>           <xsl:for-each select="esql:call//esql:parameter">
>             try {
>             <xsl:if test="@direction='out' or @direction='inout'">
>               <xsl:text>_esql_query.getCallableStatement().</xsl:text>
>               registerOutParameter(<xsl:value-of select="position()"/>, 
>Types.<xsl:call-template name="get-Sql-Type"><xsl:with-param 
>name="type"><xsl:value-of 
>select="@type"/></xsl:with-param></xsl:call-template><xsl:if test="@typename">, 
><xsl:value-of select="@typename"/> </xsl:if>);
>             </xsl:if>
>             <xsl:if test="not(@direction) or @direction='inout'">
>               <xsl:text>_esql_query.getCallableStatement().</xsl:text>
>               <xsl:choose>
>                 <xsl:when test="@type">
>                   <xsl:variable name="type"><xsl:value-of 
>select="concat(translate(substring(@type,1,1),'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ'),substring(@type,2))"/></xsl:variable>
>                   <xsl:text>set</xsl:text><xsl:value-of 
>select="$type"/>(<xsl:value-of select="position()"/>,<xsl:call-template 
>name="get-nested-content"><xsl:with-param name="content" 
>select="."/></xsl:call-template>);<xsl:text>
> </xsl:text>
>               </xsl:when>
>               <xsl:otherwise>
>                 <xsl:text>setString(</xsl:text><xsl:value-of 
>select="position()"/>,String.valueOf(<xsl:call-template 
>name="get-nested-string"><xsl:with-param name="content" 
>select="."/></xsl:call-template>));<xsl:text>
> </xsl:text>
>               </xsl:otherwise>
>             </xsl:choose>
>           </xsl:if>
>             } catch (SQLException _esql_exception_<xsl:value-of 
>select="generate-id(.)"/>) {
>               throw new RuntimeException("Error setting parameter on statement: " + 
>_esql_query.getQueryString() + ": "+_esql_exception_<xsl:value-of 
>select="generate-id(.)"/>);
>             }
>           </xsl:for-each>
>           try {
>           <xsl:choose>
>             <xsl:when test="esql:call[@needs-query='true' or 
>@needs-query='yes']">_esql_query.execute(true);</xsl:when>
>             <xsl:when 
>test="esql:call[@resultset-from-object]">_esql_query.execute(<xsl:copy-of 
>select="esql:call[@resultset-from-object]"/>);</xsl:when>
>             <xsl:otherwise>_esql_query.execute();</xsl:otherwise>
>           </xsl:choose>
>           } catch (SQLException _esql_exception_<xsl:value-of 
>select="generate-id(.)"/>) {
>             throw new RuntimeException("Error executing prepared statement: " + 
>_esql_query.getQueryString() + ": "+_esql_exception_<xsl:value-of 
>select="generate-id(.)"/>);
>           }
>         </xsl:when>
509a553,558
>       <xsl:if test="esql:call">
>         // call results
>         <xsp:content>
>           <xsl:apply-templates select="esql:call-results"/>
>         </xsp:content>
>       </xsl:if>
561a611
> <xsl:template match="esql:call//esql:parameter">"?"</xsl:template>
572a623,631
> <xsl:template match="esql:execute-query//esql:call-results">
>   <xsp:logic>
>   // call results2
>   </xsp:logic>
>   <xsp:content>
>     <xsl:apply-templates/>
>   </xsp:content>
> </xsl:template>
> 
784c843
< <xsl:template match="esql:row-results//esql:get-string" name="get-string">
---
> <xsl:template 
>match="esql:row-results//esql:get-string|esql:call-results//esql:get-string" 
>name="get-string">
794c853
< <xsl:template match="esql:row-results//esql:get-date">
---
> <xsl:template 
>match="esql:row-results//esql:get-date|esql:call-results//esql:get-date">
806c865
< <xsl:template match="esql:row-results//esql:get-time">
---
> <xsl:template 
>match="esql:row-results//esql:get-time|esql:call-results//esql:get-time">
818c877
< <xsl:template match="esql:row-results//esql:get-timestamp">
---
> <xsl:template 
>match="esql:row-results//esql:get-timestamp|esql:call-results//esql:get-timestamp">
830c889
< <xsl:template match="esql:row-results//esql:get-boolean">
---
> <xsl:template 
>match="esql:row-results//esql:get-boolean|esql:call-results//esql:get-boolean">
835c894
< <xsl:template match="esql:row-results//esql:get-double">
---
> <xsl:template 
>match="esql:row-results//esql:get-double|esql:call-results//esql:get-double">
847c906
< <xsl:template match="esql:row-results//esql:get-float">
---
> <xsl:template 
>match="esql:row-results//esql:get-float|esql:call-results//esql:get-float">
864c923
< <xsl:template match="esql:row-results//esql:get-object">
---
> <xsl:template 
>match="esql:row-results//esql:get-object|esql:call-results//esql:get-object">
869c928
< <xsl:template match="esql:row-results//esql:get-array">
---
> <xsl:template 
>match="esql:row-results//esql:get-array|esql:call-results//esql:get-array">
874c933
< <xsl:template match="esql:row-results//esql:get-struct">
---
> <xsl:template 
>match="esql:row-results//esql:get-struct|esql:call-results//esql:get-struct">
879c938
< <xsl:template match="esql:row-results//esql:get-int">
---
> <xsl:template match="esql:row-results//esql:get-int|esql:call-results//esql:get-int">
884c943
< <xsl:template match="esql:row-results//esql:get-long">
---
> <xsl:template 
>match="esql:row-results//esql:get-long|esql:call-results//esql:get-long">
889c948
< <xsl:template match="esql:row-results//esql:get-short">
---
> <xsl:template 
>match="esql:row-results//esql:get-short|esql:call-results//esql:get-short">
894c953
< <xsl:template match="esql:row-results//esql:get-ascii">
---
> <xsl:template 
>match="esql:row-results//esql:get-ascii|esql:call-results//esql:get-ascii">
902c961
< <xsl:template match="esql:row-results//esql:get-xml">
---
> <xsl:template match="esql:row-results//esql:get-xml|esql:call-results//esql:get-xml">
975c1034
< <xsl:template 
match="esql:row-results//esql:get-row-position|esql:results//esql:get-row-position">
---
> <xsl:template 
>match="esql:row-results//esql:get-row-position|esql:results//esql:get-row-position|esql:call-results//esql:get-row-position">
980c1039
< <xsl:template match="esql:row-results//esql:get-column-name">
---
> <xsl:template 
>match="esql:row-results//esql:get-column-name|esql:call-results//esql:get-column-name">
985c1044
< <xsl:template match="esql:row-results//esql:get-column-label">
---
> <xsl:template 
>match="esql:row-results//esql:get-column-label|esql:call-results//esql:get-column-label">
990c1049
< <xsl:template match="esql:row-results//esql:get-column-type-name">
---
> <xsl:template 
>match="esql:row-results//esql:get-column-type-name|esql:call-results//esql:get-column-type-name">
995c1054
< <xsl:template match="esql:row-results//esql:get-column-type">
---
> <xsl:template 
>match="esql:row-results//esql:get-column-type|esql:call-results//esql:get-column-type">
1003a1063,1096
> <xspdoc:desc></xspdoc:desc>
> <xsl:template 
>match="esql:row-results//esql:results[@from-column]|esql:call-results//esql:results[@from-column]"
> priority="2">
> <xsp:logic>
>   // nested result set
>     if (_esql_query != null) {
>       _esql_queries.push(_esql_query);
>     }
>     _esql_query = new EsqlQuery((ResultSet) <xsl:call-template 
>name="get-resultset"/>.getObject(<xsl:value-of select="@from-column"/>));
>     {
>       if (_esql_query.hasResultSet()) {
>         do {
>           _esql_query.getResultRows();
> 
>           if (_esql_query.nextRow()) {
>             <xsl:apply-templates select="esql:row-results"/>
>           }
>           else {
>             <xsl:apply-templates select="esql:no-results"/>
>           }
>           _esql_query.getResultSet().close();
> 
>         } while(_esql_query.getMoreResults());
>       } else {
>         <xsl:apply-templates select="esql:no-results"/>
>       }
>     }
>     if (_esql_queries.empty()) {
>       _esql_query = null;
>     } else {
>       _esql_query = (EsqlQuery)_esql_queries.pop();
>     }
>   </xsp:logic>
> </xsl:template>
> 
1020c1113
<   <xsl:call-template name="get-query"/><xsl:text>.getResultSet()</xsl:text>
---
>   <xsl:call-template name="get-query"/><xsl:choose><xsl:when test="@from-call='yes' 
>or 
>@from-call='true'"><xsl:text>.getCallableStatement()</xsl:text></xsl:when><xsl:otherwise><xsl:text>.getResultSet()</xsl:text></xsl:otherwise></xsl:choose>
1089a1183,1203
> 
> <xsl:template name="get-Sql-Type">
>   <xsl:param name="type"/>
>   <xsl:choose>
>     <!-- just do the 'unusual' mappings -->
>     <xsl:when test="$type='Byte'">TINYINT</xsl:when>
>     <xsl:when test="$type='Short'">SMALLINT</xsl:when>
>     <xsl:when test="$type='Int'">INTEGER</xsl:when>
>     <xsl:when test="$type='Long'">BIGINT</xsl:when>
>     <xsl:when test="$type='Float'">REAL</xsl:when>
>     <xsl:when test="$type='BigDecimal'">DECIMAL</xsl:when>
>     <xsl:when test="$type='Boolean'">BIT</xsl:when>
>     <xsl:when test="$type='String'">VARCHAR</xsl:when>
>     <xsl:when test="$type='Bytes'">BINARY</xsl:when>
>     <xsl:when test="$type='AsciiStream'">LONGVARCHAR</xsl:when>
>     <xsl:when test="$type='UnicodeStream'">LONGVARCHAR</xsl:when>
>     <xsl:when test="$type='BinaryStream'">VARBINARY</xsl:when>
>     <xsl:otherwise><xsl:value-of 
>select="translate(@type,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/></xsl:otherwise>
>   </xsl:choose>
> </xsl:template>
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, email: [EMAIL PROTECTED]

Reply via email to