Home » MySQL-JDBC-5.1.11 » com.mysql.jdbc » [javadoc | source]

    1   /*
    2    Copyright  2002-2007 MySQL AB, 2008 Sun Microsystems
    3   
    4    This program is free software; you can redistribute it and/or modify
    5    it under the terms of version 2 of the GNU General Public License as 
    6    published by the Free Software Foundation.
    7   
    8    There are special exceptions to the terms and conditions of the GPL 
    9    as it is applied to this software. View the full text of the 
   10    exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
   11    software distribution.
   12   
   13    This program is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16    GNU General Public License for more details.
   17   
   18    You should have received a copy of the GNU General Public License
   19    along with this program; if not, write to the Free Software
   20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21   
   22   
   23   
   24    */
   25   package com.mysql.jdbc;
   26   
   27   import java.io.ByteArrayInputStream;
   28   import java.io.IOException;
   29   import java.io.InputStream;
   30   import java.io.OutputStream;
   31   import java.sql.SQLException;
   32   
   33   /**
   34    * The representation (mapping) in the JavaTM programming language of an SQL
   35    * BLOB value. An SQL BLOB is a built-in type that stores a Binary Large Object
   36    * as a column value in a row of a database table. The driver implements Blob
   37    * using an SQL locator(BLOB), which means that a Blob object contains a logical
   38    * pointer to the SQL BLOB data rather than the data itself. A Blob object is
   39    * valid for the duration of the transaction in which is was created. Methods in
   40    * the interfaces ResultSet, CallableStatement, and PreparedStatement, such as
   41    * getBlob and setBlob allow a programmer to access an SQL BLOB value. The Blob
   42    * interface provides methods for getting the length of an SQL BLOB (Binary
   43    * Large Object) value, for materializing a BLOB value on the client, and for
   44    * determining the position of a pattern of bytes within a BLOB value. This
   45    * class is new in the JDBC 2.0 API.
   46    * 
   47    * @author Mark Matthews
   48    * @version $Id$
   49    */
   50   public class Blob implements java.sql.Blob, OutputStreamWatcher {
   51   
   52   	//
   53   	// This is a real brain-dead implementation of BLOB. Once I add
   54   	// streamability to the I/O for MySQL this will be more efficiently
   55   	// implemented (except for the position() method, ugh).
   56   	//
   57   
   58   	/** The binary data that makes up this BLOB */
   59   	private byte[] binaryData = null;
   60   	private boolean isClosed = false;
   61   	private ExceptionInterceptor exceptionInterceptor;
   62   	
   63   	/**
   64        * Creates a Blob without data
   65        */
   66       Blob(ExceptionInterceptor exceptionInterceptor) {
   67           setBinaryData(Constants.EMPTY_BYTE_ARRAY);
   68           this.exceptionInterceptor = exceptionInterceptor;
   69       }
   70       
   71   	/**
   72   	 * Creates a BLOB encapsulating the given binary data
   73   	 * 
   74   	 * @param data
   75   	 *            DOCUMENT ME!
   76   	 */
   77   	Blob(byte[] data, ExceptionInterceptor exceptionInterceptor) {
   78   		setBinaryData(data);
   79   		this.exceptionInterceptor = exceptionInterceptor;
   80   	}
   81   
   82   	/**
   83   	 * Creates an updatable BLOB that can update in-place (not implemented yet).
   84   	 * 
   85   	 * @param data
   86   	 *            DOCUMENT ME!
   87   	 * @param creatorResultSetToSet
   88   	 *            DOCUMENT ME!
   89   	 * @param columnIndexToSet
   90   	 *            DOCUMENT ME!
   91   	 */
   92   	Blob(byte[] data, ResultSetInternalMethods creatorResultSetToSet, int columnIndexToSet) {
   93   		setBinaryData(data);
   94   	}
   95   
   96   	private synchronized byte[] getBinaryData() {
   97   		return this.binaryData;
   98   	}
   99   
  100   	/**
  101   	 * Retrieves the BLOB designated by this Blob instance as a stream.
  102   	 * 
  103   	 * @return this BLOB represented as a binary stream of bytes.
  104   	 * 
  105   	 * @throws SQLException
  106   	 *             if a database error occurs
  107   	 */
  108   	public synchronized java.io.InputStream getBinaryStream() throws SQLException {
  109   		checkClosed();
  110   		
  111   		return new ByteArrayInputStream(getBinaryData());
  112   	}
  113   
  114   	/**
  115   	 * Returns as an array of bytes, part or all of the BLOB value that this
  116   	 * Blob object designates.
  117   	 * 
  118   	 * @param pos
  119   	 *            where to start the part of the BLOB
  120   	 * @param length
  121   	 *            the length of the part of the BLOB you want returned.
  122   	 * 
  123   	 * @return the bytes stored in the blob starting at position
  124   	 *         <code>pos</code> and having a length of <code>length</code>.
  125   	 * 
  126   	 * @throws SQLException
  127   	 *             if a database error occurs
  128   	 */
  129   	public synchronized byte[] getBytes(long pos, int length) throws SQLException {
  130   		checkClosed();
  131   		
  132   		if (pos < 1) {
  133   			throw SQLError.createSQLException(Messages.getString("Blob.2"), //$NON-NLS-1$
  134   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  135   		}
  136   
  137   		pos--;
  138   		
  139   		if (pos > this.binaryData.length) {
  140   			throw SQLError.createSQLException("\"pos\" argument can not be larger than the BLOB's length.", 
  141   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  142   		}
  143   		
  144   		if (pos + length > this.binaryData.length) {
  145   			throw SQLError.createSQLException("\"pos\" + \"length\" arguments can not be larger than the BLOB's length.", 
  146   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  147   		}
  148   		
  149   		byte[] newData = new byte[length];
  150   		System.arraycopy(getBinaryData(), (int) (pos), newData, 0, length);
  151   
  152   		return newData;
  153   	}
  154   
  155   	/**
  156   	 * Returns the number of bytes in the BLOB value designated by this Blob
  157   	 * object.
  158   	 * 
  159   	 * @return the length of this blob
  160   	 * 
  161   	 * @throws SQLException
  162   	 *             if a database error occurs
  163   	 */
  164   	public synchronized long length() throws SQLException {
  165   		checkClosed();
  166   		
  167   		return getBinaryData().length;
  168   	}
  169   
  170   	/**
  171   	 * @see java.sql.Blob#position(byte[], long)
  172   	 */
  173   	public synchronized long position(byte[] pattern, long start) throws SQLException {
  174   		throw SQLError.createSQLException("Not implemented", this.exceptionInterceptor); //$NON-NLS-1$
  175   	}
  176   
  177   	/**
  178   	 * Finds the position of the given pattern in this BLOB.
  179   	 * 
  180   	 * @param pattern
  181   	 *            the pattern to find
  182   	 * @param start
  183   	 *            where to start finding the pattern
  184   	 * 
  185   	 * @return the position where the pattern is found in the BLOB, -1 if not
  186   	 *         found
  187   	 * 
  188   	 * @throws SQLException
  189   	 *             if a database error occurs
  190   	 */
  191   	public synchronized long position(java.sql.Blob pattern, long start) throws SQLException {
  192   		checkClosed();
  193   		
  194   		return position(pattern.getBytes(0, (int) pattern.length()), start);
  195   	}
  196   
  197   	private synchronized void setBinaryData(byte[] newBinaryData) {
  198   		this.binaryData = newBinaryData;
  199   	}
  200   
  201   	/**
  202   	 * @see Blob#setBinaryStream(long)
  203   	 */
  204   	public synchronized OutputStream setBinaryStream(long indexToWriteAt)
  205   			throws SQLException {
  206   		checkClosed();
  207   		
  208   		if (indexToWriteAt < 1) {
  209   			throw SQLError.createSQLException(Messages.getString("Blob.0"), //$NON-NLS-1$
  210   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  211   		}
  212   
  213   		WatchableOutputStream bytesOut = new WatchableOutputStream();
  214   		bytesOut.setWatcher(this);
  215   
  216   		if (indexToWriteAt > 0) {
  217   			bytesOut.write(this.binaryData, 0, (int) (indexToWriteAt - 1));
  218   		}
  219   
  220   		return bytesOut;
  221   	}
  222   
  223   	/**
  224   	 * @see Blob#setBytes(long, byte[])
  225   	 */
  226   	public synchronized int setBytes(long writeAt, byte[] bytes) throws SQLException {
  227   		checkClosed();
  228   		
  229   		return setBytes(writeAt, bytes, 0, bytes.length);
  230   	}
  231   
  232   	/**
  233   	 * @see Blob#setBytes(long, byte[], int, int)
  234   	 */
  235   	public synchronized int setBytes(long writeAt, byte[] bytes, int offset, int length)
  236   			throws SQLException {
  237   		checkClosed();
  238   		
  239   		OutputStream bytesOut = setBinaryStream(writeAt);
  240   
  241   		try {
  242   			bytesOut.write(bytes, offset, length);
  243   		} catch (IOException ioEx) {
  244   			SQLException sqlEx = SQLError.createSQLException(Messages.getString("Blob.1"), //$NON-NLS-1$
  245   					SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  246   			sqlEx.initCause(ioEx);
  247   			
  248   			throw sqlEx;
  249   		} finally {
  250   			try {
  251   				bytesOut.close();
  252   			} catch (IOException doNothing) {
  253   				; // do nothing
  254   			}
  255   		}
  256   
  257   		return length;
  258   	}
  259   
  260   	/**
  261   	 * @see com.mysql.jdbc.OutputStreamWatcher#streamClosed(byte[])
  262   	 */
  263   	public synchronized void streamClosed(byte[] byteData) {
  264   		this.binaryData = byteData;
  265   	}
  266   
  267   	/**
  268   	 * @see com.mysql.jdbc.OutputStreamWatcher#streamClosed(byte[])
  269   	 */
  270   	public synchronized void streamClosed(WatchableOutputStream out) {
  271   		int streamSize = out.size();
  272   
  273   		if (streamSize < this.binaryData.length) {
  274   			out.write(this.binaryData, streamSize, this.binaryData.length
  275   					- streamSize);
  276   		}
  277   
  278   		this.binaryData = out.toByteArray();
  279   	}
  280   
  281   	/**
  282        * Truncates the <code>BLOB</code> value that this <code>Blob</code>
  283        * object represents to be <code>len</code> bytes in length.
  284        * <p>
  285        * <b>Note:</b> If the value specified for <code>len</code>
  286        * is greater then the length+1 of the <code>BLOB</code> value then the 
  287        * behavior is undefined. Some JDBC drivers may throw a 
  288        * <code>SQLException</code> while other drivers may support this 
  289        * operation.
  290        *
  291        * @param len the length, in bytes, to which the <code>BLOB</code> value
  292        *        that this <code>Blob</code> object represents should be truncated
  293        * @exception SQLException if there is an error accessing the
  294        *            <code>BLOB</code> value or if len is less than 0
  295        * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
  296        * this method
  297        * @since 1.4
  298        */
  299   	public synchronized void truncate(long len) throws SQLException {
  300   		checkClosed();
  301   		
  302   		if (len < 0) {
  303   			throw SQLError.createSQLException("\"len\" argument can not be < 1.", 
  304   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  305   		}
  306   		
  307   		if (len > this.binaryData.length) {
  308   			throw SQLError.createSQLException("\"len\" argument can not be larger than the BLOB's length.", 
  309   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  310   		}
  311   		
  312   		// TODO: Do this without copying byte[]s by maintaining some end pointer
  313   		// on the original data
  314   		
  315   		byte[] newData = new byte[(int)len];
  316   		System.arraycopy(getBinaryData(), 0, newData, 0, (int)len);
  317   		this.binaryData = newData;
  318   	}
  319   
  320   	/**
  321        * This method frees the <code>Blob</code> object and releases the resources that 
  322        * it holds. The object is invalid once the <code>free</code>
  323        * method is called.
  324        *<p>
  325        * After <code>free</code> has been called, any attempt to invoke a
  326        * method other than <code>free</code> will result in a <code>SQLException</code> 
  327        * being thrown.  If <code>free</code> is called multiple times, the subsequent
  328        * calls to <code>free</code> are treated as a no-op.
  329        *<p>
  330        * 
  331        * @throws SQLException if an error occurs releasing
  332        * the Blob's resources
  333        * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
  334        * this method
  335        * @since 1.6
  336        */
  337   	
  338   	public synchronized void free() throws SQLException {
  339   		this.binaryData = null;
  340   		this.isClosed = true;
  341   	}
  342   
  343   	/**
  344        * Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value, 
  345        * starting  with the byte specified by pos, which is length bytes in length.
  346        *
  347        * @param pos the offset to the first byte of the partial value to be retrieved.
  348        *  The first byte in the <code>Blob</code> is at position 1
  349        * @param length the length in bytes of the partial value to be retrieved
  350        * @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read.
  351        * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes
  352        * in the <code>Blob</code> or if pos + length is greater than the number of bytes 
  353        * in the <code>Blob</code>
  354        *
  355        * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
  356        * this method
  357        * @since 1.6
  358        */
  359   	public synchronized InputStream getBinaryStream(long pos, long length) throws SQLException {
  360   		checkClosed();
  361   		
  362   		if (pos < 1) {
  363   			throw SQLError.createSQLException("\"pos\" argument can not be < 1.", 
  364   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  365   		}
  366   		
  367   		pos--;
  368   		
  369   		if (pos > this.binaryData.length) {
  370   			throw SQLError.createSQLException("\"pos\" argument can not be larger than the BLOB's length.", 
  371   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  372   		}
  373   		
  374   		if (pos + length > this.binaryData.length) {
  375   			throw SQLError.createSQLException("\"pos\" + \"length\" arguments can not be larger than the BLOB's length.", 
  376   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  377   		}
  378   		
  379   		return new ByteArrayInputStream(getBinaryData(), (int)pos, (int)length);
  380   	}
  381   	
  382   	private synchronized void checkClosed() throws SQLException {
  383   		if (this.isClosed) {
  384   			throw SQLError.createSQLException("Invalid operation on closed BLOB", 
  385   					SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor);
  386   		}
  387   	}
  388   }

Home » MySQL-JDBC-5.1.11 » com.mysql.jdbc » [javadoc | source]