PageRenderTime 27ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/EQEmuJSM/mysql-connector-java-5.1.13/src/com/mysql/jdbc/BlobFromLocator.java

http://cubbers-eqemu-utils.googlecode.com/
Java | 709 lines | 448 code | 126 blank | 135 comment | 64 complexity | 408a9020931b2c01ba6e401ef056b3a3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0
  1. /*
  2. Copyright 2002-2004 MySQL AB, 2008 Sun Microsystems
  3. All rights reserved. Use is subject to license terms.
  4. The MySQL Connector/J is licensed under the terms of the GPL,
  5. like most MySQL Connectors. There are special exceptions to the
  6. terms and conditions of the GPL as it is applied to this software,
  7. see the FLOSS License Exception available on mysql.com.
  8. This program is free software; you can redistribute it and/or
  9. modify it under the terms of the GNU General Public License as
  10. published by the Free Software Foundation; version 2 of the
  11. License.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  19. 02110-1301 USA
  20. */
  21. package com.mysql.jdbc;
  22. import java.io.BufferedInputStream;
  23. import java.io.IOException;
  24. import java.io.InputStream;
  25. import java.io.OutputStream;
  26. import java.sql.SQLException;
  27. import java.util.ArrayList;
  28. import java.util.List;
  29. /**
  30. * The representation (mapping) in the JavaTM programming language of an SQL
  31. * BLOB value. An SQL BLOB is a built-in type that stores a Binary Large Object
  32. * as a column value in a row of a database table. The driver implements Blob
  33. * using an SQL locator(BLOB), which means that a Blob object contains a logical
  34. * pointer to the SQL BLOB data rather than the data itself. A Blob object is
  35. * valid for the duration of the transaction in which is was created. Methods in
  36. * the interfaces ResultSet, CallableStatement, and PreparedStatement, such as
  37. * getBlob and setBlob allow a programmer to access an SQL BLOB value. The Blob
  38. * interface provides methods for getting the length of an SQL BLOB (Binary
  39. * Large Object) value, for materializing a BLOB value on the client, and for
  40. * determining the position of a pattern of bytes within a BLOB value. This
  41. * class is new in the JDBC 2.0 API.
  42. *
  43. * @author Mark Matthews
  44. *
  45. * @version $Id: BlobFromLocator.java,v 1.1.4.1 2005/05/19 18:31:49 mmatthews
  46. * Exp $
  47. */
  48. public class BlobFromLocator implements java.sql.Blob {
  49. private List primaryKeyColumns = null;
  50. private List primaryKeyValues = null;
  51. /** The ResultSet that created this BLOB */
  52. private ResultSetImpl creatorResultSet;
  53. private String blobColumnName = null;
  54. private String tableName = null;
  55. private int numColsInResultSet = 0;
  56. private int numPrimaryKeys = 0;
  57. private String quotedId;
  58. private ExceptionInterceptor exceptionInterceptor;
  59. /**
  60. * Creates an updatable BLOB that can update in-place
  61. */
  62. BlobFromLocator(ResultSetImpl creatorResultSetToSet, int blobColumnIndex, ExceptionInterceptor exceptionInterceptor)
  63. throws SQLException {
  64. this.exceptionInterceptor = exceptionInterceptor;
  65. this.creatorResultSet = creatorResultSetToSet;
  66. this.numColsInResultSet = this.creatorResultSet.fields.length;
  67. this.quotedId = this.creatorResultSet.connection.getMetaData()
  68. .getIdentifierQuoteString();
  69. if (this.numColsInResultSet > 1) {
  70. this.primaryKeyColumns = new ArrayList();
  71. this.primaryKeyValues = new ArrayList();
  72. for (int i = 0; i < this.numColsInResultSet; i++) {
  73. if (this.creatorResultSet.fields[i].isPrimaryKey()) {
  74. StringBuffer keyName = new StringBuffer();
  75. keyName.append(quotedId);
  76. String originalColumnName = this.creatorResultSet.fields[i]
  77. .getOriginalName();
  78. if ((originalColumnName != null)
  79. && (originalColumnName.length() > 0)) {
  80. keyName.append(originalColumnName);
  81. } else {
  82. keyName.append(this.creatorResultSet.fields[i]
  83. .getName());
  84. }
  85. keyName.append(quotedId);
  86. this.primaryKeyColumns.add(keyName.toString());
  87. this.primaryKeyValues.add(this.creatorResultSet
  88. .getString(i + 1));
  89. }
  90. }
  91. } else {
  92. notEnoughInformationInQuery();
  93. }
  94. this.numPrimaryKeys = this.primaryKeyColumns.size();
  95. if (this.numPrimaryKeys == 0) {
  96. notEnoughInformationInQuery();
  97. }
  98. if (this.creatorResultSet.fields[0].getOriginalTableName() != null) {
  99. StringBuffer tableNameBuffer = new StringBuffer();
  100. String databaseName = this.creatorResultSet.fields[0]
  101. .getDatabaseName();
  102. if ((databaseName != null) && (databaseName.length() > 0)) {
  103. tableNameBuffer.append(quotedId);
  104. tableNameBuffer.append(databaseName);
  105. tableNameBuffer.append(quotedId);
  106. tableNameBuffer.append('.');
  107. }
  108. tableNameBuffer.append(quotedId);
  109. tableNameBuffer.append(this.creatorResultSet.fields[0]
  110. .getOriginalTableName());
  111. tableNameBuffer.append(quotedId);
  112. this.tableName = tableNameBuffer.toString();
  113. } else {
  114. StringBuffer tableNameBuffer = new StringBuffer();
  115. tableNameBuffer.append(quotedId);
  116. tableNameBuffer.append(this.creatorResultSet.fields[0]
  117. .getTableName());
  118. tableNameBuffer.append(quotedId);
  119. this.tableName = tableNameBuffer.toString();
  120. }
  121. this.blobColumnName = quotedId
  122. + this.creatorResultSet.getString(blobColumnIndex) + quotedId;
  123. }
  124. private void notEnoughInformationInQuery() throws SQLException {
  125. throw SQLError.createSQLException("Emulated BLOB locators must come from "
  126. + "a ResultSet with only one table selected, and all primary "
  127. + "keys selected", SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  128. }
  129. /**
  130. * @see Blob#setBinaryStream(long)
  131. */
  132. public OutputStream setBinaryStream(long indexToWriteAt)
  133. throws SQLException {
  134. throw SQLError.notImplemented();
  135. }
  136. /**
  137. * Retrieves the BLOB designated by this Blob instance as a stream.
  138. *
  139. * @return this BLOB represented as a binary stream of bytes.
  140. *
  141. * @throws SQLException
  142. * if a database error occurs
  143. */
  144. public java.io.InputStream getBinaryStream() throws SQLException {
  145. // TODO: Make fetch size configurable
  146. return new BufferedInputStream(new LocatorInputStream(),
  147. this.creatorResultSet.connection.getLocatorFetchBufferSize());
  148. }
  149. /**
  150. * @see Blob#setBytes(long, byte[], int, int)
  151. */
  152. public int setBytes(long writeAt, byte[] bytes, int offset, int length)
  153. throws SQLException {
  154. java.sql.PreparedStatement pStmt = null;
  155. if ((offset + length) > bytes.length) {
  156. length = bytes.length - offset;
  157. }
  158. byte[] bytesToWrite = new byte[length];
  159. System.arraycopy(bytes, offset, bytesToWrite, 0, length);
  160. // FIXME: Needs to use identifiers for column/table names
  161. StringBuffer query = new StringBuffer("UPDATE ");
  162. query.append(this.tableName);
  163. query.append(" SET ");
  164. query.append(this.blobColumnName);
  165. query.append(" = INSERT(");
  166. query.append(this.blobColumnName);
  167. query.append(", ");
  168. query.append(writeAt);
  169. query.append(", ");
  170. query.append(length);
  171. query.append(", ?) WHERE ");
  172. query.append((String) this.primaryKeyColumns.get(0));
  173. query.append(" = ?");
  174. for (int i = 1; i < this.numPrimaryKeys; i++) {
  175. query.append(" AND ");
  176. query.append((String) this.primaryKeyColumns.get(i));
  177. query.append(" = ?");
  178. }
  179. try {
  180. // FIXME: Have this passed in instead
  181. pStmt = this.creatorResultSet.connection.prepareStatement(query
  182. .toString());
  183. pStmt.setBytes(1, bytesToWrite);
  184. for (int i = 0; i < this.numPrimaryKeys; i++) {
  185. pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
  186. }
  187. int rowsUpdated = pStmt.executeUpdate();
  188. if (rowsUpdated != 1) {
  189. throw SQLError.createSQLException(
  190. "BLOB data not found! Did primary keys change?",
  191. SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  192. }
  193. } finally {
  194. if (pStmt != null) {
  195. try {
  196. pStmt.close();
  197. } catch (SQLException sqlEx) {
  198. ; // do nothing
  199. }
  200. pStmt = null;
  201. }
  202. }
  203. return (int) length();
  204. }
  205. /**
  206. * @see Blob#setBytes(long, byte[])
  207. */
  208. public int setBytes(long writeAt, byte[] bytes) throws SQLException {
  209. return setBytes(writeAt, bytes, 0, bytes.length);
  210. }
  211. /**
  212. * Returns as an array of bytes, part or all of the BLOB value that this
  213. * Blob object designates.
  214. *
  215. * @param pos
  216. * where to start the part of the BLOB
  217. * @param length
  218. * the length of the part of the BLOB you want returned.
  219. *
  220. * @return the bytes stored in the blob starting at position
  221. * <code>pos</code> and having a length of <code>length</code>.
  222. *
  223. * @throws SQLException
  224. * if a database error occurs
  225. */
  226. public byte[] getBytes(long pos, int length) throws SQLException {
  227. java.sql.PreparedStatement pStmt = null;
  228. try {
  229. pStmt = createGetBytesStatement();
  230. return getBytesInternal(pStmt, pos, length);
  231. } finally {
  232. if (pStmt != null) {
  233. try {
  234. pStmt.close();
  235. } catch (SQLException sqlEx) {
  236. ; // do nothing
  237. }
  238. pStmt = null;
  239. }
  240. }
  241. }
  242. /**
  243. * Returns the number of bytes in the BLOB value designated by this Blob
  244. * object.
  245. *
  246. * @return the length of this blob
  247. *
  248. * @throws SQLException
  249. * if a database error occurs
  250. */
  251. public long length() throws SQLException {
  252. java.sql.ResultSet blobRs = null;
  253. java.sql.PreparedStatement pStmt = null;
  254. // FIXME: Needs to use identifiers for column/table names
  255. StringBuffer query = new StringBuffer("SELECT LENGTH(");
  256. query.append(this.blobColumnName);
  257. query.append(") FROM ");
  258. query.append(this.tableName);
  259. query.append(" WHERE ");
  260. query.append((String) this.primaryKeyColumns.get(0));
  261. query.append(" = ?");
  262. for (int i = 1; i < this.numPrimaryKeys; i++) {
  263. query.append(" AND ");
  264. query.append((String) this.primaryKeyColumns.get(i));
  265. query.append(" = ?");
  266. }
  267. try {
  268. // FIXME: Have this passed in instead
  269. pStmt = this.creatorResultSet.connection.prepareStatement(query
  270. .toString());
  271. for (int i = 0; i < this.numPrimaryKeys; i++) {
  272. pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
  273. }
  274. blobRs = pStmt.executeQuery();
  275. if (blobRs.next()) {
  276. return blobRs.getLong(1);
  277. }
  278. throw SQLError.createSQLException(
  279. "BLOB data not found! Did primary keys change?",
  280. SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  281. } finally {
  282. if (blobRs != null) {
  283. try {
  284. blobRs.close();
  285. } catch (SQLException sqlEx) {
  286. ; // do nothing
  287. }
  288. blobRs = null;
  289. }
  290. if (pStmt != null) {
  291. try {
  292. pStmt.close();
  293. } catch (SQLException sqlEx) {
  294. ; // do nothing
  295. }
  296. pStmt = null;
  297. }
  298. }
  299. }
  300. /**
  301. * Finds the position of the given pattern in this BLOB.
  302. *
  303. * @param pattern
  304. * the pattern to find
  305. * @param start
  306. * where to start finding the pattern
  307. *
  308. * @return the position where the pattern is found in the BLOB, -1 if not
  309. * found
  310. *
  311. * @throws SQLException
  312. * if a database error occurs
  313. */
  314. public long position(java.sql.Blob pattern, long start) throws SQLException {
  315. return position(pattern.getBytes(0, (int) pattern.length()), start);
  316. }
  317. /**
  318. * @see java.sql.Blob#position(byte[], long)
  319. */
  320. public long position(byte[] pattern, long start) throws SQLException {
  321. java.sql.ResultSet blobRs = null;
  322. java.sql.PreparedStatement pStmt = null;
  323. // FIXME: Needs to use identifiers for column/table names
  324. StringBuffer query = new StringBuffer("SELECT LOCATE(");
  325. query.append("?, ");
  326. query.append(this.blobColumnName);
  327. query.append(", ");
  328. query.append(start);
  329. query.append(") FROM ");
  330. query.append(this.tableName);
  331. query.append(" WHERE ");
  332. query.append((String) this.primaryKeyColumns.get(0));
  333. query.append(" = ?");
  334. for (int i = 1; i < this.numPrimaryKeys; i++) {
  335. query.append(" AND ");
  336. query.append((String) this.primaryKeyColumns.get(i));
  337. query.append(" = ?");
  338. }
  339. try {
  340. // FIXME: Have this passed in instead
  341. pStmt = this.creatorResultSet.connection.prepareStatement(query
  342. .toString());
  343. pStmt.setBytes(1, pattern);
  344. for (int i = 0; i < this.numPrimaryKeys; i++) {
  345. pStmt.setString(i + 2, (String) this.primaryKeyValues.get(i));
  346. }
  347. blobRs = pStmt.executeQuery();
  348. if (blobRs.next()) {
  349. return blobRs.getLong(1);
  350. }
  351. throw SQLError.createSQLException(
  352. "BLOB data not found! Did primary keys change?",
  353. SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  354. } finally {
  355. if (blobRs != null) {
  356. try {
  357. blobRs.close();
  358. } catch (SQLException sqlEx) {
  359. ; // do nothing
  360. }
  361. blobRs = null;
  362. }
  363. if (pStmt != null) {
  364. try {
  365. pStmt.close();
  366. } catch (SQLException sqlEx) {
  367. ; // do nothing
  368. }
  369. pStmt = null;
  370. }
  371. }
  372. }
  373. /**
  374. * @see Blob#truncate(long)
  375. */
  376. public void truncate(long length) throws SQLException {
  377. java.sql.PreparedStatement pStmt = null;
  378. // FIXME: Needs to use identifiers for column/table names
  379. StringBuffer query = new StringBuffer("UPDATE ");
  380. query.append(this.tableName);
  381. query.append(" SET ");
  382. query.append(this.blobColumnName);
  383. query.append(" = LEFT(");
  384. query.append(this.blobColumnName);
  385. query.append(", ");
  386. query.append(length);
  387. query.append(") WHERE ");
  388. query.append((String) this.primaryKeyColumns.get(0));
  389. query.append(" = ?");
  390. for (int i = 1; i < this.numPrimaryKeys; i++) {
  391. query.append(" AND ");
  392. query.append((String) this.primaryKeyColumns.get(i));
  393. query.append(" = ?");
  394. }
  395. try {
  396. // FIXME: Have this passed in instead
  397. pStmt = this.creatorResultSet.connection.prepareStatement(query
  398. .toString());
  399. for (int i = 0; i < this.numPrimaryKeys; i++) {
  400. pStmt.setString(i + 1, (String) this.primaryKeyValues.get(i));
  401. }
  402. int rowsUpdated = pStmt.executeUpdate();
  403. if (rowsUpdated != 1) {
  404. throw SQLError.createSQLException(
  405. "BLOB data not found! Did primary keys change?",
  406. SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  407. }
  408. } finally {
  409. if (pStmt != null) {
  410. try {
  411. pStmt.close();
  412. } catch (SQLException sqlEx) {
  413. ; // do nothing
  414. }
  415. pStmt = null;
  416. }
  417. }
  418. }
  419. java.sql.PreparedStatement createGetBytesStatement() throws SQLException {
  420. StringBuffer query = new StringBuffer("SELECT SUBSTRING(");
  421. query.append(this.blobColumnName);
  422. query.append(", ");
  423. query.append("?");
  424. query.append(", ");
  425. query.append("?");
  426. query.append(") FROM ");
  427. query.append(this.tableName);
  428. query.append(" WHERE ");
  429. query.append((String) this.primaryKeyColumns.get(0));
  430. query.append(" = ?");
  431. for (int i = 1; i < this.numPrimaryKeys; i++) {
  432. query.append(" AND ");
  433. query.append((String) this.primaryKeyColumns.get(i));
  434. query.append(" = ?");
  435. }
  436. return this.creatorResultSet.connection.prepareStatement(query
  437. .toString());
  438. }
  439. byte[] getBytesInternal(java.sql.PreparedStatement pStmt, long pos,
  440. int length) throws SQLException {
  441. java.sql.ResultSet blobRs = null;
  442. try {
  443. pStmt.setLong(1, pos);
  444. pStmt.setInt(2, length);
  445. for (int i = 0; i < this.numPrimaryKeys; i++) {
  446. pStmt.setString(i + 3, (String) this.primaryKeyValues.get(i));
  447. }
  448. blobRs = pStmt.executeQuery();
  449. if (blobRs.next()) {
  450. return ((com.mysql.jdbc.ResultSetImpl) blobRs).getBytes(1, true);
  451. }
  452. throw SQLError.createSQLException(
  453. "BLOB data not found! Did primary keys change?",
  454. SQLError.SQL_STATE_GENERAL_ERROR, this.exceptionInterceptor);
  455. } finally {
  456. if (blobRs != null) {
  457. try {
  458. blobRs.close();
  459. } catch (SQLException sqlEx) {
  460. ; // do nothing
  461. }
  462. blobRs = null;
  463. }
  464. }
  465. }
  466. class LocatorInputStream extends InputStream {
  467. long currentPositionInBlob = 0;
  468. long length = 0;
  469. java.sql.PreparedStatement pStmt = null;
  470. LocatorInputStream() throws SQLException {
  471. length = length();
  472. pStmt = createGetBytesStatement();
  473. }
  474. LocatorInputStream(long pos, long len) throws SQLException {
  475. length = pos + len;
  476. currentPositionInBlob = pos;
  477. long blobLength = length();
  478. if (pos + len > blobLength) {
  479. throw SQLError.createSQLException(
  480. Messages.getString("Blob.invalidStreamLength",
  481. new Object[] {new Long(blobLength), new Long(pos), new Long(len)}),
  482. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
  483. }
  484. if (pos < 1) {
  485. throw SQLError.createSQLException(Messages.getString("Blob.invalidStreamPos"),
  486. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
  487. }
  488. if (pos > blobLength) {
  489. throw SQLError.createSQLException(Messages.getString("Blob.invalidStreamPos"),
  490. SQLError.SQL_STATE_ILLEGAL_ARGUMENT, exceptionInterceptor);
  491. }
  492. }
  493. public int read() throws IOException {
  494. if (currentPositionInBlob + 1 > length) {
  495. return -1;
  496. }
  497. try {
  498. byte[] asBytes = getBytesInternal(pStmt,
  499. (currentPositionInBlob++) + 1, 1);
  500. if (asBytes == null) {
  501. return -1;
  502. }
  503. return asBytes[0];
  504. } catch (SQLException sqlEx) {
  505. throw new IOException(sqlEx.toString());
  506. }
  507. }
  508. /*
  509. * (non-Javadoc)
  510. *
  511. * @see java.io.InputStream#read(byte[], int, int)
  512. */
  513. public int read(byte[] b, int off, int len) throws IOException {
  514. if (currentPositionInBlob + 1 > length) {
  515. return -1;
  516. }
  517. try {
  518. byte[] asBytes = getBytesInternal(pStmt,
  519. (currentPositionInBlob) + 1, len);
  520. if (asBytes == null) {
  521. return -1;
  522. }
  523. System.arraycopy(asBytes, 0, b, off, asBytes.length);
  524. currentPositionInBlob += asBytes.length;
  525. return asBytes.length;
  526. } catch (SQLException sqlEx) {
  527. throw new IOException(sqlEx.toString());
  528. }
  529. }
  530. /*
  531. * (non-Javadoc)
  532. *
  533. * @see java.io.InputStream#read(byte[])
  534. */
  535. public int read(byte[] b) throws IOException {
  536. if (currentPositionInBlob + 1 > length) {
  537. return -1;
  538. }
  539. try {
  540. byte[] asBytes = getBytesInternal(pStmt,
  541. (currentPositionInBlob) + 1, b.length);
  542. if (asBytes == null) {
  543. return -1;
  544. }
  545. System.arraycopy(asBytes, 0, b, 0, asBytes.length);
  546. currentPositionInBlob += asBytes.length;
  547. return asBytes.length;
  548. } catch (SQLException sqlEx) {
  549. throw new IOException(sqlEx.toString());
  550. }
  551. }
  552. /*
  553. * (non-Javadoc)
  554. *
  555. * @see java.io.InputStream#close()
  556. */
  557. public void close() throws IOException {
  558. if (pStmt != null) {
  559. try {
  560. pStmt.close();
  561. } catch (SQLException sqlEx) {
  562. throw new IOException(sqlEx.toString());
  563. }
  564. }
  565. super.close();
  566. }
  567. }
  568. public void free() throws SQLException {
  569. this.creatorResultSet = null;
  570. this.primaryKeyColumns = null;
  571. this.primaryKeyValues = null;
  572. }
  573. public InputStream getBinaryStream(long pos, long length) throws SQLException {
  574. return new LocatorInputStream(pos, length);
  575. }
  576. }