001: /*
002: * Copyright 2002-2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jdbc.object;
018:
019: import java.sql.ResultSet;
020: import java.sql.SQLException;
021: import java.sql.Types;
022:
023: import javax.sql.DataSource;
024:
025: import org.springframework.dao.TypeMismatchDataAccessException;
026: import org.springframework.jdbc.core.SingleColumnRowMapper;
027: import org.springframework.jdbc.support.JdbcUtils;
028:
029: /**
030: * SQL "function" wrapper for a query that returns a single row of results.
031: * The default behavior is to return an int, but that can be overridden by
032: * using the constructor with an extra return type parameter.
033: *
034: * <p>Intended to use to call SQL functions that return a single result using a
035: * query like "select user()" or "select sysdate from dual". It is not intended
036: * for calling more complex stored functions or for using a CallableStatement to
037: * invoke a stored procedure or stored function. Use StoredProcedure or SqlCall
038: * for this type of processing.
039: *
040: * <p>This is a concrete class, which there is often no need to subclass.
041: * Code using this package can create an object of this type, declaring SQL
042: * and parameters, and then invoke the appropriate <code>run</code> method
043: * repeatedly to execute the function. Subclasses are only supposed to add
044: * specialized <code>run</code> methods for specific parameter and return types.
045: *
046: * <p>Like all RdbmsOperation objects, SqlFunction objects are thread-safe.
047: *
048: * @author Rod Johnson
049: * @author Juergen Hoeller
050: * @author Jean-Pierre Pawlak
051: * @see org.springframework.jdbc.object.StoredProcedure
052: */
053: public class SqlFunction extends MappingSqlQuery {
054:
055: private final SingleColumnRowMapper rowMapper = new SingleColumnRowMapper();
056:
057: /**
058: * Constructor to allow use as a JavaBean.
059: * A DataSource, SQL and any parameters must be supplied before
060: * invoking the <code>compile</code> method and using this object.
061: * @see #setDataSource
062: * @see #setSql
063: * @see #compile
064: */
065: public SqlFunction() {
066: setRowsExpected(1);
067: }
068:
069: /**
070: * Create a new SqlFunction object with SQL, but without parameters.
071: * Must add parameters or settle with none.
072: * @param ds DataSource to obtain connections from
073: * @param sql SQL to execute
074: */
075: public SqlFunction(DataSource ds, String sql) {
076: setRowsExpected(1);
077: setDataSource(ds);
078: setSql(sql);
079: }
080:
081: /**
082: * Create a new SqlFunction object with SQL and parameters.
083: * @param ds DataSource to obtain connections from
084: * @param sql SQL to execute
085: * @param types SQL types of the parameters, as defined in the
086: * <code>java.sql.Types</code> class
087: * @see java.sql.Types
088: */
089: public SqlFunction(DataSource ds, String sql, int[] types) {
090: setRowsExpected(1);
091: setDataSource(ds);
092: setSql(sql);
093: setTypes(types);
094: }
095:
096: /**
097: * Create a new SqlFunction object with SQL, parameters and a result type.
098: * @param ds DataSource to obtain connections from
099: * @param sql SQL to execute
100: * @param types SQL types of the parameters, as defined in the
101: * <code>java.sql.Types</code> class
102: * @param resultType the type that the result object is required to match
103: * @see #setResultType(Class)
104: * @see java.sql.Types
105: */
106: public SqlFunction(DataSource ds, String sql, int[] types,
107: Class resultType) {
108: setRowsExpected(1);
109: setDataSource(ds);
110: setSql(sql);
111: setTypes(types);
112: setResultType(resultType);
113: }
114:
115: /**
116: * Specify the type that the result object is required to match.
117: * <p>If not specified, the result value will be exposed as
118: * returned by the JDBC driver.
119: */
120: public void setResultType(Class resultType) {
121: this .rowMapper.setRequiredType(resultType);
122: }
123:
124: /**
125: * This implementation of this method extracts a single value from the
126: * single row returned by the function. If there are a different number
127: * of rows returned, this is treated as an error.
128: */
129: protected Object mapRow(ResultSet rs, int rowNum)
130: throws SQLException {
131: return this .rowMapper.mapRow(rs, rowNum);
132: }
133:
134: /**
135: * Convenient method to run the function without arguments.
136: * @return the value of the function
137: */
138: public int run() {
139: return run(null);
140: }
141:
142: /**
143: * Convenient method to run the function with a single int argument.
144: * @param parameter single int parameter
145: * @return the value of the function
146: */
147: public int run(int parameter) {
148: return run(new Object[] { new Integer(parameter) });
149: }
150:
151: /**
152: * Analogous to the SqlQuery.execute([]) method. This is a
153: * generic method to execute a query, taken a number of arguments.
154: * @param parameters array of parameters. These will be objects or
155: * object wrapper types for primitives.
156: * @return the value of the function
157: */
158: public int run(Object[] parameters) {
159: Object obj = super .findObject(parameters);
160: if (!(obj instanceof Number)) {
161: throw new TypeMismatchDataAccessException(
162: "Couldn't convert result object [" + obj
163: + "] to int");
164: }
165: return ((Number) obj).intValue();
166: }
167:
168: /**
169: * Convenient method to run the function without arguments,
170: * returning the value as an object.
171: * @return the value of the function
172: */
173: public Object runGeneric() {
174: return findObject((Object[]) null);
175: }
176:
177: /**
178: * Convenient method to run the function with a single int argument.
179: * @param parameter single int parameter
180: * @return the value of the function as an Object
181: */
182: public Object runGeneric(int parameter) {
183: return findObject(parameter);
184: }
185:
186: /**
187: * Analogous to the <code>SqlQuery.findObject(Object[])</code> method.
188: * This is a generic method to execute a query, taken a number of arguments.
189: * @param parameters array of parameters. These will be objects or
190: * object wrapper types for primitives.
191: * @return the value of the function, as an Object
192: * @see #execute(Object[])
193: */
194: public Object runGeneric(Object[] parameters) {
195: return findObject(parameters);
196: }
197:
198: }
|