/spring-jdbc/src/test/java/org/springframework/jdbc/object/StoredProcedureTests.java

https://github.com/sidneyzhang/spring-framework · Java · 726 lines · 575 code · 114 blank · 37 comment · 1 complexity · acbe0b1b22fa49331a51b671d5a4ca2f MD5 · raw file

  1. /*
  2. * Copyright 2002-2012 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 static org.junit.Assert.assertEquals;
  18. import static org.junit.Assert.assertTrue;
  19. import static org.junit.Assert.fail;
  20. import static org.mockito.BDDMockito.given;
  21. import static org.mockito.Matchers.eq;
  22. import static org.mockito.Matchers.startsWith;
  23. import static org.mockito.Mockito.atLeastOnce;
  24. import static org.mockito.Mockito.mock;
  25. import static org.mockito.Mockito.never;
  26. import static org.mockito.Mockito.verify;
  27. import java.math.BigDecimal;
  28. import java.sql.CallableStatement;
  29. import java.sql.Connection;
  30. import java.sql.ResultSet;
  31. import java.sql.ResultSetMetaData;
  32. import java.sql.SQLException;
  33. import java.sql.Types;
  34. import java.util.HashMap;
  35. import java.util.List;
  36. import java.util.Map;
  37. import javax.sql.DataSource;
  38. import org.junit.After;
  39. import org.junit.Before;
  40. import org.junit.Rule;
  41. import org.junit.Test;
  42. import org.junit.rules.ExpectedException;
  43. import org.springframework.dao.DataAccessException;
  44. import org.springframework.dao.InvalidDataAccessApiUsageException;
  45. import org.springframework.jdbc.BadSqlGrammarException;
  46. import org.springframework.jdbc.core.CallableStatementCreator;
  47. import org.springframework.jdbc.core.JdbcTemplate;
  48. import org.springframework.jdbc.core.ParameterMapper;
  49. import org.springframework.jdbc.core.RowMapper;
  50. import org.springframework.jdbc.core.SimpleRowCountCallbackHandler;
  51. import org.springframework.jdbc.core.SqlOutParameter;
  52. import org.springframework.jdbc.core.SqlParameter;
  53. import org.springframework.jdbc.core.SqlReturnResultSet;
  54. import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
  55. import org.springframework.jdbc.datasource.ConnectionHolder;
  56. import org.springframework.jdbc.support.SQLExceptionTranslator;
  57. import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
  58. import org.springframework.transaction.support.TransactionSynchronizationManager;
  59. /**
  60. * @author Thomas Risberg
  61. * @author Trevor Cook
  62. * @author Rod Johnson
  63. */
  64. public class StoredProcedureTests {
  65. @Rule
  66. public ExpectedException thrown = ExpectedException.none();
  67. private DataSource dataSource;
  68. private Connection connection;
  69. private CallableStatement callableStatement;
  70. private boolean verifyClosedAfter = true;
  71. @Before
  72. public void setup() throws Exception {
  73. dataSource = mock(DataSource.class);
  74. connection = mock(Connection.class);
  75. callableStatement = mock(CallableStatement.class);
  76. given(dataSource.getConnection()).willReturn(connection);
  77. given(callableStatement.getConnection()).willReturn(connection);
  78. }
  79. @After
  80. public void verifyClosed() throws Exception {
  81. if(verifyClosedAfter) {
  82. verify(callableStatement).close();
  83. verify(connection, atLeastOnce()).close();
  84. }
  85. }
  86. @Test
  87. public void testNoSuchStoredProcedure() throws Exception {
  88. SQLException sqlException = new SQLException(
  89. "Syntax error or access violation exception", "42000");
  90. given(callableStatement.execute()).willThrow(sqlException);
  91. given(connection.prepareCall("{call " + NoSuchStoredProcedure.SQL + "()}")).willReturn(
  92. callableStatement);
  93. NoSuchStoredProcedure sproc = new NoSuchStoredProcedure(dataSource);
  94. thrown.expect(BadSqlGrammarException.class);
  95. sproc.execute();
  96. }
  97. private void testAddInvoice(final int amount, final int custid) throws Exception {
  98. AddInvoice adder = new AddInvoice(dataSource);
  99. int id = adder.execute(amount, custid);
  100. assertEquals(4, id);
  101. }
  102. private void testAddInvoiceUsingObjectArray(final int amount, final int custid)
  103. throws Exception {
  104. AddInvoiceUsingObjectArray adder = new AddInvoiceUsingObjectArray(dataSource);
  105. int id = adder.execute(amount, custid);
  106. assertEquals(5, id);
  107. }
  108. @Test
  109. public void testAddInvoices() throws Exception {
  110. given(callableStatement.execute()).willReturn(false);
  111. given(callableStatement.getUpdateCount()).willReturn(-1);
  112. given(callableStatement.getObject(3)).willReturn(4);
  113. given(connection.prepareCall("{call " + AddInvoice.SQL + "(?, ?, ?)}")
  114. ).willReturn(callableStatement);
  115. testAddInvoice(1106, 3);
  116. verify(callableStatement).setObject(1, 1106, Types.INTEGER);
  117. verify(callableStatement).setObject(2, 3, Types.INTEGER);
  118. verify(callableStatement).registerOutParameter(3, Types.INTEGER);
  119. }
  120. @Test
  121. public void testAddInvoicesUsingObjectArray() throws Exception {
  122. given(callableStatement.execute()).willReturn(false);
  123. given(callableStatement.getUpdateCount()).willReturn(-1);
  124. given(callableStatement.getObject(3)).willReturn(5);
  125. given(connection.prepareCall("{call " + AddInvoice.SQL + "(?, ?, ?)}")
  126. ).willReturn(callableStatement);
  127. testAddInvoiceUsingObjectArray(1106, 4);
  128. verify(callableStatement).setObject(1, 1106, Types.INTEGER);
  129. verify(callableStatement).setObject(2, 4, Types.INTEGER);
  130. verify(callableStatement).registerOutParameter(3, Types.INTEGER);
  131. }
  132. @Test
  133. public void testAddInvoicesWithinTransaction() throws Exception {
  134. given(callableStatement.execute()).willReturn(false);
  135. given(callableStatement.getUpdateCount()).willReturn(-1);
  136. given(callableStatement.getObject(3)).willReturn(4);
  137. given(connection.prepareCall("{call " + AddInvoice.SQL + "(?, ?, ?)}")
  138. ).willReturn(callableStatement);
  139. TransactionSynchronizationManager.bindResource(dataSource, new ConnectionHolder(connection));
  140. try {
  141. testAddInvoice(1106, 3);
  142. verify(callableStatement).setObject(1, 1106, Types.INTEGER);
  143. verify(callableStatement).setObject(2, 3, Types.INTEGER);
  144. verify(callableStatement).registerOutParameter(3, Types.INTEGER);
  145. verify(connection, never()).close();
  146. }
  147. finally {
  148. TransactionSynchronizationManager.unbindResource(dataSource);
  149. connection.close();
  150. }
  151. }
  152. /**
  153. * Confirm no connection was used to get metadata. Does not use superclass replay
  154. * mechanism.
  155. *
  156. * @throws Exception
  157. */
  158. @Test
  159. public void testStoredProcedureConfiguredViaJdbcTemplateWithCustomExceptionTranslator()
  160. throws Exception {
  161. given(callableStatement.execute()).willReturn(false);
  162. given(callableStatement.getUpdateCount()).willReturn(-1);
  163. given(callableStatement.getObject(2)).willReturn(5);
  164. given(connection.prepareCall("{call " + StoredProcedureConfiguredViaJdbcTemplate.SQL + "(?, ?)}")
  165. ).willReturn(callableStatement);
  166. class TestJdbcTemplate extends JdbcTemplate {
  167. int calls;
  168. @Override
  169. public Map<String, Object> call(CallableStatementCreator csc,
  170. List<SqlParameter> declaredParameters) throws DataAccessException {
  171. calls++;
  172. return super.call(csc, declaredParameters);
  173. }
  174. }
  175. TestJdbcTemplate t = new TestJdbcTemplate();
  176. t.setDataSource(dataSource);
  177. // Will fail without the following, because we're not able to get a connection
  178. // from the DataSource here if we need to to create an ExceptionTranslator
  179. t.setExceptionTranslator(new SQLStateSQLExceptionTranslator());
  180. StoredProcedureConfiguredViaJdbcTemplate sp = new StoredProcedureConfiguredViaJdbcTemplate(t);
  181. assertEquals(sp.execute(11), 5);
  182. assertEquals(1, t.calls);
  183. verify(callableStatement).setObject(1, 11, Types.INTEGER);
  184. verify(callableStatement).registerOutParameter(2, Types.INTEGER);
  185. }
  186. /**
  187. * Confirm our JdbcTemplate is used
  188. *
  189. * @throws Exception
  190. */
  191. @Test
  192. public void testStoredProcedureConfiguredViaJdbcTemplate() throws Exception {
  193. given(callableStatement.execute()).willReturn(false);
  194. given(callableStatement.getUpdateCount()).willReturn(-1);
  195. given(callableStatement.getObject(2)).willReturn(4);
  196. given(connection.prepareCall("{call " + StoredProcedureConfiguredViaJdbcTemplate.SQL + "(?, ?)}")
  197. ).willReturn(callableStatement);
  198. JdbcTemplate t = new JdbcTemplate();
  199. t.setDataSource(dataSource);
  200. StoredProcedureConfiguredViaJdbcTemplate sp = new StoredProcedureConfiguredViaJdbcTemplate(t);
  201. assertEquals(sp.execute(1106), 4);
  202. verify(callableStatement).setObject(1, 1106, Types.INTEGER);
  203. verify(callableStatement).registerOutParameter(2, Types.INTEGER);
  204. }
  205. @Test
  206. public void testNullArg() throws Exception {
  207. given(callableStatement.execute()).willReturn(false);
  208. given(callableStatement.getUpdateCount()).willReturn(-1);
  209. given(connection.prepareCall("{call " + NullArg.SQL + "(?)}")).willReturn(callableStatement);
  210. NullArg na = new NullArg(dataSource);
  211. na.execute((String) null);
  212. callableStatement.setNull(1, Types.VARCHAR);
  213. }
  214. @Test
  215. public void testUnnamedParameter() throws Exception {
  216. this.verifyClosedAfter = false;
  217. // Shouldn't succeed in creating stored procedure with unnamed parameter
  218. thrown.expect(InvalidDataAccessApiUsageException.class);
  219. new UnnamedParameterStoredProcedure(dataSource);
  220. }
  221. @Test
  222. public void testMissingParameter() throws Exception {
  223. this.verifyClosedAfter = false;
  224. MissingParameterStoredProcedure mp = new MissingParameterStoredProcedure(dataSource);
  225. thrown.expect(InvalidDataAccessApiUsageException.class);
  226. mp.execute();
  227. fail("Shouldn't succeed in running stored procedure with missing required parameter");
  228. }
  229. @Test
  230. public void testStoredProcedureExceptionTranslator() throws Exception {
  231. SQLException sqlException = new SQLException(
  232. "Syntax error or access violation exception", "42000");
  233. given(callableStatement.execute()).willThrow(sqlException);
  234. given(connection.prepareCall("{call " + StoredProcedureExceptionTranslator.SQL + "()}")
  235. ).willReturn(callableStatement);
  236. StoredProcedureExceptionTranslator sproc = new StoredProcedureExceptionTranslator(dataSource);
  237. thrown.expect(CustomDataException.class);
  238. sproc.execute();
  239. }
  240. @Test
  241. public void testStoredProcedureWithResultSet() throws Exception {
  242. ResultSet resultSet = mock(ResultSet.class);
  243. given(resultSet.next()).willReturn(true, true, false);
  244. given(callableStatement.execute()).willReturn(true);
  245. given(callableStatement.getUpdateCount()).willReturn(-1);
  246. given(callableStatement.getResultSet()).willReturn(resultSet);
  247. given(callableStatement.getUpdateCount()).willReturn(-1);
  248. given(connection.prepareCall("{call " + StoredProcedureWithResultSet.SQL + "()}")
  249. ).willReturn(callableStatement);
  250. StoredProcedureWithResultSet sproc = new StoredProcedureWithResultSet(dataSource);
  251. sproc.execute();
  252. assertEquals(2, sproc.getCount());
  253. verify(resultSet).close();
  254. }
  255. @Test
  256. @SuppressWarnings("unchecked")
  257. public void testStoredProcedureWithResultSetMapped() throws Exception {
  258. ResultSet resultSet = mock(ResultSet.class);
  259. given(resultSet.next()).willReturn(true, true, false);
  260. given(resultSet.getString(2)).willReturn("Foo", "Bar");
  261. given(callableStatement.execute()).willReturn(true);
  262. given(callableStatement.getUpdateCount()).willReturn(-1);
  263. given(callableStatement.getResultSet()).willReturn(resultSet);
  264. given(callableStatement.getMoreResults()).willReturn(false);
  265. given(callableStatement.getUpdateCount()).willReturn(-1);
  266. given(connection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}")
  267. ).willReturn(callableStatement);
  268. StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(dataSource);
  269. Map<String, Object> res = sproc.execute();
  270. List<String> rs = (List<String>) res.get("rs");
  271. assertEquals(2, rs.size());
  272. assertEquals("Foo", rs.get(0));
  273. assertEquals("Bar", rs.get(1));
  274. verify(resultSet).close();
  275. }
  276. @Test
  277. @SuppressWarnings("unchecked")
  278. public void testStoredProcedureWithUndeclaredResults() throws Exception {
  279. ResultSet resultSet1 = mock(ResultSet.class);
  280. given(resultSet1.next()).willReturn(true, true, false);
  281. given(resultSet1.getString(2)).willReturn("Foo", "Bar");
  282. ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class);
  283. given(resultSetMetaData.getColumnCount()).willReturn(2);
  284. given(resultSetMetaData.getColumnLabel(1)).willReturn("spam");
  285. given(resultSetMetaData.getColumnLabel(2)).willReturn("eggs");
  286. ResultSet resultSet2 = mock(ResultSet.class);
  287. given(resultSet2.getMetaData()).willReturn(resultSetMetaData);
  288. given(resultSet2.next()).willReturn(true, false);
  289. given(resultSet2.getObject(1)).willReturn("Spam");
  290. given(resultSet2.getObject(2)).willReturn("Eggs");
  291. given(callableStatement.execute()).willReturn(true);
  292. given(callableStatement.getUpdateCount()).willReturn(-1);
  293. given(callableStatement.getResultSet()).willReturn(resultSet1, resultSet2);
  294. given(callableStatement.getMoreResults()).willReturn(true, false, false);
  295. given(callableStatement.getUpdateCount()).willReturn(-1, -1, 0, -1);
  296. given(connection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}")
  297. ).willReturn(callableStatement);
  298. StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(dataSource);
  299. Map<String, Object> res = sproc.execute();
  300. assertEquals("incorrect number of returns", 3, res.size());
  301. List<String> rs1 = (List<String>) res.get("rs");
  302. assertEquals(2, rs1.size());
  303. assertEquals("Foo", rs1.get(0));
  304. assertEquals("Bar", rs1.get(1));
  305. List<Object> rs2 = (List<Object>) res.get("#result-set-2");
  306. assertEquals(1, rs2.size());
  307. Object o2 = rs2.get(0);
  308. assertTrue("wron type returned for result set 2", o2 instanceof Map);
  309. Map<String, String> m2 = (Map<String, String>) o2;
  310. assertEquals("Spam", m2.get("spam"));
  311. assertEquals("Eggs", m2.get("eggs"));
  312. Number n = (Number) res.get("#update-count-1");
  313. assertEquals("wrong update count", 0, n.intValue());
  314. verify(resultSet1).close();
  315. verify(resultSet2).close();
  316. }
  317. @Test
  318. public void testStoredProcedureSkippingResultsProcessing() throws Exception {
  319. given(callableStatement.execute()).willReturn(true);
  320. given(callableStatement.getUpdateCount()).willReturn(-1);
  321. given(connection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}")
  322. ).willReturn(callableStatement);
  323. JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
  324. jdbcTemplate.setSkipResultsProcessing(true);
  325. StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(
  326. jdbcTemplate);
  327. Map<String, Object> res = sproc.execute();
  328. assertEquals("incorrect number of returns", 0, res.size());
  329. }
  330. @Test
  331. @SuppressWarnings("unchecked")
  332. public void testStoredProcedureSkippingUndeclaredResults() throws Exception {
  333. ResultSet resultSet = mock(ResultSet.class);
  334. given(resultSet.next()).willReturn(true, true, false);
  335. given(resultSet.getString(2)).willReturn("Foo", "Bar");
  336. given(callableStatement.execute()).willReturn(true);
  337. given(callableStatement.getUpdateCount()).willReturn(-1);
  338. given(callableStatement.getResultSet()).willReturn(resultSet);
  339. given(callableStatement.getMoreResults()).willReturn(true, false);
  340. given(callableStatement.getUpdateCount()).willReturn(-1, -1);
  341. given(connection.prepareCall("{call " + StoredProcedureWithResultSetMapped.SQL + "()}")
  342. ).willReturn(callableStatement);
  343. JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
  344. jdbcTemplate.setSkipUndeclaredResults(true);
  345. StoredProcedureWithResultSetMapped sproc = new StoredProcedureWithResultSetMapped(
  346. jdbcTemplate);
  347. Map<String, Object> res = sproc.execute();
  348. assertEquals("incorrect number of returns", 1, res.size());
  349. List<String> rs1 = (List<String>) res.get("rs");
  350. assertEquals(2, rs1.size());
  351. assertEquals("Foo", rs1.get(0));
  352. assertEquals("Bar", rs1.get(1));
  353. verify(resultSet).close();
  354. }
  355. @Test
  356. public void testParameterMapper() throws Exception {
  357. given(callableStatement.execute()).willReturn(false);
  358. given(callableStatement.getUpdateCount()).willReturn(-1);
  359. given(callableStatement.getObject(2)).willReturn("OK");
  360. given(connection.prepareCall("{call " + ParameterMapperStoredProcedure.SQL + "(?, ?)}")
  361. ).willReturn(callableStatement);
  362. ParameterMapperStoredProcedure pmsp = new ParameterMapperStoredProcedure(dataSource);
  363. Map<String, Object> out = pmsp.executeTest();
  364. assertEquals("OK", out.get("out"));
  365. verify(callableStatement).setString(eq(1), startsWith("Mock for Connection"));
  366. verify(callableStatement).registerOutParameter(2, Types.VARCHAR);
  367. }
  368. @Test
  369. public void testSqlTypeValue() throws Exception {
  370. int[] testVal = new int[] { 1, 2 };
  371. given(callableStatement.execute()).willReturn(false);
  372. given(callableStatement.getUpdateCount()).willReturn(-1);
  373. given(callableStatement.getObject(2)).willReturn("OK");
  374. given(connection.prepareCall("{call " + SqlTypeValueStoredProcedure.SQL + "(?, ?)}")
  375. ).willReturn(callableStatement);
  376. SqlTypeValueStoredProcedure stvsp = new SqlTypeValueStoredProcedure(dataSource);
  377. Map<String, Object> out = stvsp.executeTest(testVal);
  378. assertEquals("OK", out.get("out"));
  379. verify(callableStatement).setObject(1, testVal, Types.ARRAY);
  380. verify(callableStatement).registerOutParameter(2, Types.VARCHAR);
  381. }
  382. @Test
  383. public void testNumericWithScale() throws Exception {
  384. given(callableStatement.execute()).willReturn(false);
  385. given(callableStatement.getUpdateCount()).willReturn(-1);
  386. given(callableStatement.getObject(1)).willReturn(new BigDecimal("12345.6789"));
  387. given(connection.prepareCall("{call " + NumericWithScaleStoredProcedure.SQL + "(?)}")
  388. ).willReturn(callableStatement);
  389. NumericWithScaleStoredProcedure nwssp = new NumericWithScaleStoredProcedure(dataSource);
  390. Map<String, Object> out = nwssp.executeTest();
  391. assertEquals(new BigDecimal("12345.6789"), out.get("out"));
  392. verify(callableStatement).registerOutParameter(1, Types.DECIMAL, 4);
  393. }
  394. private static class StoredProcedureConfiguredViaJdbcTemplate extends StoredProcedure {
  395. public static final String SQL = "configured_via_jt";
  396. public StoredProcedureConfiguredViaJdbcTemplate(JdbcTemplate t) {
  397. setJdbcTemplate(t);
  398. setSql(SQL);
  399. declareParameter(new SqlParameter("intIn", Types.INTEGER));
  400. declareParameter(new SqlOutParameter("intOut", Types.INTEGER));
  401. compile();
  402. }
  403. public int execute(int intIn) {
  404. Map<String, Integer> in = new HashMap<String, Integer>();
  405. in.put("intIn", intIn);
  406. Map<String, Object> out = execute(in);
  407. return ((Number) out.get("intOut")).intValue();
  408. }
  409. }
  410. private static class AddInvoice extends StoredProcedure {
  411. public static final String SQL = "add_invoice";
  412. public AddInvoice(DataSource ds) {
  413. setDataSource(ds);
  414. setSql(SQL);
  415. declareParameter(new SqlParameter("amount", Types.INTEGER));
  416. declareParameter(new SqlParameter("custid", Types.INTEGER));
  417. declareParameter(new SqlOutParameter("newid", Types.INTEGER));
  418. compile();
  419. }
  420. public int execute(int amount, int custid) {
  421. Map<String, Integer> in = new HashMap<String, Integer>();
  422. in.put("amount", amount);
  423. in.put("custid", custid);
  424. Map<String, Object> out = execute(in);
  425. return ((Number) out.get("newid")).intValue();
  426. }
  427. }
  428. private static class AddInvoiceUsingObjectArray extends StoredProcedure {
  429. public static final String SQL = "add_invoice";
  430. public AddInvoiceUsingObjectArray(DataSource ds) {
  431. setDataSource(ds);
  432. setSql(SQL);
  433. declareParameter(new SqlParameter("amount", Types.INTEGER));
  434. declareParameter(new SqlParameter("custid", Types.INTEGER));
  435. declareParameter(new SqlOutParameter("newid", Types.INTEGER));
  436. compile();
  437. }
  438. public int execute(int amount, int custid) {
  439. Map<String, Object> out = execute(new Object[] { amount, custid });
  440. return ((Number) out.get("newid")).intValue();
  441. }
  442. }
  443. private static class NullArg extends StoredProcedure {
  444. public static final String SQL = "takes_null";
  445. public NullArg(DataSource ds) {
  446. setDataSource(ds);
  447. setSql(SQL);
  448. declareParameter(new SqlParameter("ptest", Types.VARCHAR));
  449. compile();
  450. }
  451. public void execute(String s) {
  452. Map<String, String> in = new HashMap<String, String>();
  453. in.put("ptest", s);
  454. execute(in);
  455. }
  456. }
  457. private static class NoSuchStoredProcedure extends StoredProcedure {
  458. public static final String SQL = "no_sproc_with_this_name";
  459. public NoSuchStoredProcedure(DataSource ds) {
  460. setDataSource(ds);
  461. setSql(SQL);
  462. compile();
  463. }
  464. public void execute() {
  465. execute(new HashMap<String, Object>());
  466. }
  467. }
  468. private static class UnnamedParameterStoredProcedure extends StoredProcedure {
  469. public UnnamedParameterStoredProcedure(DataSource ds) {
  470. super(ds, "unnamed_parameter_sp");
  471. declareParameter(new SqlParameter(Types.INTEGER));
  472. compile();
  473. }
  474. }
  475. private static class MissingParameterStoredProcedure extends StoredProcedure {
  476. public MissingParameterStoredProcedure(DataSource ds) {
  477. setDataSource(ds);
  478. setSql("takes_string");
  479. declareParameter(new SqlParameter("mystring", Types.VARCHAR));
  480. compile();
  481. }
  482. public void execute() {
  483. execute(new HashMap<String, Object>());
  484. }
  485. }
  486. private static class StoredProcedureWithResultSet extends StoredProcedure {
  487. public static final String SQL = "sproc_with_result_set";
  488. private final SimpleRowCountCallbackHandler handler = new SimpleRowCountCallbackHandler();
  489. public StoredProcedureWithResultSet(DataSource ds) {
  490. setDataSource(ds);
  491. setSql(SQL);
  492. declareParameter(new SqlReturnResultSet("rs", this.handler));
  493. compile();
  494. }
  495. public void execute() {
  496. execute(new HashMap<String, Object>());
  497. }
  498. public int getCount() {
  499. return this.handler.getCount();
  500. }
  501. }
  502. private static class StoredProcedureWithResultSetMapped extends StoredProcedure {
  503. public static final String SQL = "sproc_with_result_set";
  504. public StoredProcedureWithResultSetMapped(DataSource ds) {
  505. setDataSource(ds);
  506. setSql(SQL);
  507. declareParameter(new SqlReturnResultSet("rs", new RowMapperImpl()));
  508. compile();
  509. }
  510. public StoredProcedureWithResultSetMapped(JdbcTemplate jt) {
  511. setJdbcTemplate(jt);
  512. setSql(SQL);
  513. declareParameter(new SqlReturnResultSet("rs", new RowMapperImpl()));
  514. compile();
  515. }
  516. public Map<String, Object> execute() {
  517. return execute(new HashMap<String, Object>());
  518. }
  519. private static class RowMapperImpl implements RowMapper<String> {
  520. @Override
  521. public String mapRow(ResultSet rs, int rowNum) throws SQLException {
  522. return rs.getString(2);
  523. }
  524. }
  525. }
  526. private static class ParameterMapperStoredProcedure extends StoredProcedure {
  527. public static final String SQL = "parameter_mapper_sp";
  528. public ParameterMapperStoredProcedure(DataSource ds) {
  529. setDataSource(ds);
  530. setSql(SQL);
  531. declareParameter(new SqlParameter("in", Types.VARCHAR));
  532. declareParameter(new SqlOutParameter("out", Types.VARCHAR));
  533. compile();
  534. }
  535. public Map<String, Object> executeTest() {
  536. return execute(new TestParameterMapper());
  537. }
  538. private static class TestParameterMapper implements ParameterMapper {
  539. private TestParameterMapper() {
  540. }
  541. @Override
  542. public Map<String, ?> createMap(Connection con) throws SQLException {
  543. Map<String, Object> inParms = new HashMap<String, Object>();
  544. String testValue = con.toString();
  545. inParms.put("in", testValue);
  546. return inParms;
  547. }
  548. }
  549. }
  550. private static class SqlTypeValueStoredProcedure extends StoredProcedure {
  551. public static final String SQL = "sql_type_value_sp";
  552. public SqlTypeValueStoredProcedure(DataSource ds) {
  553. setDataSource(ds);
  554. setSql(SQL);
  555. declareParameter(new SqlParameter("in", Types.ARRAY, "NUMBERS"));
  556. declareParameter(new SqlOutParameter("out", Types.VARCHAR));
  557. compile();
  558. }
  559. public Map<String, Object> executeTest(final int[] inValue) {
  560. Map<String, AbstractSqlTypeValue> in = new HashMap<String, AbstractSqlTypeValue>();
  561. in.put("in", new AbstractSqlTypeValue() {
  562. @Override
  563. public Object createTypeValue(Connection con, int type, String typeName) {
  564. // assertEquals(Connection.class, con.getClass());
  565. // assertEquals(Types.ARRAY, type);
  566. // assertEquals("NUMBER", typeName);
  567. return inValue;
  568. }
  569. });
  570. return execute(in);
  571. }
  572. }
  573. private static class NumericWithScaleStoredProcedure extends StoredProcedure {
  574. public static final String SQL = "numeric_with_scale_sp";
  575. public NumericWithScaleStoredProcedure(DataSource ds) {
  576. setDataSource(ds);
  577. setSql(SQL);
  578. declareParameter(new SqlOutParameter("out", Types.DECIMAL, 4));
  579. compile();
  580. }
  581. public Map<String, Object> executeTest() {
  582. return execute(new HashMap<String, Object>());
  583. }
  584. }
  585. private static class StoredProcedureExceptionTranslator extends StoredProcedure {
  586. public static final String SQL = "no_sproc_with_this_name";
  587. public StoredProcedureExceptionTranslator(DataSource ds) {
  588. setDataSource(ds);
  589. setSql(SQL);
  590. getJdbcTemplate().setExceptionTranslator(new SQLExceptionTranslator() {
  591. @Override
  592. public DataAccessException translate(String task, String sql,
  593. SQLException sqlex) {
  594. return new CustomDataException(sql, sqlex);
  595. }
  596. });
  597. compile();
  598. }
  599. public void execute() {
  600. execute(new HashMap<String, Object>());
  601. }
  602. }
  603. @SuppressWarnings("serial")
  604. private static class CustomDataException extends DataAccessException {
  605. public CustomDataException(String s) {
  606. super(s);
  607. }
  608. public CustomDataException(String s, Throwable ex) {
  609. super(s, ex);
  610. }
  611. }
  612. }