Logo Search packages:      
Sourcecode: mysql-connector-java version File versions  Download package

BlobFromLocator.java

/*
 Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
 

  The MySQL Connector/J is licensed under the terms of the GPLv2
  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
  this software, see the FLOSS License Exception
  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.

  This program is free software; you can redistribute it and/or modify it under the terms
  of the GNU General Public License as published by the Free Software Foundation; version 2
  of the License.

  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along with this
  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
  Floor, Boston, MA 02110-1301  USA



 */
package com.mysql.jdbc;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * The representation (mapping) in the JavaTM programming language of an SQL
 * BLOB value. An SQL BLOB is a built-in type that stores a Binary Large Object
 * as a column value in a row of a database table. The driver implements Blob
 * using an SQL locator(BLOB), which means that a Blob object contains a logical
 * pointer to the SQL BLOB data rather than the data itself. A Blob object is
 * valid for the duration of the transaction in which is was created. Methods in
 * the interfaces ResultSet, CallableStatement, and PreparedStatement, such as
 * getBlob and setBlob allow a programmer to access an SQL BLOB value. The Blob
 * interface provides methods for getting the length of an SQL BLOB (Binary
 * Large Object) value, for materializing a BLOB value on the client, and for
 * determining the position of a pattern of bytes within a BLOB value. This
 * class is new in the JDBC 2.0 API.
 * 
 * @author Mark Matthews
 * 
 * @version $Id: BlobFromLocator.java,v 1.1.4.1 2005/05/19 18:31:49 mmatthews
 *          Exp $
 */
