/*
 * Copyright 2002-2004 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.jdbc.core.support;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.LobRetrievalFailureException;
import org.springframework.jdbc.core.ResultSetExtractor;

/**
 * Abstract ResultSetExtractor implementation that assumes streaming of LOB data.
 * Typically used as inner class, with access to surrounding method arguments.
 *
 * <p>Delegates to the <code>streamData</code> template method for streaming LOB
 * content to some OutputStream, typically using a LobHandler. Converts an
 * IOException thrown during streaming to a LobRetrievalFailureException.
 *
 * @author Juergen Hoeller
 * @since 28.04.2004
 * @see org.springframework.jdbc.support.lob.LobHandler
 * @see org.springframework.jdbc.LobRetrievalFailureException
 */
public abstract class AbstractLobStreamingResultSetExtractor implements ResultSetExtractor {

	/**
	 * Delegates to handleNoRowFound, handleMultipleRowsFound and streamData,
	 * according to the ResultSet state. Converts an IOException thrown by
	 * streamData to a LobRetrievalFailureException.
	 * @see #handleNoRowFound
	 * @see #handleMultipleRowsFound
	 * @see #streamData
	 * @see org.springframework.jdbc.LobRetrievalFailureException
	 */
	public final Object extractData(ResultSet rs) throws SQLException, DataAccessException {
		if (!rs.next()) {
			handleNoRowFound();
		}
		else {
			try {
				streamData(rs);
				if (rs.next()) {
					handleMultipleRowsFound();
				}
			}
			catch (IOException ex) {
				throw new LobRetrievalFailureException("Couldn't stream LOB content", ex);
			}
		}
		return null;
	}

	/**
	 * Handle the case where the ResultSet does not contain a row.
	 * @throws DataAccessException a corresponding exception,
	 * by default a LobRetrievalFailureException
	 * @see org.springframework.jdbc.LobRetrievalFailureException
	 */
	protected void handleNoRowFound() throws DataAccessException {
		throw new LobRetrievalFailureException("No row found in database");
	}

	/**
	 * Handle the case where the ResultSet contains multiple rows.
	 * @throws DataAccessException a corresponding exception,
	 * by default a LobRetrievalFailureException
	 * @see org.springframework.jdbc.LobRetrievalFailureException
	 */
	protected void handleMultipleRowsFound() throws DataAccessException {
		throw new LobRetrievalFailureException("Multiple rows found in database");
	}

	/**
	 * Stream LOB content from the given ResultSet to some OutputStream.
	 * <p>Typically used as inner class, with access to surrounding method arguments
	 * and to a LobHandler instance variable of the surrounding class.
	 * @param rs the ResultSet to take the LOB content from
	 * @throws SQLException if thrown by JDBC methods
	 * @throws IOException if thrown by stream access methods
	 * @throws DataAccessException in case of custom exceptions
	 * @see org.springframework.jdbc.support.lob.LobHandler#getBlobAsBinaryStream
	 * @see org.springframework.util.FileCopyUtils
	 */
	protected abstract void streamData(ResultSet rs) throws SQLException, IOException, DataAccessException;

}

@@ -793,32 +793,103 @@
 ccessException;%0A
+import org.springframework.dao.IncorrectResultSizeDataAccessException;%0A
 import org.sprin
@@ -926,32 +926,32 @@
 ilureException;%0A
-
 import org.sprin
@@ -1393,16 +1393,562 @@
 ion.%0A *%0A
+ * %3Cp%3EA usage example with JdbcTemplate:%0A *%0A * %3Cpre%3E%0A * JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);  // reusable object%0A * final LobHandler lobHandler = new DefaultLobHandler();  // reusable object%0A *%0A * jdbcTemplate.query(%0A *%09%09 %22SELECT content FROM imagedb WHERE image_name=?%22, new Object%5B%5D %7Bname%7D,%0A *%09%09 new AbstractLobStreamingResultSetExtractor() %7B%0A *%09%09%09 public void streamData(ResultSet rs) throws SQLException, IOException %7B%0A *%09%09%09%09 FileCopyUtils.copy(lobHandler.getBlobAsBinaryStream(rs, 1), os);%0A *%09%09%09 %7D%0A *%09%09 %7D%0A * );%3C/pre%3E%0A *%0A
  * @auth
@@ -3073,36 +3073,47 @@
 efault a
- LobRetrievalFailure
+n IncorrectResultSizeDataAccess
 Exceptio
@@ -3262,63 +3262,165 @@
 new 
-LobRetrievalFailureException(%22No row found in database%22
+IncorrectResultSizeDataAccessException(%22LobStreamingResultSetExtractor did not find row in database%22,%0A%09%09                                                 1, 0
 );%0A%09
@@ -3566,36 +3566,47 @@
 efault a
- LobRetrievalFailure
+n IncorrectResultSizeDataAccess
 Exceptio
@@ -3762,39 +3762,86 @@
 new 
-LobRetrievalFailureException(%22M
+IncorrectResultSizeDataAccessException(%22LobStreamingResultSetExtractor found m
 ulti
@@ -3849,22 +3849,16 @@
 le rows 
-found 
 in datab
@@ -3861,16 +3861,74 @@
 atabase%22
+,%0A%09%09                                                 1, -1
 );%0A%09%7D%0A%0A%09

use LobRetrievalFailureException only for actual content reading failure, and IncorrectResultSizeDataAccessException for wrong row count