001/* 002 * Copyright 2002-2017 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.core; 018 019import java.sql.ResultSet; 020import java.sql.ResultSetMetaData; 021import java.sql.SQLException; 022 023import org.springframework.jdbc.support.JdbcUtils; 024 025/** 026 * Implementation of {@link RowCallbackHandler}. An instance can only be used once. 027 * 028 * <p>We can either use this on its own (for example, in a test case, to ensure 029 * that our result sets have valid dimensions), or use it as a superclass for 030 * callback handlers that actually do something, and will benefit from the 031 * dimension information it provides. 032 * 033 * <p>A usage example with {@link JdbcTemplate}: 034 * 035 * <pre class="code"> 036 * JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); // reusable object 037 * 038 * RowCountCallbackHandler countCallback = new RowCountCallbackHandler(); // not reusable 039 * jdbcTemplate.query("select * from user", countCallback); 040 * int rowCount = countCallback.getRowCount(); 041 * </pre> 042 * 043 * @author Rod Johnson 044 * @since May 3, 2001 045 */ 046public class RowCountCallbackHandler implements RowCallbackHandler { 047 048 /** Rows we've seen so far */ 049 private int rowCount; 050 051 /** Columns we've seen so far */ 052 private int columnCount; 053 054 /** 055 * Indexed from 0. Type (as in java.sql.Types) for the columns 056 * as returned by ResultSetMetaData object. 057 */ 058 private int[] columnTypes; 059 060 /** 061 * Indexed from 0. Column name as returned by ResultSetMetaData object. 062 */ 063 private String[] columnNames; 064 065 066 /** 067 * Work out column size if this is the first row, otherwise just count rows. 068 * <p>Subclasses can perform custom extraction or processing 069 * by overriding the {@code processRow(ResultSet, int)} method. 070 * @see #processRow(java.sql.ResultSet, int) 071 */ 072 @Override 073 public final void processRow(ResultSet rs) throws SQLException { 074 if (this.rowCount == 0) { 075 ResultSetMetaData rsmd = rs.getMetaData(); 076 this.columnCount = rsmd.getColumnCount(); 077 this.columnTypes = new int[this.columnCount]; 078 this.columnNames = new String[this.columnCount]; 079 for (int i = 0; i < this.columnCount; i++) { 080 this.columnTypes[i] = rsmd.getColumnType(i + 1); 081 this.columnNames[i] = JdbcUtils.lookupColumnName(rsmd, i + 1); 082 } 083 // could also get column names 084 } 085 processRow(rs, this.rowCount++); 086 } 087 088 /** 089 * Subclasses may override this to perform custom extraction 090 * or processing. This class's implementation does nothing. 091 * @param rs ResultSet to extract data from. This method is 092 * invoked for each row 093 * @param rowNum number of the current row (starting from 0) 094 */ 095 protected void processRow(ResultSet rs, int rowNum) throws SQLException { 096 } 097 098 099 /** 100 * Return the types of the columns as java.sql.Types constants 101 * Valid after processRow is invoked the first time. 102 * @return the types of the columns as java.sql.Types constants. 103 * <b>Indexed from 0 to n-1.</b> 104 */ 105 public final int[] getColumnTypes() { 106 return this.columnTypes; 107 } 108 109 /** 110 * Return the names of the columns. 111 * Valid after processRow is invoked the first time. 112 * @return the names of the columns. 113 * <b>Indexed from 0 to n-1.</b> 114 */ 115 public final String[] getColumnNames() { 116 return this.columnNames; 117 } 118 119 /** 120 * Return the row count of this ResultSet 121 * Only valid after processing is complete 122 * @return the number of rows in this ResultSet 123 */ 124 public final int getRowCount() { 125 return this.rowCount; 126 } 127 128 /** 129 * Return the number of columns in this result set. 130 * Valid once we've seen the first row, 131 * so subclasses can use it during processing 132 * @return the number of columns in this result set 133 */ 134 public final int getColumnCount() { 135 return this.columnCount; 136 } 137 138}