001/*
002 * Copyright 2002-2013 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.support.lob;
018
019import java.io.InputStream;
020import java.io.Reader;
021import java.sql.ResultSet;
022import java.sql.SQLException;
023
024/**
025 * Abstraction for handling large binary fields and large text fields in
026 * specific databases, no matter if represented as simple types or Large OBjects.
027 * Its main purpose is to isolate Oracle 9i's peculiar handling of LOBs in
028 * {@link OracleLobHandler}; most other databases should be able to work
029 * with the provided {@link DefaultLobHandler}.
030 *
031 * <p>Provides accessor methods for BLOBs and CLOBs, and acts as factory for
032 * LobCreator instances, to be used as sessions for creating BLOBs or CLOBs.
033 * LobCreators are typically instantiated for each statement execution or for
034 * each transaction; they are not thread-safe because they might track
035 * allocated database resources in order to free them after execution.
036 *
037 * <p>Most databases/drivers should be able to work with {@link DefaultLobHandler},
038 * which by default delegates to JDBC's direct accessor methods, avoiding the
039 * {@code java.sql.Blob} and {@code java.sql.Clob} API completely.
040 * {@link DefaultLobHandler} can also be configured to access LOBs using
041 * {@code PreparedStatement.setBlob/setClob} (e.g. for PostgreSQL), through
042 * setting the {@link DefaultLobHandler#setWrapAsLob "wrapAsLob"} property.
043 *
044 * <p>Unfortunately, Oracle 9i just accepts Blob/Clob instances created via its own
045 * proprietary BLOB/CLOB API, and additionally doesn't accept large streams for
046 * PreparedStatement's corresponding setter methods. Therefore, you need to use
047 * {@link OracleLobHandler} there, which uses Oracle's BLOB/CLOB API for both types
048 * of access. The Oracle 10g+ JDBC driver will work with {@link DefaultLobHandler}
049 * as well, with some limitations in terms of LOB sizes depending on DBMS setup;
050 * as of Oracle 11g (or actually, using the 11g driver even against older databases),
051 * there should be no need to use {@link OracleLobHandler} at all anymore.
052 *
053 * <p>Of course, you need to declare different field types for each database.
054 * In Oracle, any binary content needs to go into a BLOB, and all character content
055 * beyond 4000 bytes needs to go into a CLOB. In MySQL, there is no notion of a
056 * CLOB type but rather a LONGTEXT type that behaves like a VARCHAR. For complete
057 * portability, use a LobHandler for fields that might typically require LOBs on
058 * some database because of the field size (take Oracle's numbers as a guideline).
059 *
060 * <p><b>Summarizing the recommended options (for actual LOB fields):</b>
061 * <ul>
062 * <li><b>JDBC 4.0 driver (including Oracle 11g driver):</b> Use {@link DefaultLobHandler},
063 * potentially with {@code streamAsLob=true} if your database driver requires that
064 * hint when populating a LOB field. Fall back to {@code createTemporaryLob=true}
065 * if you happen to run into LOB size limitations with your (Oracle) database setup.
066 * <li><b>Oracle 10g driver:</b> Use {@link DefaultLobHandler} with standard setup.
067 * On Oracle 10.1, set the "SetBigStringTryClob" connection property; as of Oracle 10.2,
068 * DefaultLobHandler should work with standard setup out of the box. Alternatively,
069 * consider using the proprietary {@link OracleLobHandler} (see below).
070 * <li><b>Oracle 9i driver:</b> Use {@link OracleLobHandler} with a connection-pool-specific
071 * {@link OracleLobHandler#setNativeJdbcExtractor NativeJdbcExtractor}.
072 * <li><b>PostgreSQL:</b> Configure {@link DefaultLobHandler} with {@code wrapAsLob=true},
073 * and use that LobHandler to access OID columns (but not BYTEA) in your database tables.
074 * <li>For all other database drivers (and for non-LOB fields that might potentially
075 * turn into LOBs on some databases): Simply use a plain {@link DefaultLobHandler}.
076 * </ul>
077 *
078 * @author Juergen Hoeller
079 * @since 23.12.2003
080 * @see DefaultLobHandler
081 * @see OracleLobHandler
082 * @see java.sql.ResultSet#getBlob
083 * @see java.sql.ResultSet#getClob
084 * @see java.sql.ResultSet#getBytes
085 * @see java.sql.ResultSet#getBinaryStream
086 * @see java.sql.ResultSet#getString
087 * @see java.sql.ResultSet#getAsciiStream
088 * @see java.sql.ResultSet#getCharacterStream
089 */
090public interface LobHandler {
091
092        /**
093         * Retrieve the given column as bytes from the given ResultSet.
094         * Might simply invoke {@code ResultSet.getBytes} or work with
095         * {@code ResultSet.getBlob}, depending on the database and driver.
096         * @param rs the ResultSet to retrieve the content from
097         * @param columnName the column name to use
098         * @return the content as byte array, or {@code null} in case of SQL NULL
099         * @throws SQLException if thrown by JDBC methods
100         * @see java.sql.ResultSet#getBytes
101         */
102        byte[] getBlobAsBytes(ResultSet rs, String columnName) throws SQLException;
103
104        /**
105         * Retrieve the given column as bytes from the given ResultSet.
106         * Might simply invoke {@code ResultSet.getBytes} or work with
107         * {@code ResultSet.getBlob}, depending on the database and driver.
108         * @param rs the ResultSet to retrieve the content from
109         * @param columnIndex the column index to use
110         * @return the content as byte array, or {@code null} in case of SQL NULL
111         * @throws SQLException if thrown by JDBC methods
112         * @see java.sql.ResultSet#getBytes
113         */
114        byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException;
115
116        /**
117         * Retrieve the given column as binary stream from the given ResultSet.
118         * Might simply invoke {@code ResultSet.getBinaryStream} or work with
119         * {@code ResultSet.getBlob}, depending on the database and driver.
120         * @param rs the ResultSet to retrieve the content from
121         * @param columnName the column name to use
122         * @return the content as binary stream, or {@code null} in case of SQL NULL
123         * @throws SQLException if thrown by JDBC methods
124         * @see java.sql.ResultSet#getBinaryStream
125         */
126        InputStream getBlobAsBinaryStream(ResultSet rs, String columnName) throws SQLException;
127
128        /**
129         * Retrieve the given column as binary stream from the given ResultSet.
130         * Might simply invoke {@code ResultSet.getBinaryStream} or work with
131         * {@code ResultSet.getBlob}, depending on the database and driver.
132         * @param rs the ResultSet to retrieve the content from
133         * @param columnIndex the column index to use
134         * @return the content as binary stream, or {@code null} in case of SQL NULL
135         * @throws SQLException if thrown by JDBC methods
136         * @see java.sql.ResultSet#getBinaryStream
137         */
138        InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException;
139
140        /**
141         * Retrieve the given column as String from the given ResultSet.
142         * Might simply invoke {@code ResultSet.getString} or work with
143         * {@code ResultSet.getClob}, depending on the database and driver.
144         * @param rs the ResultSet to retrieve the content from
145         * @param columnName the column name to use
146         * @return the content as String, or {@code null} in case of SQL NULL
147         * @throws SQLException if thrown by JDBC methods
148         * @see java.sql.ResultSet#getString
149         */
150        String getClobAsString(ResultSet rs, String columnName) throws SQLException;
151
152        /**
153         * Retrieve the given column as String from the given ResultSet.
154         * Might simply invoke {@code ResultSet.getString} or work with
155         * {@code ResultSet.getClob}, depending on the database and driver.
156         * @param rs the ResultSet to retrieve the content from
157         * @param columnIndex the column index to use
158         * @return the content as String, or {@code null} in case of SQL NULL
159         * @throws SQLException if thrown by JDBC methods
160         * @see java.sql.ResultSet#getString
161         */
162        String getClobAsString(ResultSet rs, int columnIndex) throws SQLException;
163
164        /**
165         * Retrieve the given column as ASCII stream from the given ResultSet.
166         * Might simply invoke {@code ResultSet.getAsciiStream} or work with
167         * {@code ResultSet.getClob}, depending on the database and driver.
168         * @param rs the ResultSet to retrieve the content from
169         * @param columnName the column name to use
170         * @return the content as ASCII stream, or {@code null} in case of SQL NULL
171         * @throws SQLException if thrown by JDBC methods
172         * @see java.sql.ResultSet#getAsciiStream
173         */
174        InputStream getClobAsAsciiStream(ResultSet rs, String columnName) throws SQLException;
175
176        /**
177         * Retrieve the given column as ASCII stream from the given ResultSet.
178         * Might simply invoke {@code ResultSet.getAsciiStream} or work with
179         * {@code ResultSet.getClob}, depending on the database and driver.
180         * @param rs the ResultSet to retrieve the content from
181         * @param columnIndex the column index to use
182         * @return the content as ASCII stream, or {@code null} in case of SQL NULL
183         * @throws SQLException if thrown by JDBC methods
184         * @see java.sql.ResultSet#getAsciiStream
185         */
186        InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException;
187
188        /**
189         * Retrieve the given column as character stream from the given ResultSet.
190         * Might simply invoke {@code ResultSet.getCharacterStream} or work with
191         * {@code ResultSet.getClob}, depending on the database and driver.
192         * @param rs the ResultSet to retrieve the content from
193         * @param columnName the column name to use
194         * @return the content as character stream
195         * @throws SQLException if thrown by JDBC methods
196         * @see java.sql.ResultSet#getCharacterStream
197         */
198        Reader getClobAsCharacterStream(ResultSet rs, String columnName) throws SQLException;
199
200        /**
201         * Retrieve the given column as character stream from the given ResultSet.
202         * Might simply invoke {@code ResultSet.getCharacterStream} or work with
203         * {@code ResultSet.getClob}, depending on the database and driver.
204         * @param rs the ResultSet to retrieve the content from
205         * @param columnIndex the column index to use
206         * @return the content as character stream
207         * @throws SQLException if thrown by JDBC methods
208         * @see java.sql.ResultSet#getCharacterStream
209         */
210        Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException;
211
212        /**
213         * Create a new {@link LobCreator} instance, i.e. a session for creating BLOBs
214         * and CLOBs. Needs to be closed after the created LOBs are not needed anymore -
215         * typically after statement execution or transaction completion.
216         * @return the new LobCreator instance
217         * @see LobCreator#close()
218         */
219        LobCreator getLobCreator();
220
221}