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]