EMMA Coverage Report (generated Wed Jul 26 14:28:59 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [BlobFromLocator.java]

nameclass, %method, %block, %line, %
BlobFromLocator.java50%  (1/2)39%  (7/18)51%  (616/1202)49%  (128.3/264)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class BlobFromLocator$LocatorInputStream0%   (0/1)0%   (0/5)0%   (0/182)0%   (0/42)
BlobFromLocator$LocatorInputStream (BlobFromLocator): void 0%   (0/1)0%   (0/23)0%   (0/7)
close (): void 0%   (0/1)0%   (0/17)0%   (0/7)
read (): int 0%   (0/1)0%   (0/41)0%   (0/8)
read (byte []): int 0%   (0/1)0%   (0/51)0%   (0/10)
read (byte [], int, int): int 0%   (0/1)0%   (0/50)0%   (0/10)
     
class BlobFromLocator100% (1/1)54%  (7/13)60%  (616/1020)58%  (128.3/222)
getBinaryStream (): InputStream 0%   (0/1)0%   (0/12)0%   (0/1)
notEnoughInformationInQuery (): void 0%   (0/1)0%   (0/4)0%   (0/1)
position (Blob, long): long 0%   (0/1)0%   (0/10)0%   (0/1)
position (byte [], long): long 0%   (0/1)0%   (0/143)0%   (0/34)
setBinaryStream (long): OutputStream 0%   (0/1)0%   (0/4)0%   (0/1)
truncate (long): void 0%   (0/1)0%   (0/130)0%   (0/30)
getBytes (long, int): byte [] 100% (1/1)67%  (20/30)53%  (4.8/9)
length (): long 100% (1/1)78%  (99/127)77%  (23.1/30)
createGetBytesStatement (): PreparedStatement 100% (1/1)78%  (64/82)80%  (12.8/16)
setBytes (long, byte [], int, int): int 100% (1/1)81%  (133/165)82%  (30.2/37)
getBytesInternal (PreparedStatement, long, int): byte [] 100% (1/1)85%  (52/61)82%  (11.4/14)
BlobFromLocator (ResultSet, int): void 100% (1/1)98%  (240/244)96%  (45/47)
setBytes (long, byte []): int 100% (1/1)100% (8/8)100% (1/1)

1/*
2 Copyright (C) 2002-2004 MySQL AB
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 */
25package com.mysql.jdbc;
26 
27import java.io.BufferedInputStream;
28import java.io.IOException;
29import java.io.InputStream;
30import java.io.OutputStream;
31import java.sql.SQLException;
32import java.util.ArrayList;
33import java.util.List;
34 
35/**
36 * The representation (mapping) in the JavaTM programming language of an SQL
37 * BLOB value. An SQL BLOB is a built-in type that stores a Binary Large Object
38 * as a column value in a row of a database table. The driver implements Blob
39 * using an SQL locator(BLOB), which means that a Blob object contains a logical
40 * pointer to the SQL BLOB data rather than the data itself. A Blob object is
41 * valid for the duration of the transaction in which is was created. Methods in
42 * the interfaces ResultSet, CallableStatement, and PreparedStatement, such as
43 * getBlob and setBlob allow a programmer to access an SQL BLOB value. The Blob
44 * interface provides methods for getting the length of an SQL BLOB (Binary
45 * Large Object) value, for materializing a BLOB value on the client, and for
46 * determining the position of a pattern of bytes within a BLOB value. This
47 * class is new in the JDBC 2.0 API.
48 * 
49 * @author Mark Matthews
50 * 
51 * @version $Id: BlobFromLocator.java,v 1.1.4.1 2005/05/19 18:31:49 mmatthews
52 *          Exp $
53 */
54public class BlobFromLocator implements java.sql.Blob {
55        private List primaryKeyColumns = null;
56 
57        private List primaryKeyValues = null;
58 
59        /** The ResultSet that created this BLOB */
60        private ResultSet creatorResultSet;
61 
62        private String blobColumnName = null;
63 
64        private String tableName = null;
65 
66        private int numColsInResultSet = 0;
67 
68        private int numPrimaryKeys = 0;
69 
70        private String quotedId;
71 
72        /**
73         * Creates an updatable BLOB that can update in-place
74         */
75        BlobFromLocator(ResultSet creatorResultSetToSet, int blobColumnIndex)
76                        throws SQLException {
77                this.creatorResultSet = creatorResultSetToSet;
78 
79                this.numColsInResultSet = this.creatorResultSet.fields.length;
80                this.quotedId = this.creatorResultSet.connection.getMetaData()
81                                .getIdentifierQuoteString();
82 
83                if (this.numColsInResultSet > 1) {
84                        this.primaryKeyColumns = new ArrayList();
85                        this.primaryKeyValues = new ArrayList();
86 
87                        for (int i = 0; i < this.numColsInResultSet; i++) {
88                                if (this.creatorResultSet.fields[i].isPrimaryKey()) {
89                                        StringBuffer keyName = new StringBuffer();
90                                        keyName.append(quotedId);
91 
92                                        String originalColumnName = this.creatorResultSet.fields[i]
93                                                        .getOriginalName();
94 
95                                        if ((originalColumnName != null)
96                                                        && (originalColumnName.length() > 0)) {
97                                                keyName.append(originalColumnName);
98                                        } else {
99                                                keyName.append(this.creatorResultSet.fields[i]
100                                                                .getName());
101                                        }
102 
103                                        keyName.append(quotedId);
104 
105                                        this.primaryKeyColumns.add(keyName.toString());
106                                        this.primaryKeyValues.add(this.creatorResultSet
107                                                        .getString(i + 1));
108                                }
109                        }
110                } else {
111                        notEnoughInformationInQuery();
112                }
113 
114                this.numPrimaryKeys = this.primaryKeyColumns.size();
115 
116                if (this.numPrimaryKeys == 0) {
117                        notEnoughInformationInQuery();
118                }
119 
120                if (this.creatorResultSet.fields[0].getOriginalTableName() != null) {
121                        StringBuffer tableNameBuffer = new StringBuffer();
122 
123                        String databaseName = this.creatorResultSet.fields[0]
124                                        .getDatabaseName();
125 
126                        if ((databaseName != null) && (databaseName.length() > 0)) {
127                                tableNameBuffer.append(quotedId);
128                                tableNameBuffer.append(databaseName);
129                                tableNameBuffer.append(quotedId);
130                                tableNameBuffer.append('.');
131                        }
132 
133                        tableNameBuffer.append(quotedId);
134                        tableNameBuffer.append(this.creatorResultSet.fields[0]
135                                        .getOriginalTableName());
136                        tableNameBuffer.append(quotedId);
137 
138                        this.tableName = tableNameBuffer.toString();
139                } else {
140                        StringBuffer tableNameBuffer = new StringBuffer();
141 
142                        tableNameBuffer.append(quotedId);
143                        tableNameBuffer.append(this.creatorResultSet.fields[0]
144                                        .getTableName());
145                        tableNameBuffer.append(quotedId);
146 
147                        this.tableName = tableNameBuffer.toString();
148                }
149 
150                this.blobColumnName = quotedId
151                                + this.creatorResultSet.getString(blobColumnIndex) + quotedId;
152        }
153 
154        private void notEnoughInformationInQuery() throws SQLException {
155                throw SQLError.createSQLException("Emulated BLOB locators must come from "
156                                + "a ResultSet with only one table selected, and all primary "
157                                + "keys selected", SQLError.SQL_STATE_GENERAL_ERROR);
158        }
159 
160        /**
161         * @see Blob#setBinaryStream(long)
162         */
163        public OutputStream setBinaryStream(long indexToWriteAt)
164                        throws SQLException {
165                throw new NotImplemented();
166        }
167 
168        /**
169         * Retrieves the BLOB designated by this Blob instance as a stream.
170         * 
171         * @return this BLOB represented as a binary stream of bytes.
172         * 
173         * @throws SQLException
174         *             if a database error occurs
175         */
176        public java.io.InputStream getBinaryStream() throws SQLException {
177                // TODO: Make fetch size configurable
178                return new BufferedInputStream(new LocatorInputStream(),
179                                this.creatorResultSet.connection.getLocatorFetchBufferSize());
180        }
181 
182        /**
183         * @see Blob#setBytes(long, byte[], int, int)
184         */
185        public int setBytes(long writeAt, byte[] bytes, int offset, int length)
186                        throws SQLException {
187                java.sql.PreparedStatement pStmt = null;
188 
189                if ((offset + length) > bytes.length) {
190                        length = bytes.length - offset;
191                }
192 
193                byte[] bytesToWrite = new byte[length];
194                System.arraycopy(bytes, offset, bytesToWrite, 0, length);
195 
196                // FIXME: Needs to use identifiers for column/table names
197                StringBuffer query = new StringBuffer("UPDATE ");
198                query.append(this.tableName);
199                query.append(" SET ");
200                query.append(this.blobColumnName);
201                query.append(" = INSERT(");
202                query.append(this.blobColumnName);
203                query.append(", ");
204                query.append(writeAt);
205                query.append(", ");
206                query.append(length);
207                query.append(", ?) WHERE ");
208 
209                query.append((String) this.primaryKeyColumns.get(0));
210                query.append(" = ?");
211 
212                for (int i = 1; i < this.numPrimaryKeys; i++) {
213                        query.append(" AND ");
214                        query.append((String) this.primaryKeyColumns.get(i));
215                        query.append(" = ?");
216                }
217 
218                try {
219                        // FIXME: Have this passed in instead
220                        pStmt = this.creatorResultSet.connection.prepareStatement(query
221                                        .toString());
222 
223                        pStmt.setBytes(1, bytesToWrite);
224 
225                        for (int i = 0; i < this.numPrimaryKeys; i++) {
226                                pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
227                        }
228 
229                        int rowsUpdated = pStmt.executeUpdate();
230 
231                        if (rowsUpdated != 1) {
232                                throw SQLError.createSQLException(
233                                                "BLOB data not found! Did primary keys change?",
234                                                SQLError.SQL_STATE_GENERAL_ERROR);
235                        }
236                } finally {
237                        if (pStmt != null) {
238                                try {
239                                        pStmt.close();
240                                } catch (SQLException sqlEx) {
241                                        ; // do nothing
242                                }
243 
244                                pStmt = null;
245                        }
246                }
247 
248                return (int) length();
249        }
250 
251        /**
252         * @see Blob#setBytes(long, byte[])
253         */
254        public int setBytes(long writeAt, byte[] bytes) throws SQLException {
255                return setBytes(writeAt, bytes, 0, bytes.length);
256        }
257 
258        /**
259         * Returns as an array of bytes, part or all of the BLOB value that this
260         * Blob object designates.
261         * 
262         * @param pos
263         *            where to start the part of the BLOB
264         * @param length
265         *            the length of the part of the BLOB you want returned.
266         * 
267         * @return the bytes stored in the blob starting at position
268         *         <code>pos</code> and having a length of <code>length</code>.
269         * 
270         * @throws SQLException
271         *             if a database error occurs
272         */
273        public byte[] getBytes(long pos, int length) throws SQLException {
274                java.sql.ResultSet blobRs = null;
275                java.sql.PreparedStatement pStmt = null;
276 
277                try {
278 
279                        pStmt = createGetBytesStatement();
280 
281                        return getBytesInternal(pStmt, pos, length);
282                } finally {
283                        if (blobRs != null) {
284                                try {
285                                        blobRs.close();
286                                } catch (SQLException sqlEx) {
287                                        ; // do nothing
288                                }
289 
290                                blobRs = null;
291                        }
292                }
293        }
294 
295        /**
296         * Returns the number of bytes in the BLOB value designated by this Blob
297         * object.
298         * 
299         * @return the length of this blob
300         * 
301         * @throws SQLException
302         *             if a database error occurs
303         */
304        public long length() throws SQLException {
305                java.sql.ResultSet blobRs = null;
306                java.sql.PreparedStatement pStmt = null;
307 
308                // FIXME: Needs to use identifiers for column/table names
309                StringBuffer query = new StringBuffer("SELECT LENGTH(");
310                query.append(this.blobColumnName);
311                query.append(") FROM ");
312                query.append(this.tableName);
313                query.append(" WHERE ");
314 
315                query.append((String) this.primaryKeyColumns.get(0));
316                query.append(" = ?");
317 
318                for (int i = 1; i < this.numPrimaryKeys; i++) {
319                        query.append(" AND ");
320                        query.append((String) this.primaryKeyColumns.get(i));
321                        query.append(" = ?");
322                }
323 
324                try {
325                        // FIXME: Have this passed in instead
326                        pStmt = this.creatorResultSet.connection.prepareStatement(query
327                                        .toString());
328 
329                        for (int i = 0; i < this.numPrimaryKeys; i++) {
330                                pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
331                        }
332 
333                        blobRs = pStmt.executeQuery();
334 
335                        if (blobRs.next()) {
336                                return blobRs.getLong(1);
337                        }
338 
339                        throw SQLError.createSQLException(
340                                        "BLOB data not found! Did primary keys change?",
341                                        SQLError.SQL_STATE_GENERAL_ERROR);
342                } finally {
343                        if (blobRs != null) {
344                                try {
345                                        blobRs.close();
346                                } catch (SQLException sqlEx) {
347                                        ; // do nothing
348                                }
349 
350                                blobRs = null;
351                        }
352 
353                        if (pStmt != null) {
354                                try {
355                                        pStmt.close();
356                                } catch (SQLException sqlEx) {
357                                        ; // do nothing
358                                }
359 
360                                pStmt = null;
361                        }
362                }
363        }
364 
365        /**
366         * Finds the position of the given pattern in this BLOB.
367         * 
368         * @param pattern
369         *            the pattern to find
370         * @param start
371         *            where to start finding the pattern
372         * 
373         * @return the position where the pattern is found in the BLOB, -1 if not
374         *         found
375         * 
376         * @throws SQLException
377         *             if a database error occurs
378         */
379        public long position(java.sql.Blob pattern, long start) throws SQLException {
380                return position(pattern.getBytes(0, (int) pattern.length()), start);
381        }
382 
383        /**
384         * @see java.sql.Blob#position(byte[], long)
385         */
386        public long position(byte[] pattern, long start) throws SQLException {
387                java.sql.ResultSet blobRs = null;
388                java.sql.PreparedStatement pStmt = null;
389 
390                // FIXME: Needs to use identifiers for column/table names
391                StringBuffer query = new StringBuffer("SELECT LOCATE(");
392                query.append("?, ");
393                query.append(this.blobColumnName);
394                query.append(", ");
395                query.append(start);
396                query.append(") FROM ");
397                query.append(this.tableName);
398                query.append(" WHERE ");
399 
400                query.append((String) this.primaryKeyColumns.get(0));
401                query.append(" = ?");
402 
403                for (int i = 1; i < this.numPrimaryKeys; i++) {
404                        query.append(" AND ");
405                        query.append((String) this.primaryKeyColumns.get(i));
406                        query.append(" = ?");
407                }
408 
409                try {
410                        // FIXME: Have this passed in instead
411                        pStmt = this.creatorResultSet.connection.prepareStatement(query
412                                        .toString());
413                        pStmt.setBytes(1, pattern);
414 
415                        for (int i = 0; i < this.numPrimaryKeys; i++) {
416                                pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
417                        }
418 
419                        blobRs = pStmt.executeQuery();
420 
421                        if (blobRs.next()) {
422                                return blobRs.getLong(1);
423                        }
424 
425                        throw SQLError.createSQLException(
426                                        "BLOB data not found! Did primary keys change?",
427                                        SQLError.SQL_STATE_GENERAL_ERROR);
428                } finally {
429                        if (blobRs != null) {
430                                try {
431                                        blobRs.close();
432                                } catch (SQLException sqlEx) {
433                                        ; // do nothing
434                                }
435 
436                                blobRs = null;
437                        }
438 
439                        if (pStmt != null) {
440                                try {
441                                        pStmt.close();
442                                } catch (SQLException sqlEx) {
443                                        ; // do nothing
444                                }
445 
446                                pStmt = null;
447                        }
448                }
449        }
450 
451        /**
452         * @see Blob#truncate(long)
453         */
454        public void truncate(long length) throws SQLException {
455                java.sql.PreparedStatement pStmt = null;
456 
457                // FIXME: Needs to use identifiers for column/table names
458                StringBuffer query = new StringBuffer("UPDATE ");
459                query.append(this.tableName);
460                query.append(" SET ");
461                query.append(this.blobColumnName);
462                query.append(" = LEFT(");
463                query.append(this.blobColumnName);
464                query.append(", ");
465                query.append(length);
466                query.append(") WHERE ");
467 
468                query.append((String) this.primaryKeyColumns.get(0));
469                query.append(" = ?");
470 
471                for (int i = 1; i < this.numPrimaryKeys; i++) {
472                        query.append(" AND ");
473                        query.append((String) this.primaryKeyColumns.get(i));
474                        query.append(" = ?");
475                }
476 
477                try {
478                        // FIXME: Have this passed in instead
479                        pStmt = this.creatorResultSet.connection.prepareStatement(query
480                                        .toString());
481 
482                        for (int i = 0; i < this.numPrimaryKeys; i++) {
483                                pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
484                        }
485 
486                        int rowsUpdated = pStmt.executeUpdate();
487 
488                        if (rowsUpdated != 1) {
489                                throw SQLError.createSQLException(
490                                                "BLOB data not found! Did primary keys change?",
491                                                SQLError.SQL_STATE_GENERAL_ERROR);
492                        }
493                } finally {
494                        if (pStmt != null) {
495                                try {
496                                        pStmt.close();
497                                } catch (SQLException sqlEx) {
498                                        ; // do nothing
499                                }
500 
501                                pStmt = null;
502                        }
503                }
504        }
505 
506        java.sql.PreparedStatement createGetBytesStatement() throws SQLException {
507                StringBuffer query = new StringBuffer("SELECT SUBSTRING(");
508 
509                query.append(this.blobColumnName);
510                query.append(", ");
511                query.append("?");
512                query.append(", ");
513                query.append("?");
514                query.append(") FROM ");
515                query.append(this.tableName);
516                query.append(" WHERE ");
517 
518                query.append((String) this.primaryKeyColumns.get(0));
519                query.append(" = ?");
520 
521                for (int i = 1; i < this.numPrimaryKeys; i++) {
522                        query.append(" AND ");
523                        query.append((String) this.primaryKeyColumns.get(i));
524                        query.append(" = ?");
525                }
526 
527                return this.creatorResultSet.connection.prepareStatement(query
528                                .toString());
529        }
530 
531        byte[] getBytesInternal(java.sql.PreparedStatement pStmt, long pos,
532                        int length) throws SQLException {
533 
534                java.sql.ResultSet blobRs = null;
535 
536                try {
537 
538                        pStmt.setLong(1, pos);
539                        pStmt.setInt(2, length);
540 
541                        for (int i = 0; i < this.numPrimaryKeys; i++) {
542                                pStmt.setString(i + 3, (String) this.primaryKeyValues.get(i));
543                        }
544 
545                        blobRs = pStmt.executeQuery();
546 
547                        if (blobRs.next()) {
548                                return ((com.mysql.jdbc.ResultSet) blobRs).getBytes(1, true);
549                        }
550 
551                        throw SQLError.createSQLException(
552                                        "BLOB data not found! Did primary keys change?",
553                                        SQLError.SQL_STATE_GENERAL_ERROR);
554                } finally {
555                        if (blobRs != null) {
556                                try {
557                                        blobRs.close();
558                                } catch (SQLException sqlEx) {
559                                        ; // do nothing
560                                }
561 
562                                blobRs = null;
563                        }
564                }
565        }
566 
567        class LocatorInputStream extends InputStream {
568                long currentPositionInBlob = 0;
569 
570                long length = 0;
571 
572                java.sql.PreparedStatement pStmt = null;
573 
574                LocatorInputStream() throws SQLException {
575                        length = length();
576                        pStmt = createGetBytesStatement();
577                }
578 
579                public int read() throws IOException {
580                        if (currentPositionInBlob + 1 > length) {
581                                return -1;
582                        }
583 
584                        try {
585                                byte[] asBytes = getBytesInternal(pStmt,
586                                                (currentPositionInBlob++) + 1, 1);
587 
588                                if (asBytes == null) {
589                                        return -1;
590                                }
591 
592                                return asBytes[0];
593                        } catch (SQLException sqlEx) {
594                                throw new IOException(sqlEx.toString());
595                        }
596                }
597 
598                /*
599                 * (non-Javadoc)
600                 * 
601                 * @see java.io.InputStream#read(byte[], int, int)
602                 */
603                public int read(byte[] b, int off, int len) throws IOException {
604                        if (currentPositionInBlob + 1 > length) {
605                                return -1;
606                        }
607 
608                        try {
609                                byte[] asBytes = getBytesInternal(pStmt,
610                                                (currentPositionInBlob) + 1, len);
611 
612                                if (asBytes == null) {
613                                        return -1;
614                                }
615 
616                                System.arraycopy(asBytes, 0, b, off, asBytes.length);
617 
618                                currentPositionInBlob += asBytes.length;
619 
620                                return asBytes.length;
621                        } catch (SQLException sqlEx) {
622                                throw new IOException(sqlEx.toString());
623                        }
624                }
625 
626                /*
627                 * (non-Javadoc)
628                 * 
629                 * @see java.io.InputStream#read(byte[])
630                 */
631                public int read(byte[] b) throws IOException {
632                        if (currentPositionInBlob + 1 > length) {
633                                return -1;
634                        }
635 
636                        try {
637                                byte[] asBytes = getBytesInternal(pStmt,
638                                                (currentPositionInBlob) + 1, b.length);
639 
640                                if (asBytes == null) {
641                                        return -1;
642                                }
643 
644                                System.arraycopy(asBytes, 0, b, 0, asBytes.length);
645 
646                                currentPositionInBlob += asBytes.length;
647 
648                                return asBytes.length;
649                        } catch (SQLException sqlEx) {
650                                throw new IOException(sqlEx.toString());
651                        }
652                }
653 
654                /*
655                 * (non-Javadoc)
656                 * 
657                 * @see java.io.InputStream#close()
658                 */
659                public void close() throws IOException {
660                        if (pStmt != null) {
661                                try {
662                                        pStmt.close();
663                                } catch (SQLException sqlEx) {
664                                        throw new IOException(sqlEx.toString());
665                                }
666                        }
667 
668                        super.close();
669                }
670        }
671}

[all classes][com.mysql.jdbc]
EMMA 2.0.4217 (C) Vladimir Roubtsov