001/* 002 * Copyright 2002-2012 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 * https://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 017package org.springframework.jdbc.object; 018 019import java.sql.ResultSet; 020import java.sql.SQLException; 021import javax.sql.DataSource; 022 023import org.springframework.dao.TypeMismatchDataAccessException; 024import org.springframework.jdbc.core.SingleColumnRowMapper; 025 026/** 027 * SQL "function" wrapper for a query that returns a single row of results. 028 * The default behavior is to return an int, but that can be overridden by 029 * using the constructor with an extra return type parameter. 030 * 031 * <p>Intended to use to call SQL functions that return a single result using a 032 * query like "select user()" or "select sysdate from dual". It is not intended 033 * for calling more complex stored functions or for using a CallableStatement to 034 * invoke a stored procedure or stored function. Use StoredProcedure or SqlCall 035 * for this type of processing. 036 * 037 * <p>This is a concrete class, which there is often no need to subclass. 038 * Code using this package can create an object of this type, declaring SQL 039 * and parameters, and then invoke the appropriate {@code run} method 040 * repeatedly to execute the function. Subclasses are only supposed to add 041 * specialized {@code run} methods for specific parameter and return types. 042 * 043 * <p>Like all RdbmsOperation objects, SqlFunction objects are thread-safe. 044 * 045 * @author Rod Johnson 046 * @author Juergen Hoeller 047 * @author Jean-Pierre Pawlak 048 * @see StoredProcedure 049 */ 050public class SqlFunction<T> extends MappingSqlQuery<T> { 051 052 private final SingleColumnRowMapper<T> rowMapper = new SingleColumnRowMapper<T>(); 053 054 055 /** 056 * Constructor to allow use as a JavaBean. 057 * A DataSource, SQL and any parameters must be supplied before 058 * invoking the {@code compile} method and using this object. 059 * @see #setDataSource 060 * @see #setSql 061 * @see #compile 062 */ 063 public SqlFunction() { 064 setRowsExpected(1); 065 } 066 067 /** 068 * Create a new SqlFunction object with SQL, but without parameters. 069 * Must add parameters or settle with none. 070 * @param ds DataSource to obtain connections from 071 * @param sql SQL to execute 072 */ 073 public SqlFunction(DataSource ds, String sql) { 074 setRowsExpected(1); 075 setDataSource(ds); 076 setSql(sql); 077 } 078 079 /** 080 * Create a new SqlFunction object with SQL and parameters. 081 * @param ds DataSource to obtain connections from 082 * @param sql SQL to execute 083 * @param types SQL types of the parameters, as defined in the 084 * {@code java.sql.Types} class 085 * @see java.sql.Types 086 */ 087 public SqlFunction(DataSource ds, String sql, int[] types) { 088 setRowsExpected(1); 089 setDataSource(ds); 090 setSql(sql); 091 setTypes(types); 092 } 093 094 /** 095 * Create a new SqlFunction object with SQL, parameters and a result type. 096 * @param ds DataSource to obtain connections from 097 * @param sql SQL to execute 098 * @param types SQL types of the parameters, as defined in the 099 * {@code java.sql.Types} class 100 * @param resultType the type that the result object is required to match 101 * @see #setResultType(Class) 102 * @see java.sql.Types 103 */ 104 public SqlFunction(DataSource ds, String sql, int[] types, Class<T> resultType) { 105 setRowsExpected(1); 106 setDataSource(ds); 107 setSql(sql); 108 setTypes(types); 109 setResultType(resultType); 110 } 111 112 113 /** 114 * Specify the type that the result object is required to match. 115 * <p>If not specified, the result value will be exposed as 116 * returned by the JDBC driver. 117 */ 118 public void setResultType(Class<T> resultType) { 119 this.rowMapper.setRequiredType(resultType); 120 } 121 122 123 /** 124 * This implementation of this method extracts a single value from the 125 * single row returned by the function. If there are a different number 126 * of rows returned, this is treated as an error. 127 */ 128 @Override 129 protected T mapRow(ResultSet rs, int rowNum) throws SQLException { 130 return this.rowMapper.mapRow(rs, rowNum); 131 } 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(new Object[0]); 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[] {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("Couldn't convert result object [" + obj + "] to int"); 162 } 163 return ((Number) obj).intValue(); 164 } 165 166 /** 167 * Convenient method to run the function without arguments, 168 * returning the value as an object. 169 * @return the value of the function 170 */ 171 public Object runGeneric() { 172 return findObject((Object[]) null); 173 } 174 175 /** 176 * Convenient method to run the function with a single int argument. 177 * @param parameter single int parameter 178 * @return the value of the function as an Object 179 */ 180 public Object runGeneric(int parameter) { 181 return findObject(parameter); 182 } 183 184 /** 185 * Analogous to the {@code SqlQuery.findObject(Object[])} method. 186 * This is a generic method to execute a query, taken a number of arguments. 187 * @param parameters array of parameters. These will be objects or 188 * object wrapper types for primitives. 189 * @return the value of the function, as an Object 190 * @see #execute(Object[]) 191 */ 192 public Object runGeneric(Object[] parameters) { 193 return findObject(parameters); 194 } 195 196}