Skip to content

Commit

Permalink
[jdbc-driver] Support for binary types (BLOB, byte array, input stream)
Browse files Browse the repository at this point in the history
  • Loading branch information
cchantep committed Aug 12, 2014
1 parent 43257c1 commit 194d549
Show file tree
Hide file tree
Showing 14 changed files with 1,126 additions and 99 deletions.
297 changes: 297 additions & 0 deletions jdbc-driver/src/main/java/acolyte/jdbc/Blob.java
@@ -0,0 +1,297 @@
package acolyte.jdbc;

import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.io.InputStream;

import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLException;

import javax.sql.rowset.serial.SerialBlob;

/**
* Binary large object.
*
* @author Cedric Chantepie
*/
final class Blob implements java.sql.Blob {
// --- Shared ---

/**
* Empty data
*/
private static final byte[] NO_BYTE = new byte[0];

/**
* Empty stream
*/
private static final ByteArrayInputStream NO_DATA =
new ByteArrayInputStream(NO_BYTE);

// --- Properties ---

/**
* Underlying blob
*/
private java.sql.Blob underlying = null;

// --- Constructors ---

/**
* No-arg constructor.
*/
private Blob() throws SQLException { }

/**
* Bulk constructor.
*/
public Blob(final byte[] bytes) throws SQLException {
this.underlying = new SerialBlob(bytes);
} // end of <init>

/**
* Returns nil BLOB.
*/
public static Blob Nil() throws SQLException { return new Blob(); }

// --- Blob implementation ---

/**
* {@inheritDoc}
*/
public void free() throws SQLException {
synchronized (this) {
if (this.underlying == null) return;

// ---

this.underlying.free();
} // end of sync
} // end of free

/**
* {@inheritDoc}
*/
public InputStream getBinaryStream() throws SQLException {
synchronized (this) {
if (this.underlying == null) return NO_DATA;

// ---

return this.underlying.getBinaryStream();
} // end of sync
} // end of getBinaryStream

/**
* {@inheritDoc}
*/
public InputStream getBinaryStream(final long pos, final long length)
throws SQLException {

synchronized (this) {
if (this.underlying == null) {
if (pos > 1) {
throw new SQLException("Invalid position: " + pos);
} // end of if

return NO_DATA;
} // end of if

// ---

return this.underlying.getBinaryStream(pos, length);
} // end of sync
} // end of getBinaryStream

/**
* {@inheritDoc}
*/
public byte[] getBytes(final long pos, final int length)
throws SQLException {

synchronized (this) {
if (this.underlying == null) {
if (pos > 1) {
throw new SQLException("Invalid position: " + pos);
} // end of if

return NO_BYTE;
} // end of if

// ---

return this.underlying.getBytes(pos, length);
} // end of sync
} // end of getBytes

/**
* {@inheritDoc}
*/
public long length() throws SQLException {
synchronized (this) {
if (this.underlying == null) {
return 0L;
} // end of if

return this.underlying.length();
} // end of sync
} // end of length

/**
* {@inheritDoc}
*/
public long position(final java.sql.Blob pattern, final long start)
throws SQLException {

synchronized (this) {
if (this.underlying == null) {
if (start > 1) {
throw new SQLException("Invalid offset: " + start);
} // end of if

return -1L;
} // end of if

return this.underlying.position(pattern, start);
} // end of sync
} // end of position

/**
* {@inheritDoc}
*/
public long position(final byte[] pattern, final long start)
throws SQLException {

synchronized (this) {
if (this.underlying == null) {
if (start > 1) {
throw new SQLException("Invalid offset: " + start);
} // end of if

return -1L;
} // end of if

return this.underlying.position(pattern, start);
} // end of sync
} // end of position

/**
* {@inheritDoc}
* @throw SQLFeatureNotSupportedException if this BLOB is empty
*/
public OutputStream setBinaryStream(final long pos) throws SQLException {
synchronized (this) {
if (this.underlying == null) {
if (pos > 1) {
throw new SQLException("Invalid position: " + pos);
} // end of if

throw new SQLFeatureNotSupportedException("Cannot write to empty BLOB");
} // end of if

// ---

return this.underlying.setBinaryStream(pos);
} // end of sync
} // end of setBinaryStream

/**
* {@inheritDoc}
* @see #setBytes(long, bytes[], offset, int)
*/
public int setBytes(final long pos, byte[] bytes) throws SQLException {
if (bytes == null) {
throw new IllegalArgumentException("No byte to be set");
} // end of if

return setBytes(pos, bytes, 0, bytes.length);
} // end of setBytes

/**
* {@inheritDoc}
*/
public int setBytes(final long pos, byte[] bytes,
final int offset, final int len) throws SQLException {

synchronized (this) {
if (this.underlying == null) {
if (pos > 1) {
throw new SQLException("Invalid position: " + pos);
} // end of if

if (len < 0) {
throw new IllegalArgumentException("Invalid bytes length: "
+ len);

} // end of if

// ---

final byte[] copy = new byte[len];

try {
System.arraycopy(bytes, offset, copy, 0, len);
} catch (Exception e) {
throw new IllegalArgumentException("Fails to prepare binary data", e);
} // end of catch

// ---

this.underlying = new SerialBlob(copy);

return len;
} // end of if

// ---

return this.underlying.setBytes(pos, bytes, offset, len);
} // end of sync
} // end of setBytes

/**
* {@inheritDoc}
*/
public void truncate(final long len) throws SQLException {
synchronized (this) {
if (this.underlying == null) {
if (len < 0) {
throw new SQLException("Invalid length: " + len);
} // end of if

return;
} // end of if

// ---

this.underlying.truncate(len);
} // end of truncate
} // end of truncate

// --- Object support ---

/**
* {@inheritDoc}
*/
public boolean equals(Object o) {
if (o == null || !(o instanceof Blob)) {
return false;
} // end of if

// ---

final Blob other = (Blob) o;

return ((this.underlying == null && other.underlying == null) ||
(this.underlying != null &&
this.underlying.equals(other.underlying)));

} // end of equals

/**
* {@inheritDoc}
*/
public int hashCode() {
return (this.underlying == null) ? 3 : this.underlying.hashCode();
} // end of hashCode
} // end of class Blob
13 changes: 10 additions & 3 deletions jdbc-driver/src/main/java/acolyte/jdbc/Connection.java
Expand Up @@ -28,7 +28,7 @@
*
* @author Cedric Chantepie
*/
public final class Connection implements java.sql.Connection {
public class Connection implements java.sql.Connection {
// --- Properties ---

/**
Expand Down Expand Up @@ -578,10 +578,17 @@ public Clob createClob() throws SQLException {

/**
* {@inheritDoc}
* @throws java.sql.SQLFeatureNotSupportedException
* @see #createBlob(byte[])
*/
public Blob createBlob() throws SQLException {
throw new SQLFeatureNotSupportedException();
return acolyte.jdbc.Blob.Nil();
} // end of createBlob

/**
* Returns a BLOB with given |data|.
*/
public Blob createBlob(final byte[] data) throws SQLException {
return new javax.sql.rowset.serial.SerialBlob(data);
} // end of createBlob

/**
Expand Down

0 comments on commit 194d549

Please sign in to comment.