1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.jdbc.object;
  17. import java.sql.ResultSet;
  18. import java.sql.SQLException;
  19. import java.sql.Types;
  20. import javax.sql.DataSource;
  21. import org.springframework.dao.InvalidDataAccessApiUsageException;
  22. import org.springframework.jdbc.support.JdbcUtils;
  23. /**
  24. * SQL "function" wrapper for a query that returns a single row of results.
  25. * The default behavior is to return an int, but that can be overridden by
  26. * using the methods with an extra return type parameter.
  27. *
  28. * <p>Intended to use to call SQL functions that return a single result using a
  29. * query like "select user()" or "select sysdate from dual". It is not intended
  30. * for calling more complex stored functions or for using a CallableStatement to
  31. * invoke a stored procedure or stored function. Use StoredProcedure or SqlCall
  32. * for this type of processing.
  33. *
  34. * <p>This is a concrete class, which there is normally no need to subclass.
  35. * Code using this package can create an object of this type, declaring SQL
  36. * and parameters, and then invoke the appropriate run method repeatedly to
  37. * execute the function.
  38. *
  39. * <p>Like all RdbmsOperation objects, SqlFunction objects are threadsafe.
  40. *
  41. * @author Rod Johnson
  42. * @author Isabelle Muszynski
  43. * @author Jean-Pierre Pawlak
  44. * @see org.springframework.jdbc.object.StoredProcedure
  45. */
  46. public class SqlFunction extends MappingSqlQuery {
  47. /** The SQL return type of the function */
  48. private int retType;
  49. /**
  50. * Constructor to allow use as a JavaBean.
  51. * A DataSource, SQL and any parameters must be supplied
  52. * before invoking the compile() method and using this object.
  53. */
  54. public SqlFunction() {
  55. }
  56. /**
  57. * Create a new SQLFunction object with SQL and parameters.
  58. * @param ds DataSource to obtain connections from
  59. * @param sql SQL to execute
  60. * @param types SQL types of the parameters, as defined
  61. * in the java.sql.Types class
  62. */
  63. public SqlFunction(DataSource ds, String sql, int[] types) {
  64. setDataSource(ds);
  65. setSql(sql);
  66. setTypes(types);
  67. this.retType = Types.INTEGER;
  68. setRowsExpected(1);
  69. }
  70. /**
  71. * Create a new SQLFunction object with SQL, parameters and a
  72. * return type
  73. * @param ds DataSource to obtain connections from
  74. * @param sql SQL to execute
  75. * @param types SQL types of the parameters, as defined
  76. * in the java.sql.Types class
  77. * @param retType SQL type of the return value, as defined
  78. * in the java.sql.Types class
  79. * @exception InvalidDataAccessApiUsageException is thrown if the return
  80. * type is not numeric or char
  81. */
  82. public SqlFunction(DataSource ds, String sql, int[] types, int retType)
  83. throws InvalidDataAccessApiUsageException {
  84. setDataSource(ds);
  85. setSql(sql);
  86. setTypes(types);
  87. this.retType = JdbcUtils.translateType(retType);
  88. setRowsExpected(1);
  89. }
  90. /**
  91. * Create a new SQLFunction object with SQL, but without parameters.
  92. * Must add parameters or settle with none.
  93. * @param ds DataSource to obtain connections from
  94. * @param sql SQL to execute
  95. */
  96. public SqlFunction(DataSource ds, String sql) {
  97. setDataSource(ds);
  98. setSql(sql);
  99. this.retType = Types.INTEGER;
  100. setRowsExpected(1);
  101. }
  102. /**
  103. * Create a new SQLFunction object with SQL and return type, but without parameters.
  104. * Must add parameters or settle with none.
  105. * @param ds DataSource to obtain connections from
  106. * @param sql SQL to execute
  107. * @param retType SQL type of the return value, as defined
  108. * in the java.sql.Types class
  109. */
  110. public SqlFunction(DataSource ds, String sql, int retType) {
  111. setDataSource(ds);
  112. setSql(sql);
  113. this.retType = JdbcUtils.translateType(retType);
  114. setRowsExpected(1);
  115. }
  116. /**
  117. * This implementation of this method extracts a single value from the
  118. * single row returned by the function. If there are a different number
  119. * of rows returned, this is treated as an error.
  120. */
  121. protected Object mapRow(ResultSet rs, int rowNum) throws SQLException, InvalidDataAccessApiUsageException {
  122. if (rowNum != 0) {
  123. throw new InvalidDataAccessApiUsageException("SQL function '" + getSql() + "' can't return more than one row");
  124. }
  125. Object obj = null;
  126. switch (this.retType) {
  127. case Types.INTEGER:
  128. obj = new Integer(rs.getInt(1));
  129. break;
  130. case Types.NUMERIC:
  131. obj = new Double(rs.getDouble(1));
  132. break;
  133. case Types.VARCHAR:
  134. obj = new String(rs.getString(1));
  135. break;
  136. case Types.BIGINT:
  137. obj = new Long(rs.getLong(1));
  138. break;
  139. default:
  140. obj = rs.getObject(1);
  141. break;
  142. }
  143. return obj;
  144. }
  145. /**
  146. * Convenient method to run the function without arguments.
  147. * @return the value of the function
  148. */
  149. public int run() {
  150. Integer i = (Integer) super.findObject((Object[]) null);
  151. return i.intValue();
  152. }
  153. /**
  154. * Convenient method to run the function with a single int argument.
  155. * @param p single int argument
  156. * @return the value of the function
  157. */
  158. public int run(int p) {
  159. Integer i = (Integer) super.findObject(p);
  160. return i.intValue();
  161. }
  162. /**
  163. * Analogous to the SqlQuery.execute([]) method. This is a
  164. * generic method to execute a query, taken a number of arguments.
  165. * @param args array of arguments. These will be objects or
  166. * object wrapper types for primitives.
  167. * @return the value of the function
  168. */
  169. public int run(Object[] args) {
  170. Integer i = (Integer) super.findObject(args);
  171. return i.intValue();
  172. }
  173. /**
  174. * Convenient method to run the function without arguments,
  175. * returning the value as an object
  176. * @return the value of the function
  177. */
  178. public Object runGeneric() {
  179. return super.findObject((Object[]) null);
  180. }
  181. /**
  182. * Convenient method to run the function with a single int argument.
  183. * @param p single int argument
  184. * @return the value of the function as an Object
  185. */
  186. public Object runGeneric(int p) {
  187. return super.findObject(p);
  188. }
  189. /**
  190. * Analogous to the SqlQuery.execute([]) method. This is a
  191. * generic method to execute a query, taken a number of arguments.
  192. * @param args array of arguments. These will be objects or
  193. * object wrapper types for primitives.
  194. * @return the value of the function, as an Object
  195. */
  196. public Object runGeneric(Object[] args) {
  197. return super.findObject(args);
  198. }
  199. }