00055 public class BlobFromLocator implements java.sql.Blob {
      private List primaryKeyColumns = null;

      private List primaryKeyValues = null;

      /** The ResultSet that created this BLOB */
00061       private ResultSetImpl creatorResultSet;

      private String blobColumnName = null;

      private String tableName = null;

      private int numColsInResultSet = 0;

      private int numPrimaryKeys = 0;

      private String quotedId;

      private ExceptionInterceptor exceptionInterceptor;
      
      /**
       * Creates an updatable BLOB that can update in-place
       */
00078       BlobFromLocator(ResultSetImpl creatorResultSetToSet, int blobColumnIndex, ExceptionInterceptor exceptionInterceptor)
                  throws SQLException {
            this.exceptionInterceptor = exceptionInterceptor;
            this.creatorResultSet = creatorResultSetToSet;

            this.numColsInResultSet = this.creatorResultSet.fields.length;
            this.quotedId = this.creatorResultSet.connection.getMetaData()
                        .getIdentifierQuoteString();

            if (this.numColsInResultSet > 1) {
                  this.primaryKeyColumns = new ArrayList();
                  this.primaryKeyValues = new ArrayList();

                  for (int i = 0; i < this.numColsInResultSet; i++) {
                        if (this.creatorResultSet.fields[i].isPrimaryKey()) {
                              StringBuffer keyName = new StringBuffer();
                              keyName.append(quotedId);

                              String originalColumnName = this.creatorResultSet.fields[i]
                                          .getOriginalName();

                              if ((originalColumnName != null)
                                          && (originalColumnName.length() > 0)) {
                                    keyName.append(originalColumnName);
                              } else {
                                    keyName.append(this.creatorResultSet.fields[i]
                                                .getName());
                              }

                              keyName.append(quotedId);

                              this.primaryKeyColumns.add(keyName.toString());
                              this.primaryKeyValues.add(this.creatorResultSet
                                          .getString(i + 1));
                        }
                  }
            } else {
                  notEnoughInformationInQuery();
            }

            this.numPrimaryKeys = this.primaryKeyColumns.size();

            if (this.numPrimaryKeys == 0) {
                  notEnoughInformationInQuery();
            }

            if (this.creatorResultSet.fields[0].getOriginalTableName() != null) {
                  StringBuffer tableNameBuffer = new StringBuffer();

                  String databaseName = this.creatorResultSet.fields[0]
                              .getDatabaseName();

                  if ((databaseName != null) && (databaseName.length() > 0)) {
                        tableNameBuffer.append(quotedId);
                        tableNameBuffer.append(databaseName);
                        tableNameBuffer.append(quotedId);
                        tableNameBuffer.append('.');
                  }

                  tableNameBuffer.append(quotedId);
                  tableNameBuffer.append(this.creatorResultSet.fields[0]
                              .getOriginalTableName());
                  tableNameBuffer.append(quotedId);

                  this.tableName = tableNameBuffer.toString();
            } else {
                  StringBuffer tableNameBuffer = new StringBuffer();

                  tableNameBuffer.append(quotedId);
                  tableNameBuffer.append(this.creatorResultSet.fields[0]
                              .getTableName());
                  tableNameBuffer.append(quotedId);

                  this.tableName = tableNameBuffer.toString();
            }

            this.blobColumnName = quotedId
                        + this.creatorResultSet.getString(blobColumnIndex) + quotedId;
      }

      private void notEnoughInformationInQuery() throws SQLException {
            throw SQLError.createSQLException("Emulated BLOB locators must come from "
                        + "a ResultSet with only one table selected, and all primary "
                        + "keys selected", SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
      }

      /**
       * @see Blob#setBinaryStream(long)
       */
00167       public OutputStream setBinaryStream(long indexToWriteAt)
                  throws SQLException {
            throw SQLError.notImplemented();
      }

      /**
       * Retrieves the BLOB designated by this Blob instance as a stream.
       * 
       * @return this BLOB represented as a binary stream of bytes.
       * 
       * @throws SQLException
       *             if a database error occurs
       */
00180       public java.io.InputStream getBinaryStream() throws SQLException {
            // TODO: Make fetch size configurable
            return new BufferedInputStream(new LocatorInputStream(),
                        this.creatorResultSet.connection.getLocatorFetchBufferSize());
      }

      /**
       * @see Blob#setBytes(long, byte[], int, int)
       */
00189       public int setBytes(long writeAt, byte[] bytes, int offset, int length)
                  throws SQLException {
            java.sql.PreparedStatement pStmt = null;

            if ((offset + length) > bytes.length) {
                  length = bytes.length - offset;
            }

            byte[] bytesToWrite = new byte[length];
            System.arraycopy(bytes, offset, bytesToWrite, 0, length);

            // FIXME: Needs to use identifiers for column/table names
            StringBuffer query = new StringBuffer("UPDATE ");
            query.append(this.tableName);
            query.append(" SET ");
            query.append(this.blobColumnName);
            query.append(" = INSERT(");
            query.append(this.blobColumnName);
            query.append(", ");
            query.append(writeAt);
            query.append(", ");
            query.append(length);
            query.append(", ?) WHERE ");

            query.append((String) this.primaryKeyColumns.get(0));
            query.append(" = ?");

            for (int i = 1; i < this.numPrimaryKeys; i++) {
                  query.append(" AND ");
                  query.append((String) this.primaryKeyColumns.get(i));
                  query.append(" = ?");
            }

            try {
                  // FIXME: Have this passed in instead
                  pStmt = this.creatorResultSet.connection.prepareStatement(query
                              .toString());

                  pStmt.setBytes(1, bytesToWrite);

                  for (int i = 0; i < this.numPrimaryKeys; i++) {
                        pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
                  }

                  int rowsUpdated = pStmt.executeUpdate();

                  if (rowsUpdated != 1) {
                        throw SQLError.createSQLException(
                                    "BLOB data not found! Did primary keys change?",
                                    SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
                  }
            } finally {
                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        pStmt = null;
                  }
            }

            return (int) length();
      }

      /**
       * @see Blob#setBytes(long, byte[])
       */
00258       public int setBytes(long writeAt, byte[] bytes) throws SQLException {
            return setBytes(writeAt, bytes, 0, bytes.length);
      }

      /**
       * Returns as an array of bytes, part or all of the BLOB value that this
       * Blob object designates.
       * 
       * @param pos
       *            where to start the part of the BLOB
       * @param length
       *            the length of the part of the BLOB you want returned.
       * 
       * @return the bytes stored in the blob starting at position
       *         <code>pos</code> and having a length of <code>length</code>.
       * 
       * @throws SQLException
       *             if a database error occurs
       */
00277       public byte[] getBytes(long pos, int length) throws SQLException {
            java.sql.PreparedStatement pStmt = null;

            try {

                  pStmt = createGetBytesStatement();

                  return getBytesInternal(pStmt, pos, length);
            } finally {
                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        pStmt = null;
                  }
            }
      }
      
      /**
       * Returns the number of bytes in the BLOB value designated by this Blob
       * object.
       * 
       * @return the length of this blob
       * 
       * @throws SQLException
       *             if a database error occurs
       */
00307       public long length() throws SQLException {
            java.sql.ResultSet blobRs = null;
            java.sql.PreparedStatement pStmt = null;

            // FIXME: Needs to use identifiers for column/table names
            StringBuffer query = new StringBuffer("SELECT LENGTH(");
            query.append(this.blobColumnName);
            query.append(") FROM ");
            query.append(this.tableName);
            query.append(" WHERE ");

            query.append((String) this.primaryKeyColumns.get(0));
            query.append(" = ?");

            for (int i = 1; i < this.numPrimaryKeys; i++) {
                  query.append(" AND ");
                  query.append((String) this.primaryKeyColumns.get(i));
                  query.append(" = ?");
            }

            try {
                  // FIXME: Have this passed in instead
                  pStmt = this.creatorResultSet.connection.prepareStatement(query
                              .toString());

                  for (int i = 0; i < this.numPrimaryKeys; i++) {
                        pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
                  }

                  blobRs = pStmt.executeQuery();

                  if (blobRs.next()) {
                        return blobRs.getLong(1);
                  }

                  throw SQLError.createSQLException(
                              "BLOB data not found! Did primary keys change?",
                              SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
            } finally {
                  if (blobRs != null) {
                        try {
                              blobRs.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        blobRs = null;
                  }

                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        pStmt = null;
                  }
            }
      }

      /**
       * Finds the position of the given pattern in this BLOB.
       * 
       * @param pattern
       *            the pattern to find
       * @param start
       *            where to start finding the pattern
       * 
       * @return the position where the pattern is found in the BLOB, -1 if not
       *         found
       * 
       * @throws SQLException
       *             if a database error occurs
       */
00382       public long position(java.sql.Blob pattern, long start) throws SQLException {
            return position(pattern.getBytes(0, (int) pattern.length()), start);
      }

      /**
       * @see java.sql.Blob#position(byte[], long)
       */
00389       public long position(byte[] pattern, long start) throws SQLException {
            java.sql.ResultSet blobRs = null;
            java.sql.PreparedStatement pStmt = null;

            // FIXME: Needs to use identifiers for column/table names
            StringBuffer query = new StringBuffer("SELECT LOCATE(");
            query.append("?, ");
            query.append(this.blobColumnName);
            query.append(", ");
            query.append(start);
            query.append(") FROM ");
            query.append(this.tableName);
            query.append(" WHERE ");

            query.append((String) this.primaryKeyColumns.get(0));
            query.append(" = ?");

            for (int i = 1; i < this.numPrimaryKeys; i++) {
                  query.append(" AND ");
                  query.append((String) this.primaryKeyColumns.get(i));
                  query.append(" = ?");
            }

            try {
                  // FIXME: Have this passed in instead
                  pStmt = this.creatorResultSet.connection.prepareStatement(query
                              .toString());
                  pStmt.setBytes(1, pattern);

                  for (int i = 0; i < this.numPrimaryKeys; i++) {
                        pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
                  }

                  blobRs = pStmt.executeQuery();

                  if (blobRs.next()) {
                        return blobRs.getLong(1);
                  }

                  throw SQLError.createSQLException(
                              "BLOB data not found! Did primary keys change?",
                              SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
            } finally {
                  if (blobRs != null) {
                        try {
                              blobRs.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        blobRs = null;
                  }

                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        pStmt = null;
                  }
            }
      }

      /**
       * @see Blob#truncate(long)
       */
00457       public void truncate(long length) throws SQLException {
            java.sql.PreparedStatement pStmt = null;

            // FIXME: Needs to use identifiers for column/table names
            StringBuffer query = new StringBuffer("UPDATE ");
            query.append(this.tableName);
            query.append(" SET ");
            query.append(this.blobColumnName);
            query.append(" = LEFT(");
            query.append(this.blobColumnName);
            query.append(", ");
            query.append(length);
            query.append(") WHERE ");

            query.append((String) this.primaryKeyColumns.get(0));
            query.append(" = ?");

            for (int i = 1; i < this.numPrimaryKeys; i++) {
                  query.append(" AND ");
                  query.append((String) this.primaryKeyColumns.get(i));
                  query.append(" = ?");
            }

            try {
                  // FIXME: Have this passed in instead
                  pStmt = this.creatorResultSet.connection.prepareStatement(query
                              .toString());

                  for (int i = 0; i < this.numPrimaryKeys; i++) {
                        pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
                  }

                  int rowsUpdated = pStmt.executeUpdate();

                  if (rowsUpdated != 1) {
                        throw SQLError.createSQLException(
                                    "BLOB data not found! Did primary keys change?",
                                    SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
                  }
            } finally {
                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        pStmt = null;
                  }
            }
      }

      java.sql.PreparedStatement createGetBytesStatement() throws SQLException {
            StringBuffer query = new StringBuffer("SELECT SUBSTRING(");

            query.append(this.blobColumnName);
            query.append(", ");
            query.append("?");
            query.append(", ");
            query.append("?");
            query.append(") FROM ");
            query.append(this.tableName);
            query.append(" WHERE ");

            query.append((String) this.primaryKeyColumns.get(0));
            query.append(" = ?");

            for (int i = 1; i < this.numPrimaryKeys; i++) {
                  query.append(" AND ");
                  query.append((String) this.primaryKeyColumns.get(i));
                  query.append(" = ?");
            }

            return this.creatorResultSet.connection.prepareStatement(query
                        .toString());
      }

      byte[] getBytesInternal(java.sql.PreparedStatement pStmt, long pos,
                  int length) throws SQLException {

            java.sql.ResultSet blobRs = null;

            try {

                  pStmt.setLong(1, pos);
                  pStmt.setInt(2, length);

                  for (int i = 0; i < this.numPrimaryKeys; i++) {
                        pStmt.setString(i + 3, (String) this.primaryKeyValues.get(i));
                  }

                  blobRs = pStmt.executeQuery();

                  if (blobRs.next()) {
                        return ((com.mysql.jdbc.ResultSetImpl) blobRs).getBytes(1, true);
                  }

                  throw SQLError.createSQLException(
                              "BLOB data not found! Did primary keys change?",
                              SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
            } finally {
                  if (blobRs != null) {
                        try {
                              blobRs.close();
                        } catch (SQLException sqlEx) {
                              ; // do nothing
                        }

                        blobRs = null;
                  }
            }
      }

00570       class LocatorInputStream extends InputStream {
            long currentPositionInBlob = 0;

            long length = 0;

            java.sql.PreparedStatement pStmt = null;

            LocatorInputStream() throws SQLException {
                  length = length();
                  pStmt = createGetBytesStatement();
            }

            LocatorInputStream(long pos, long len) throws SQLException {
                  length = pos + len;
                  currentPositionInBlob = pos;
                  long blobLength = length();
                  
                  if (pos + len > blobLength) {
                        throw SQLError.createSQLException(
                                    Messages.getString("Blob.invalidStreamLength", 
                                                new Object[] {Long.valueOf(blobLength), Long.valueOf(pos), Long.valueOf(len)}),
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
                  }
                  
                  if (pos < 1) {
                        throw SQLError.createSQLException(Messages.getString("Blob.invalidStreamPos"), 
                                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
                  }
                  
                  if (pos > blobLength) {
                        throw SQLError.createSQLException(Messages.getString("Blob.invalidStreamPos"), 
                                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
                  }
            }
            
            public int read() throws IOException {
                  if (currentPositionInBlob + 1 > length) {
                        return -1;
                  }

                  try {
                        byte[] asBytes = getBytesInternal(pStmt,
                                    (currentPositionInBlob++) + 1, 1);

                        if (asBytes == null) {
                              return -1;
                        }

                        return asBytes[0];
                  } catch (SQLException sqlEx) {
                        throw new IOException(sqlEx.toString());
                  }
            }

            /*
             * (non-Javadoc)
             * 
             * @see java.io.InputStream#read(byte[], int, int)
             */
            public int read(byte[] b, int off, int len) throws IOException {
                  if (currentPositionInBlob + 1 > length) {
                        return -1;
                  }

                  try {
                        byte[] asBytes = getBytesInternal(pStmt,
                                    (currentPositionInBlob) + 1, len);

                        if (asBytes == null) {
                              return -1;
                        }

                        System.arraycopy(asBytes, 0, b, off, asBytes.length);

                        currentPositionInBlob += asBytes.length;

                        return asBytes.length;
                  } catch (SQLException sqlEx) {
                        throw new IOException(sqlEx.toString());
                  }
            }

            /*
             * (non-Javadoc)
             * 
             * @see java.io.InputStream#read(byte[])
             */
            public int read(byte[] b) throws IOException {
                  if (currentPositionInBlob + 1 > length) {
                        return -1;
                  }

                  try {
                        byte[] asBytes = getBytesInternal(pStmt,
                                    (currentPositionInBlob) + 1, b.length);

                        if (asBytes == null) {
                              return -1;
                        }

                        System.arraycopy(asBytes, 0, b, 0, asBytes.length);

                        currentPositionInBlob += asBytes.length;

                        return asBytes.length;
                  } catch (SQLException sqlEx) {
                        throw new IOException(sqlEx.toString());
                  }
            }

            /*
             * (non-Javadoc)
             * 
             * @see java.io.InputStream#close()
             */
            public void close() throws IOException {
                  if (pStmt != null) {
                        try {
                              pStmt.close();
                        } catch (SQLException sqlEx) {
                              throw new IOException(sqlEx.toString());
                        }
                  }

                  super.close();
            }
      }

      public void free() throws SQLException {
            this.creatorResultSet = null;
            this.primaryKeyColumns = null;
            this.primaryKeyValues = null;
      }

      public InputStream getBinaryStream(long pos, long length) throws SQLException {
            return new LocatorInputStream(pos, length);
      }
}

Generated by  Doxygen 1.6.0   Back to index