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