Team, I'm currently considering ORDBMS support in esql, well, actually, I do have a version here that does it for C2. Davanum asked me to post any patches to esql.xsl to this list before applying them. So please comment the attached diff. This mail is largely based on my posting from jul-04 on ordbms support for esql with few modifications and comments what is already in place. The simplest ORDBMS support would be to allow the user to get an object from the query and to leave it to her/him how to deal with it. (done) In addition one could extend get-columns to extract advanced datatypes as well. Over here on Informix IUS 9.21 these are mostly of java.sql.Types.STRUCT for row types and java.sql.Types.OTHER for everything else like sets, lists, bags. One way to determine the correct type would be to try to cast the object to an appropriate interface, say java.util.Set. (done -- C2 only) How should the structure of an attribute be represented? Nesting alone wouldn't do since it wouldn't be possible to distinguish sets from structs. So we should introduce something like "sql-list", "sql-row", "sql-set", plus some "sql-item" elements to capture e.g. the list members. So far I didn't find a way e.g. to name the components of a struct. (done -- C2 only) Another issue arises: encoding. "First class" attributes can be read through getBytes() and converted afterwards. But nested attributes only offer a toString() method, right? Would it be right to disable the encoding parameter on nested attributes? (currently no encoding for complex attributes) Another feature could be, to manipulate the type mapping table for a jdbc connection and allow to map advanced or user defined types to map to a user provided java class. Jdbc drivers sometimes come with a utility to create such a class from a db schema. (not done -- should this be done? should this be done in cocoon.xconf per connection pool?) Other features I'd like to see in esql: <esql:row-results> &c. "swallow" nested text which is not what users expect (see cocoon-users list). Therefore it would be nice if the text would be automtically enclosed in <xsp:content>. (done -- example query is "select count(*) from mytable": <esql:row-results> Currently <esql:get-int column="1"/> rows are present. </esql:row-results> ) Supplying column names / numbers from a XSP variable (esql differs from other taglibs in that it doesn't use the "<esql:param name="column">1</esql:param>" notation, instead it uses "<esql:column></esql:column>". I would like to change that.) (done, you can now <esql:get-column> <esql:param name="column"> <xsp:expr>i</xsp:expr> </esql:param> </esql:get-column> ) Offer some direct paths to the esql code, like "get-metadata", "get-column-type", "get-object", or even "get-resultset" (done) Make "get-xml" more powerful so that the db needs only to store fragments of an xml document. Currently, only a root element without any attributes is allowed here. Thus it is not possible e.g. to specify a namespace for the fragment. (not done yet -- why doesn't it inherit the namespaces from the original xsp? Is there a way to figure them out?) BTW since it is possible to include other logicsheets, would it be wise to put all utility tags (copy-all, get-nested-content, get-parameter and the like) to a common logicsheet so that they could easily be used by new logicsheets? 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
Index: src/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl =================================================================== RCS file: /home/cvs/xml-cocoon2/src/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl,v retrieving revision 1.11 diff -u -r1.11 esql.xsl --- src/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl 2001/07/10 14:04:15 1.11 +++ src/org/apache/cocoon/components/language/markup/xsp/java/esql.xsl 2001/07/11 +11:18:07 @@ -71,6 +71,8 @@ <xsl:variable name="cocoon1-xsp-namespace-uri">http://www.apache.org/1999/XSP/Core</xsl:variable> <xsl:variable name="cocoon2-xsp-namespace-uri">http://apache.org/xsp</xsl:variable> +<xsl:variable name="prefix">esql</xsl:variable> + <xsl:variable name="environment"> <xsl:choose> <xsl:when test="starts-with($XSP-ENVIRONMENT,$cocoon1-environment)"> @@ -159,6 +161,44 @@ </xsl:choose> </xsl:template> + + <xsl:template name="get-parameter"> + <xsl:param name="name"/> + <xsl:param name="default"/> + <xsl:param name="required">false</xsl:param> + + <xsl:variable name="qname"> + <xsl:value-of select="concat($prefix, ':param')"/> + </xsl:variable> + + <xsl:choose> + <xsl:when test="@*[name(.) = $name]">"<xsl:value-of select="@*[name(.) = +$name]"/>"</xsl:when> + <xsl:when test="(*[name(.) = $qname])[@name = $name]"> + <xsl:call-template name="get-nested-content"> + <xsl:with-param name="content" + select="(*[name(.) = $qname])[@name = $name]"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:choose> + <xsl:when test="string-length($default) = 0"> + <xsl:choose> + <xsl:when test="$required = 'true'"> + <xsl:call-template name="error"> + <xsl:with-param name="message">[Logicsheet processor] +Parameter '<xsl:value-of select="$name"/>' missing in dynamic tag <<xsl:value-of +select="name(.)"/>> + </xsl:with-param> + </xsl:call-template> + </xsl:when> + <xsl:otherwise>""</xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:otherwise><xsl:copy-of select="$default"/></xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + <xsl:template match="xsp:page"> <xsp:page> <xsl:apply-templates select="@*"/> @@ -177,6 +217,12 @@ <xsp:include>java.io.PrintWriter</xsp:include> <xsp:include>java.io.BufferedInputStream</xsp:include> <xsp:include>java.io.InputStream</xsp:include> + <xsp:include>java.util.Set</xsp:include> + <xsp:include>java.util.List</xsp:include> + <xsp:include>java.util.Iterator</xsp:include> + <xsp:include>java.util.ListIterator</xsp:include> + <xsp:include>java.sql.Struct</xsp:include> + <xsp:include>java.sql.Types</xsp:include> <xsl:if test="$environment = 'cocoon2'"> <xsp:include>org.apache.cocoon.components.language.markup.xsp.XSPUtil</xsp:include> </xsl:if> @@ -268,6 +314,44 @@ return new String(buffer); } + + <xsl:choose> + <xsl:when test="$environment = 'cocoon1'"> + </xsl:when> + <xsl:when test="$environment = 'cocoon2'"> + protected void _esql_printObject ( Object obj, AttributesImpl xspAttr) +throws SAXException + { + try { + ListIterator j=((List)obj).listIterator(); + <xsp:element name="sql-list"> + <xsp:logic> + while (j.hasNext()){ + <xsp:element name="sql-list-item"> + <xsp:attribute +name="pos"><xsp:expr>j.nextIndex()</xsp:expr></xsp:attribute> + +<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic> + </xsp:element> + }; + </xsp:logic> + </xsp:element> + } catch (Exception e){ + try { + Iterator j=((Set)obj).iterator(); + <xsp:element name="sql-set"> + <xsp:logic> + while (j.hasNext()){ + <xsp:element name="sql-set-item"> + +<xsp:logic>this._esql_printObject(j.next(),xspAttr);</xsp:logic> + </xsp:element> + }; + </xsp:logic> + </xsp:element> + } catch (Exception f) { + <xsp:content><xsp:expr>obj</xsp:expr></xsp:content>; + } + } + } + </xsl:when> + </xsl:choose> </xsp:logic> <xsl:apply-templates/> </xsp:page> @@ -554,17 +638,23 @@ <xsl:template match="esql:query//esql:parameter">"?"</xsl:template> <xsl:template match="esql:execute-query//esql:results"> - <xsl:apply-templates/> + <xsp:content> + <xsl:apply-templates/> + </xsp:content> </xsl:template> <xsl:template match="esql:execute-query//esql:error-results"> - <xsl:apply-templates/> + <xsp:content> + <xsl:apply-templates/> + </xsp:content> </xsl:template> <xsl:template match="esql:execute-query//esql:no-results"> <xsp:logic> if (_esql_query.position == _esql_query.skip_rows) { - <xsl:apply-templates/> + <xsp:content> + <xsl:apply-templates/> + </xsp:content> } </xsp:logic> </xsl:template> @@ -576,7 +666,9 @@ <xsl:template match="esql:results//esql:row-results"> <xsp:logic> while (_esql_query.resultset.next()) { - <xsl:apply-templates/> + <xsp:content> + <xsl:apply-templates/> + </xsp:content> if (_esql_connection.use_limit_clause == 0 && _esql_query.max_rows != -1 && _esql_query.position - _esql_query.skip_rows == _esql_query.max_rows-1) { _esql_query.position++; break; @@ -584,7 +676,7 @@ _esql_query.position++; } if (_esql_query.resultset.next()) { - <xsl:apply-templates select="following-sibling::esql:more-results" mode="more"/> + <xsl:apply-templates select="following-sibling::esql:more-results" +mode="more"/> _esql_query.position++; } </xsp:logic> @@ -593,7 +685,9 @@ <xsl:template match="esql:results//esql:more-results"/> <xsl:template match="esql:results//esql:more-results" mode="more"> - <xsl:apply-templates/> + <xsp:content> + <xsl:apply-templates/> + </xsp:content> </xsl:template> <xspdoc:desc>results in a set of elements whose names are the names of the columns. the elements each have one text child, whose value is the value of the column interpreted as a string. No special formatting is allowed here. If you want to mess around with the names of the elements or the value of the text field, use the type-specific get methods and write out the result fragment yourself.</xspdoc:desc> @@ -644,12 +738,35 @@ </xsl:otherwise> </xsl:choose> </xsp:param> - <xsp:expr> - <xsl:call-template name="get-string-encoded"> - <xsl:with-param name="column-spec">_esql_i</xsl:with-param> - <xsl:with-param name="resultset">_esql_query.resultset</xsl:with-param> - </xsl:call-template> - </xsp:expr> + <xsp:logic> + switch(_esql_query.resultset.getMetaData().getColumnType(_esql_i)){ + case java.sql.Types.ARRAY: + case java.sql.Types.STRUCT: + <xsp:element name="sql-row"> + <xsp:logic> + Object[] _esql_struct = ((Struct) +_esql_query.resultset.getObject(_esql_i)).getAttributes(); + for ( int _esql_k=0; _esql_k<_esql_struct.length; +_esql_k++){ + <xsp:element +name="sql-row-item"><xsp:logic>this._esql_printObject(_esql_struct[_esql_k],xspAttr);</xsp:logic></xsp:element> + } + </xsp:logic> + </xsp:element> + break; + + case java.sql.Types.OTHER: // This is what Informix uses for Sets, +Bags, Lists + this._esql_printObject(_esql_query.resultset.getObject(_esql_i), +xspAttr); + break; + + default: + // standard type + <xsp:content> + <xsp:expr> + <xsl:call-template name="get-string-encoded"> + <xsl:with-param name="column-spec">_esql_i</xsl:with-param> + <xsl:with-param +name="resultset">_esql_query.resultset</xsl:with-param> + </xsl:call-template> + </xsp:expr></xsp:content> + } + </xsp:logic> </xsp:element> } this.characters("\n"); @@ -738,6 +855,16 @@ </xsl:choose> </xsl:template> +<xspdoc:desc>returns the current result set</xspdoc:desc> +<xsl:template match="esql:results//esql:get-resultset"> + <xsp:expr><xsl:call-template name="get-resultset"/></xsp:expr> +</xsl:template> + +<xspdoc:desc>returns the value of the given column as an object</xspdoc:desc> +<xsl:template match="esql:row-results//esql:get-object"> + <xsp:expr><xsl:call-template name="get-resultset"/>.getObject(<xsl:call-template +name="get-column"/>)</xsp:expr> +</xsl:template> + <xspdoc:desc>returns the value of the given column as an integer</xspdoc:desc> <xsl:template match="esql:row-results//esql:get-int"> <xsp:expr><xsl:call-template name="get-resultset"/>.getInt(<xsl:call-template name="get-column"/>)</xsp:expr> @@ -831,6 +958,11 @@ <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData().getColumnCount()</xsp:expr> </xsl:template> +<xspdoc:desc>returns the metadata of the resultset.</xspdoc:desc> +<xsl:template match="esql:results//esql:get-metadata"> + <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData()</xsp:expr> +</xsl:template> + <xspdoc:desc>returns the position of the current row in the result set</xspdoc:desc> <xsl:template match="esql:row-results//esql:get-row-position|esql:results//esql:get-row-position"> <xsp:expr>_esql_query.position</xsp:expr> @@ -838,17 +970,22 @@ <xspdoc:desc>returns the name of the given column. the column mus tbe specified by number, not name.</xspdoc:desc> <xsl:template match="esql:row-results//esql:get-column-name"> - <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData().getColumnName(<xsl:value-of select="@column"/>)</xsp:expr> + <xsp:expr><xsl:call-template +name="get-resultset"/>.getMetaData().getColumnName(<xsl:call-template +name="get-column"/>)</xsp:expr> </xsl:template> <xspdoc:desc>returns the label of the given column. the column mus tbe specified by number, not name.</xspdoc:desc> <xsl:template match="esql:row-results//esql:get-column-label"> - <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData().getColumnLabel(<xsl:value-of select="@column"/>)</xsp:expr> + <xsp:expr><xsl:call-template +name="get-resultset"/>.getMetaData().getColumnLabel(<xsl:call-template +name="get-column"/>)</xsp:expr> </xsl:template> <xspdoc:desc>returns the name of the type of the given column. the column must be specified by number, not name.</xspdoc:desc> <xsl:template match="esql:row-results//esql:get-column-type-name"> - <xsp:expr><xsl:call-template name="get-resultset"/>.getMetaData().getColumnTypeName(<xsl:value-of select="@column"/>)</xsp:expr> + <xsp:expr><xsl:call-template +name="get-resultset"/>.getMetaData().getColumnTypeName(<xsl:call-template +name="get-column"/>)</xsp:expr> +</xsl:template> + +<xspdoc:desc>returns the type of the given column as int. the column must be +specified by number, not name.</xspdoc:desc> +<xsl:template match="esql:row-results//esql:get-column-type"> + <xsp:expr><xsl:call-template +name="get-resultset"/>.getMetaData().getColumnType(<xsl:call-template +name="get-column"/>)</xsp:expr> </xsl:template> <xspdoc:desc>allows null-column testing. Evaluates to a Java expression, which is true when the referred column contains a null-value for the current resultset row</xspdoc:desc> @@ -890,24 +1027,29 @@ <xspdoc:desc>used internally to determine which column is the given column. if a column attribute exists and itcvs server: Diffing src/org/apache/cocoon/components/language/programming s value is a number, it is taken to be the column's position. if the value is not a number, it is taken to be the column's name. if a column attribute does not exist, an esql:column element is assumed to exist and to render as a string (after all of the xsp instructions have been evaluated), which is taken to be the column's name.</xspdoc:desc> <xsl:template name="get-column"> + <xsl:variable name="column"> + <xsl:call-template name="get-parameter"> + <xsl:with-param name="name">column</xsl:with-param> + <xsl:with-param name="required">true</xsl:with-param> + </xsl:call-template> + </xsl:variable> <xsl:choose> - <xsl:when test="@column"> + <xsl:when test="starts-with($column,'"')"> + <xsl:variable name="raw-column"> + <xsl:value-of select="substring($column,2,string-length($column)-2)"/> + </xsl:variable> <xsl:choose> - <xsl:when test="not(string(number(@column))='NaN')"> - <xsl:value-of select="@column"/> + <xsl:when test="not(string(number($raw-column))='NaN')"> + <xsl:value-of select="$raw-column"/> </xsl:when> <xsl:otherwise> - <xsl:text>"</xsl:text> - <xsl:value-of select="@column"/> - <xsl:text>"</xsl:text> + <xsl:value-of select="$column"/> </xsl:otherwise> </xsl:choose> - </xsl:when> - <xsl:when test="esql:column"> - <xsl:call-template name="get-nested-string"> - <xsl:with-param name="content" select="esql:column"/> - </xsl:call-template> </xsl:when> + <xsl:otherwise> + <xsl:copy-of select="$column"/> + </xsl:otherwise> </xsl:choose> </xsl:template>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, email: [EMAIL PROTECTED]