You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2006/05/17 03:09:11 UTC
svn commit: r407116 - in /db/derby/code/trunk/java:
client/org/apache/derby/client/am/ engine/org/apache/derby/impl/jdbc/
engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/reference/
testing/org/apache/derbyTesting/functionTests/tests/...
Author: rhillegas
Date: Tue May 16 18:09:10 2006
New Revision: 407116
URL: http://svn.apache.org/viewcvs?rev=407116&view=rev
Log:
DERBY-1328: Commit Narayanan's ClobBlob_free_v1.diff patch, implementing the LOB free() method introduced by JDBC4.
Modified:
db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java
db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java
Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Blob.java Tue May 16 18:09:10 2006
@@ -20,12 +20,17 @@
package org.apache.derby.client.am;
+import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
-
import org.apache.derby.shared.common.reference.SQLState;
public class Blob extends Lob implements java.sql.Blob {
+
+ //This boolean variable indicates whether the Blob object has
+ //been invalidated by calling free() on it
+ private boolean isValid = true;
+
//-----------------------------state------------------------------------------
byte[] binaryString_ = null;
@@ -62,6 +67,9 @@
// ---------------------------jdbc 2------------------------------------------
public long length() throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -84,6 +92,9 @@
// can return an array that may be have a length shorter than the supplied
// length (no padding occurs)
public byte[] getBytes(long pos, int length) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -131,6 +142,9 @@
public java.io.InputStream getBinaryStream() throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -162,6 +176,9 @@
}
public long position(byte[] pattern, long start) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -192,6 +209,9 @@
}
public long position(java.sql.Blob pattern, long start) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -229,6 +249,9 @@
public int setBytes(long pos, byte[] bytes) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -249,6 +272,9 @@
}
public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -325,6 +351,9 @@
}
public java.io.OutputStream setBinaryStream(long pos) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
synchronized (agent_.connection_) {
if (agent_.loggingEnabled()) {
agent_.logWriter_.traceEntry(this, "setBinaryStream", (int) pos);
@@ -339,6 +368,9 @@
}
public void truncate(long len) throws SQLException {
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
try
{
synchronized (agent_.connection_) {
@@ -368,10 +400,37 @@
}
// -------------------------- JDBC 4.0 -----------------------------------
-
+
+ /**
+ * This method frees the <code>Blob</code> object and releases the resources that
+ * it holds. The object is invalid once the <code>free</code>
+ * method is called. If <code>free</code> is called multiple times, the subsequent
+ * calls to <code>free</code> are treated as a no-op.
+ *
+ * @throws SQLException if an error occurs releasing
+ * the Blob's resources
+ */
public void free()
throws SQLException {
- throw SQLExceptionFactory.notImplemented("free()");
+
+ //calling free() on a already freed object is treated as a no-op
+ if (!isValid) return;
+
+ //now that free has been called the Blob object is no longer
+ //valid
+ isValid = false;
+
+ if(isBinaryStream()) {
+ try {
+ binaryStream_.close();
+ }
+ catch(IOException ioe) {
+ throw new SqlException(null, new ClientMessageId(SQLState.IO_ERROR_UPON_LOB_FREE)).getSQLException();
+ }
+ }
+ else {
+ binaryString_ = null;
+ }
}
public InputStream getBinaryStream(long pos, long length)
@@ -417,5 +476,18 @@
}
return true;
+ }
+
+ /*
+ * Checks is isValid is true. If it is not true throws
+ * a SQLException stating that a method has been called on
+ * an invalid LOB object
+ *
+ * throws SQLException if isvalid is not true.
+ */
+ private void checkValidity() throws SQLException{
+ if(!isValid)
+ throw new SqlException(null,new ClientMessageId(SQLState.LOB_OBJECT_INVALID))
+ .getSQLException();
}
}
Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/Clob.java Tue May 16 18:09:10 2006
@@ -20,9 +20,9 @@
package org.apache.derby.client.am;
+import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
-
import org.apache.derby.shared.common.reference.SQLState;
public class Clob extends Lob implements java.sql.Clob {
@@ -47,6 +47,10 @@
private PreparedStatement internalLengthStmt_ = null;
protected String encoding_ = "UNICODE";
+
+ //This boolean variable indicates whether the Clob object has
+ //been invalidated by calling free() on it
+ private boolean isValid = true;
//---------------------constructors/finalizer---------------------------------
public Clob(Agent agent, String string) {
@@ -144,6 +148,11 @@
// ---------------------------jdbc 2------------------------------------------
// Create another method lengthX for internal calls
public long length() throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -170,6 +179,11 @@
}
public String getSubString(long pos, int length) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -221,6 +235,11 @@
}
public java.io.Reader getCharacterStream() throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -253,6 +272,11 @@
}
public java.io.InputStream getAsciiStream() throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -285,6 +309,11 @@
}
public long position(String searchstr, long start) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -330,6 +359,11 @@
}
public long position(java.sql.Clob searchstr, long start) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -385,6 +419,11 @@
//---------------------------- jdbc 3.0 -----------------------------------
public int setString(long pos, String str) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -405,6 +444,11 @@
}
public int setString(long pos, String str, int offset, int len) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -463,6 +507,11 @@
}
public java.io.OutputStream setAsciiStream(long pos) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -484,6 +533,11 @@
}
public java.io.Writer setCharacterStream(long pos) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -505,6 +559,11 @@
}
public void truncate(long len) throws SQLException {
+
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
try
{
synchronized (agent_.connection_) {
@@ -541,10 +600,64 @@
}
//---------------------------- jdbc 4.0 -------------------------------------
-
+ /**
+ * This method frees the <code>Clob</code> object and releases the resources the resources
+ * that it holds. The object is invalid once the <code>free</code> method
+ * is called. If <code>free</code> is called multiple times, the
+ * subsequent calls to <code>free</code> are treated as a no-op.
+ *
+ * @throws SQLException if an error occurs releasing
+ * the Clob's resources
+ */
public void free()
throws SQLException {
- throw SQLExceptionFactory.notImplemented("free()");
+
+ //calling free() on a already freed object is treated as a no-op
+ if (!isValid) return;
+
+ //now that free has been called the Blob object is no longer
+ //valid
+ isValid = false;
+
+ if(isString()) {
+ string_ = null;
+ utf8String_ = null;
+ }
+ if(isAsciiStream()) {
+ try {
+ asciiStream_.close();
+ }
+ catch(IOException ioe) {
+ throw new SqlException(null, new ClientMessageId(SQLState.IO_ERROR_UPON_LOB_FREE)).getSQLException();
+ }
+ }
+ if(isUnicodeStream()) {
+ try {
+ unicodeStream_.close();
+ }
+ catch(IOException ioe) {
+ throw new SqlException(null, new ClientMessageId(SQLState.IO_ERROR_UPON_LOB_FREE)).getSQLException();
+ }
+ }
+ if(isCharacterStream()) {
+ try {
+ characterStream_.close();
+ }
+ catch(IOException ioe) {
+ throw new SqlException(null, new ClientMessageId(SQLState.IO_ERROR_UPON_LOB_FREE)).getSQLException();
+ }
+ }
+
+ lengthInBytes_ = 0;
+
+ if (internalLengthStmt_ != null) {
+ try {
+ internalLengthStmt_.closeX();
+ }
+ catch(SqlException sqle) {
+ throw sqle.getSQLException();
+ }
+ }
}
public Reader getCharacterStream(long pos, long length)
@@ -647,5 +760,18 @@
length();
return lengthInBytes_;
+ }
+
+ /*
+ * Checks is isValid is true. If it is not true throws
+ * a SQLException stating that a method has been called on
+ * an invalid LOB object
+ *
+ * throws SQLException if isvalid is not true.
+ */
+ private void checkValidity() throws SQLException{
+ if(!isValid)
+ throw new SqlException(null,new ClientMessageId(SQLState.LOB_OBJECT_INVALID))
+ .getSQLException();
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedBlob.java Tue May 16 18:09:10 2006
@@ -73,6 +73,7 @@
// blob is either bytes or stream
private boolean isBytes;
private InputStream myStream;
+
/*
* Length of the BLOB if known. Set to -1 if
* the current length of the BLOB is not known.
@@ -89,6 +90,10 @@
// and trashing them (to set the position of the stream etc.)
private static int BLOB_BUF_SIZE = 4096;
private byte buf[];
+
+ //This boolean variable indicates whether the Blob object has
+ //been invalidated by calling free() on it
+ private boolean isValid = true;
/*
This constructor should only be called by EmbedResultSet.getBlob
@@ -215,6 +220,10 @@
public long length()
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
+
if (myLength != -1)
return myLength;
@@ -284,6 +293,10 @@
public byte[] getBytes(long startPos, int length)
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -369,6 +382,10 @@
public java.io.InputStream getBinaryStream()
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -420,6 +437,10 @@
public long position(byte[] pattern, long start)
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -515,6 +536,10 @@
public long position(Blob pattern, long start)
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Blob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -744,10 +769,34 @@
// JDBC 4.0 - New public methods
//
/////////////////////////////////////////////////////////////////////////
-
+ /**
+ * This method frees the <code>Blob</code> object and releases the resources that
+ * it holds. The object is invalid once the <code>free</code>
+ * method is called. If <code>free</code> is called multiple times, the subsequent
+ * calls to <code>free</code> are treated as a no-op.
+ *
+ * @throws SQLException if an error occurs releasing
+ * the Blob's resources
+ */
public void free()
throws SQLException {
- throw Util.notImplemented();
+ //calling free() on a already freed object is treated as a no-op
+ if (!isValid) return;
+
+ //now that free has been called the Blob object is no longer
+ //valid
+ isValid = false;
+
+ //initialialize length to default value -1
+ myLength = -1;
+
+ //if it is a stream then close it.
+ //if a array of bytes then initialize it to null
+ //to free up space
+ if (!isBytes)
+ ((Resetable)myStream).closeStream();
+ else
+ myBytes = null;
}
/**
@@ -767,5 +816,17 @@
public InputStream getBinaryStream(long pos, long length)
throws SQLException {
throw Util.notImplemented();
+ }
+
+ /*
+ * Checks is isValid is true. If it is not true throws
+ * a SQLException stating that a method has been called on
+ * an invalid LOB object
+ *
+ * throws SQLException if isvalid is not true.
+ */
+ private void checkValidity() throws SQLException{
+ if(!isValid)
+ throw newSQLException(SQLState.LOB_OBJECT_INVALID);
}
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedClob.java Tue May 16 18:09:10 2006
@@ -74,6 +74,10 @@
private boolean isString;
private InputStream myStream;
private String myString;
+
+ //This boolean variable indicates whether the Clob object has
+ //been invalidated by calling free() on it
+ private boolean isValid = true;
/*
This constructor should only be called by EmbedResultSet.getClob
@@ -136,6 +140,9 @@
public long length() throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
// if we have a string, not a stream
if (isString)
return myString.length();
@@ -199,6 +206,10 @@
public String getSubString(long pos, int length) throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
if (pos < 1)
throw Util.generateCsSQLException(
SQLState.BLOB_BAD_POSITION, new Long(pos));
@@ -268,6 +279,9 @@
public java.io.Reader getCharacterStream() throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
// if we have a string, not a stream
if (isString)
@@ -306,6 +320,9 @@
public java.io.InputStream getAsciiStream() throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
return new ReaderToAscii(getCharacterStream());
}
@@ -344,6 +361,10 @@
public long position(String searchStr, long start)
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -583,6 +604,10 @@
public long position(Clob searchClob, long start)
throws SQLException
{
+ //call checkValidity to exit by throwing a SQLException if
+ //the Clob object has been freed by calling free() on it
+ checkValidity();
+
boolean pushStack = false;
try
{
@@ -745,7 +770,7 @@
public java.io.OutputStream setAsciiStream(long pos)
throws SQLException
{
- throw Util.notImplemented();
+ throw Util.notImplemented();
}
/**
@@ -784,10 +809,28 @@
// JDBC 4.0 - New public methods
//
/////////////////////////////////////////////////////////////////////////
-
+ /**
+ * This method frees the <code>Clob</code> object and releases the resources the resources
+ * that it holds. The object is invalid once the <code>free</code> method
+ * is called. If <code>free</code> is called multiple times, the
+ * subsequent calls to <code>free</code> are treated as a no-op.
+ *
+ * @throws SQLException if an error occurs releasing
+ * the Clob's resources
+ */
public void free()
throws SQLException {
- throw Util.notImplemented();
+ //calling free() on a already freed object is treated as a no-op
+ if (!isValid) return;
+
+ //now that free has been called the Clob object is no longer
+ //valid
+ isValid = false;
+
+ if (!isString)
+ ((Resetable)myStream).closeStream();
+ else
+ myString = null;
}
public java.io.Reader getCharacterStream(long pos, long length)
@@ -810,5 +853,16 @@
}
return org.apache.derby.impl.jdbc.EmbedResultSet.noStateChangeException(t);
}
-
+
+ /*
+ * Checks is isValid is true. If it is not true throws
+ * a SQLException stating that a method has been called on
+ * an invalid LOB object
+ *
+ * throws SQLException if isValid is not true.
+ */
+ private void checkValidity() throws SQLException{
+ if(!isValid)
+ throw newSQLException(SQLState.LOB_OBJECT_INVALID);
+ }
}
Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties Tue May 16 18:09:10 2006
@@ -1215,6 +1215,8 @@
XJ211.S=Non-recoverable chain-breaking exception occurred during batch processing. The batch is terminated non-atomically.
XJ212.S=Invalid attribute syntax: {0}
XJ213.C=The traceLevel connection property does not have a valid format for a number.
+XJ214.S=An IO Error occurred when calling free() on a CLOB or BLOB.
+XJ215.S=You cannot invoke other Clob/Blob methods after calling free.
#XN - Network level messages
XN001.S=Connection reset is not allowed when inside a unit of work.
Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Tue May 16 18:09:10 2006
@@ -1511,6 +1511,8 @@
String BATCH_CHAIN_BREAKING_EXCEPTION = "XJ211.S";
String INVALID_ATTRIBUTE_SYNTAX = "XJ212.S";
String TRACELEVEL_FORMAT_INVALID = "XJ213.S";
+ String IO_ERROR_UPON_LOB_FREE = "XJ214.S";
+ String LOB_OBJECT_INVALID = "XJ215.S";
//XN - Network-level messages
String NET_CONNECTION_RESET_NOT_ALLOWED_IN_UNIT_OF_WORK = "XN001.S";
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/BlobTest.java Tue May 16 18:09:10 2006
@@ -25,6 +25,90 @@
import org.apache.derbyTesting.functionTests.util.BaseJDBCTestCase;
import java.sql.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+/* This class is used to store the details of the methods that
+ * throw a SQLFeatureNotSupportedException in the implementation
+ * of java.sql.Blob.
+ *
+ * It store the following information about the methods
+ *
+ * a) Name
+ * b) Method Parameters
+ * c) Whether the method is exempted in the Embedded Sever
+ * d) Whether the method is exempted in the NetworkClient
+ *
+ */
+class ExemptBlobMD {
+ // The Name of the method
+ private String methodName_;
+
+ // The parameters of the method
+ private Class [] params_;
+
+ //Whether it is exempted in the
+ //Client or the Embedded framework
+ private boolean isClientFramework_;
+ private boolean isEmbeddedFramework_;
+
+ /**
+ * The Constructor for the ExemptBlobMD class that
+ * initialized the object with the details of the
+ * methods that have been exempted
+ *
+ * @param methodName A String that contains the name of the method
+ * that has been exempted.
+ * @param params A array of Class that contains the parameters
+ * of the methods.
+ * @param isClientFramework true if the method is exempted in the
+ * Client framework.
+ * @param isEmbeddedFramework true if the method is exempted in the
+ * Embedded framework.
+ *
+ */
+ public ExemptBlobMD(String methodName,Class [] params,
+ boolean isClientFramework,
+ boolean isEmbeddedFramework) {
+ methodName_ = methodName;
+ params_ = params;
+ isClientFramework_ = isClientFramework;
+ isEmbeddedFramework_ = isEmbeddedFramework;
+ }
+
+ /**
+ *
+ * Returns the name of the method.
+ *
+ * @return A String containing the name of the method.
+ *
+ */
+ public String getMethodName() { return methodName_; }
+
+ /**
+ * Returns a array of Class containing the type of the parameters
+ * of this method.
+ *
+ * @return A array of Class containing the type of the parameters
+ * of the method.
+ */
+ public Class [] getParams() { return params_; }
+
+ /**
+ * Returns if the method is exempted from the Client Framework.
+ *
+ * @return true if the method is exempted from the Client Framework.
+ */
+ public boolean getIfClientFramework() { return isClientFramework_; }
+
+ /**
+ * Returns if the method is exempted from the Embedded Framework.
+ *
+ * @return true if the method is exempted from the Embedded Framework.
+ */
+ public boolean getIfEmbeddedFramework() { return isEmbeddedFramework_; }
+}
/*
* Tests of the JDBC 4.0 specific <code>Blob</code> methods.
@@ -37,6 +121,29 @@
/** Default connection used by the tests. */
private Connection con = null;
+ // Initialize with the details of the method that are exempted from
+ //throwing a SQLException when they are called after calling free()
+ //on a LOB.
+
+ private ExemptBlobMD [] emd = new ExemptBlobMD [] {
+ new ExemptBlobMD( "getBinaryStream", new Class[] { long.class,long.class }
+ ,true,true ),
+ new ExemptBlobMD( "setBinaryStream", new Class[] { long.class },false,true ),
+ new ExemptBlobMD( "setBytes", new Class[] { long.class, byte[].class }
+ ,false,true ),
+ new ExemptBlobMD( "setBytes", new Class[] { long.class, byte[].class
+ , int.class, int.class },false,true ),
+ new ExemptBlobMD( "truncate", new Class[] { long.class },false,true),
+ new ExemptBlobMD( "free",null,true,true)
+ };
+
+ // An HashMap that is indexed by the Method which facilitated easy
+ //search for whether the given method has been exempted from the
+ //LOB interface.
+
+ private HashMap<Method,ExemptBlobMD> excludedMethodSet =
+ new HashMap<Method,ExemptBlobMD>();
+
/**
* Create the test with the given name.
*
@@ -50,8 +157,14 @@
throws SQLException {
con = getConnection();
blob = BlobClobTestSetup.getSampleBlob(con);
+
+ //call the buildHashSetMethod to initialize the
+ //HashSet with the method signatures that are exempted
+ //from throwing a SQLException after free has been called
+ //on the Clob object.
+ buildHashSet();
}
-
+
public void tearDown()
throws SQLException {
blob = null;
@@ -61,16 +174,217 @@
}
con = null;
}
-
- public void testFreeNotImplemented()
+
+ /**
+ * Builds the HashSet which will be used to test whether the given methods
+ * can be exempted or not
+ */
+ void buildHashSet() {
+ Class iface = Blob.class;
+ for(int i=0;i<emd.length;i++) {
+ try {
+ Method m = iface.getMethod(emd[i].getMethodName()
+ ,emd[i].getParams());
+ excludedMethodSet.put(m,emd[i]);
+ }
+ catch(NoSuchMethodException nsme) {
+ fail("The method could not be found in the interface");
+ }
+ }
+ }
+
+ /**
+ * Tests the implementation for the free() method in the
+ * Blob interface.
+ *
+ * @throws SQLException if an error occurs during releasing
+ * the Blob resources
+ *
+ */
+ public void testFreeandMethodsAfterCallingFree()
throws SQLException {
+ blob.free();
+ //testing the idempotence of the free() method
+ //the method can be called multiple times on
+ //the same instance. subsequent calls after
+ //the first are treated as no-ops
+ blob.free();
+
+ //blob becomes invalid after the first call
+ //to the free method so testing calling
+ //a method on this invalid object should throw
+ //an SQLException
+ buildMethodList(blob);
+ }
+
+ /*
+ *
+ * Enumerate the methods of the Blob interface and
+ * get the list of methods present in the interface
+ * @param LOB an instance of the Blob interface implementation
+ */
+ void buildMethodList(Object LOB) {
+ //If the given method throws the correct exception
+ //set this to true and add it to the
+ boolean valid = true;
+
+ //create a list of the methods that fail the test
+ Vector<Method> methodList = new Vector<Method>();
+
+ //The class whose methods are to be verified
+ Class clazz = Blob.class;
+
+ //The list of the methods in the class that need to be invoked
+ //and verified
+ Method [] methods = clazz.getMethods();
+
+ //Check each of the methods to ensure that
+ //they throw the required exception
+ for(int i=0;i<methods.length;i++) {
+ if(!checkIfExempted(methods[i])) {
+ valid = checkIfMethodThrowsSQLException(LOB,methods[i]);
+
+ //add the method to the list if the method does
+ //not throw the required exception
+ if(valid == false) methodList.add(methods[i]);
+
+ //reset valid
+ valid = true;
+ }
+ }
+
+ if(!methodList.isEmpty()) {
+ int c=0;
+ String failureMessage = "The Following methods don't throw " +
+ "required exception - ";
+ for (Method m : methodList) {
+ c = c + 1;
+ if(c == methodList.size() && c != 1)
+ failureMessage += " & ";
+ else if(c != 1)
+ failureMessage += " , ";
+ failureMessage += m.getName();
+ }
+ fail(failureMessage);
+ }
+ }
+
+ /**
+ *Checks if the method throws a SQLFeatureNotSupportedException
+ *@param m The method object that needs to be verified to see if it
+ * is exempted
+ *@return true if the given method does not throw the required SQLException
+ *
+ */
+ boolean checkIfExempted(Method m) {
+ ExemptBlobMD md = excludedMethodSet.get(m);
+
+ if(md != null && usingDerbyNetClient()) {
+ if(md.getIfClientFramework())
+ return true;
+ else
+ return false;
+ }
+ if(md != null && usingEmbedded()) {
+ if(md.getIfEmbeddedFramework())
+ return true;
+ else
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Checks if the invocation of the method throws a SQLExceptio
+ * as expected.
+ * @param LOB the Object that implements the Blob interface
+ * @param method the method that needs to be tested to ensure
+ * that it throws the correct exception
+ * @return true If the method throws the SQLException required
+ * after the free method has been called on the
+ * LOB object
+ *
+ */
+ boolean checkIfMethodThrowsSQLException(Object LOB,Method method) {
try {
- blob.free();
- fail("Blob.free() should not be implemented");
- } catch (SQLFeatureNotSupportedException sfnse) {
- // Do nothing, we are fine
+ method.invoke(LOB,getNullValues(method.getParameterTypes()));
+ } catch(Throwable e) {
+ if(e instanceof InvocationTargetException) {
+ Throwable cause = e.getCause();
+ if (cause instanceof SQLException ) {
+ SQLException sqle = (SQLException)cause;
+ if(sqle.getSQLState().equals("XJ215"))
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Return a array of objects containing the default values for
+ * the objects passed in as parameters
+ *
+ * @param parameterTypes an array containing the types of the parameter
+ * to the method
+ * @return an array of Objects containing the null values for the
+ * parameter inputs
+ */
+
+ Object[] getNullValues(Class<?> [] params) {
+ Object[] args = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ args[i] = getNullValueForType(params[i]);
}
+ return args;
}
+
+ /*
+ * Returns the null value for the specific type
+ *
+ * @param type the type of the parameter for which the null
+ * value is required
+ * @return the null value for the specific type
+ *
+ */
+ Object getNullValueForType(Class type)
+ {
+ if (!type.isPrimitive()) {
+ return null;
+ }
+ if (type == Boolean.TYPE) {
+ return Boolean.FALSE;
+ }
+ if (type == Character.TYPE) {
+ return new Character((char) 0);
+ }
+ if (type == Byte.TYPE) {
+ return new Byte((byte) 0);
+ }
+ if (type == Short.TYPE) {
+ return new Short((short) 0);
+ }
+ if (type == Integer.TYPE) {
+ return new Integer(0);
+ }
+ if (type == Long.TYPE) {
+ return new Long(0L);
+ }
+ if (type == Float.TYPE) {
+ return new Float(0f);
+ }
+ if (type == Double.TYPE) {
+ return new Double(0d);
+ }
+ fail("Don't know how to handle type " + type);
+ return null; // unreachable statement
+ }
+
public void testGetBinaryStringLongNotImplemented()
throws SQLException {
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java?rev=407116&r1=407115&r2=407116&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/ClobTest.java Tue May 16 18:09:10 2006
@@ -26,6 +26,90 @@
import org.apache.derbyTesting.functionTests.util.BaseJDBCTestCase;
import java.sql.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+/* This class is used to store the details of the methods that
+ * throw a SQLFeatureNotSupportedException in the implementation
+ * of java.sql.Clob.
+ *
+ * It store the following information about the methods
+ *
+ * a) Name
+ * b) Method Parameters
+ * c) Whether the method is exempted in the Embedded Sever
+ * d) Whether the method is exempted in the NetworkClient
+ *
+ */
+class ExemptClobMD {
+ // The Name of the method
+ private String methodName_;
+
+ // The parameters of the method
+ private Class [] params_;
+
+ //Whether it is exempted in the
+ //Client or the Embedded framework
+ private boolean isClientFramework_;
+ private boolean isEmbeddedFramework_;
+
+ /**
+ * The Constructor for the ExemptClobMD class that
+ * initialized the object with the details of the
+ * methods that have been exempted
+ *
+ * @param methodName A String that contains the name of the method
+ * that has been exempted.
+ * @param params A array of Class that contains the parameters
+ * of the methods.
+ * @param isClientFramework true if the method is exempted in the
+ * Client framework.
+ * @param isEmbeddedFramework true if the method is exempted in the
+ * Embedded framework.
+ *
+ */
+ public ExemptClobMD(String methodName,Class [] params,
+ boolean isClientFramework,
+ boolean isEmbeddedFramework) {
+ methodName_ = methodName;
+ params_ = params;
+ isClientFramework_ = isClientFramework;
+ isEmbeddedFramework_ = isEmbeddedFramework;
+ }
+
+ /**
+ *
+ * Returns the name of the method.
+ *
+ * @return A String containing the name of the method.
+ *
+ */
+ public String getMethodName() { return methodName_; }
+
+ /**
+ * Returns a array of Class containing the type of the parameters
+ * of this method.
+ *
+ * @return A array of Class containing the type of the parameters
+ * of the method.
+ */
+ public Class [] getParams() { return params_; }
+
+ /**
+ * Returns if the method is exempted from the Client Framework.
+ *
+ * @return true if the method is exempted from the Client Framework.
+ */
+ public boolean getIfClientFramework() { return isClientFramework_; }
+
+ /**
+ * Returns if the method is exempted from the Embedded Framework.
+ *
+ * @return true if the method is exempted from the Embedded Framework.
+ */
+ public boolean getIfEmbeddedFramework() { return isEmbeddedFramework_; }
+}
/*
* Tests of the JDBC 4.0 specific <code>Clob</code> methods.
@@ -38,6 +122,27 @@
/** Default connection used by the tests. */
private Connection con = null;
+ // Initialize with the details of the method that are exempted from
+ //throwing a SQLException when they are called after calling free()
+ //on a LOB.
+
+ private ExemptClobMD [] emd = new ExemptClobMD [] {
+ new ExemptClobMD( "getCharacterStream", new Class[] { long.class, long.class } ,true,true),
+ new ExemptClobMD( "setAsciiStream", new Class[] { long.class } ,false,true),
+ new ExemptClobMD( "setCharacterStream", new Class[] { long.class } ,true,true),
+ new ExemptClobMD( "setString", new Class[] { long.class, String.class } ,false,true),
+ new ExemptClobMD( "setString", new Class[] { long.class, String.class, int.class, int.class},false,true),
+ new ExemptClobMD( "truncate", new Class[] { long.class },false,true),
+ new ExemptClobMD( "free", null,true,true)
+ };
+
+ // An HashMap that is indexed by the Method which facilitated easy
+ //search for whether the given method has been exempted from the
+ //LOB interface.
+
+ private HashMap<Method,ExemptClobMD> excludedMethodSet =
+ new HashMap<Method,ExemptClobMD>();
+
/**
* Create the test with the given name.
*
@@ -51,6 +156,12 @@
throws SQLException {
con = getConnection();
clob = BlobClobTestSetup.getSampleClob(con);
+
+ //call the buildHashSetMethod to initialize the
+ //HashSet with the method signatures that are exempted
+ //from throwing a SQLException after free has been called
+ //on the Clob object.
+ buildHashSet();
}
public void tearDown()
@@ -62,15 +173,217 @@
}
con = null;
}
-
- public void testFreeNotImplemented()
+
+ /**
+ * Builds the HashSet which will be used to test whether the given methods
+ * can be exempted or not
+ */
+ void buildHashSet() {
+ Class iface = Clob.class;
+ for(int i=0;i<emd.length;i++) {
+ try {
+ Method m = iface.getMethod(emd[i].getMethodName()
+ ,emd[i].getParams());
+ excludedMethodSet.put(m,emd[i]);
+ }
+ catch(NoSuchMethodException nsme) {
+ fail("The method could not be found in the interface");
+ }
+ }
+ }
+
+ /**
+ * Tests the implementation for the free() method in the
+ * Clob interface.
+ *
+ * @throws SQLException if an error occurs during releasing
+ * the Clob resources
+ *
+ */
+ public void testFreeandMethodsAfterCallingFree()
throws SQLException {
- try {
+ InputStream asciiStream = clob.getAsciiStream();
+ Reader charStream = clob.getCharacterStream();
+ clob.free();
+ //testing the idempotence of the free() method
+ //the method can be called multiple times on
+ //the same instance. subsequent calls after
+ //the first are treated as no-ops
clob.free();
- fail("Clob.free() should not be implemented");
- } catch (SQLFeatureNotSupportedException sfnse) {
- // Do nothing, we are fine
+
+ //clob becomes invalid after the first call
+ //to the free method so testing calling
+ //a method on this invalid object should throw
+ //an SQLException
+ buildMethodList(clob);
+ }
+
+ /*
+ *
+ * Enumerate the methods of the Clob interface and
+ * get the list of methods present in the interface
+ * @param LOB an instance of the Clob interface implementation
+ */
+ void buildMethodList(Object LOB) {
+ //If the given method throws the correct exception
+ //set this to true and add it to the
+ boolean valid = true;
+
+ //create a list of the methods that fail the test
+ Vector<Method> methodList = new Vector<Method>();
+
+ //The class whose methods are to be verified
+ Class clazz = Clob.class;
+
+ //The list of the methods in the class that need to be invoked
+ //and verified
+ Method [] methods = clazz.getMethods();
+
+ //Check each of the methods to ensure that
+ //they throw the required exception
+ for(int i=0;i<methods.length;i++) {
+ if(!checkIfExempted(methods[i])) {
+ valid = checkIfMethodThrowsSQLException(LOB,methods[i]);
+
+ //add the method to the list if the method does
+ //not throw the required exception
+ if(valid == false) methodList.add(methods[i]);
+
+ //reset valid
+ valid = true;
+ }
+ }
+
+ if(!methodList.isEmpty()) {
+ int c=0;
+ String failureMessage = "The Following methods don't throw " +
+ "required exception - ";
+ for (Method m : methodList) {
+ c = c + 1;
+ if(c == methodList.size() && c != 1)
+ failureMessage += " & ";
+ else if(c != 1)
+ failureMessage += " , ";
+ failureMessage += m.getName();
+ }
+ fail(failureMessage);
+ }
+ }
+
+ /**
+ *Checks if the method throws a SQLFeatureNotSupportedException
+ *@param m The method object that needs to be verified to see if it
+ * is exempted
+ *@return true if the given method does not throw the required SQLException
+ *
+ */
+ boolean checkIfExempted(Method m) {
+ ExemptClobMD md = excludedMethodSet.get(m);
+
+ if(md != null && usingDerbyNetClient()) {
+ if(md.getIfClientFramework())
+ return true;
+ else
+ return false;
+ }
+ if(md != null && usingEmbedded()) {
+ if(md.getIfEmbeddedFramework())
+ return true;
+ else
+ return false;
+ }
+ return false;
+ }
+
+ /*
+ * Checks if the invocation of the method throws a SQLExceptio
+ * as expected.
+ * @param LOB the Object that implements the Blob interface
+ * @param method the method that needs to be tested to ensure
+ * that it throws the correct exception
+ * @return true If the method throws the SQLException required
+ * after the free method has been called on the
+ * LOB object
+ *
+ */
+ boolean checkIfMethodThrowsSQLException(Object LOB,Method method) {
+ try {
+ method.invoke(LOB,getNullValues(method.getParameterTypes()));
+ } catch(Throwable e) {
+ if(e instanceof InvocationTargetException) {
+ Throwable cause = e.getCause();
+ if (cause instanceof SQLException ) {
+ SQLException sqle = (SQLException)cause;
+ if(sqle.getSQLState().equals("XJ215"))
+ return true;
+ else
+ return false;
+ } else {
+ return false;
+ }
+
+ }
+ }
+ return false;
+ }
+
+ /*
+ * Return a array of objects containing the default values for
+ * the objects passed in as parameters
+ *
+ * @param parameterTypes an array containing the types of the parameter
+ * to the method
+ * @return an array of Objects containing the null values for the
+ * parameter inputs
+ */
+
+ Object[] getNullValues(Class<?> [] params) {
+ Object[] args = new Object[params.length];
+ for (int i = 0; i < params.length; i++) {
+ args[i] = getNullValueForType(params[i]);
+ }
+ return args;
+ }
+
+ /*
+ * Returns the null value for the specific type
+ *
+ * @param type the type of the parameter for which the null
+ * value is required
+ * @return the null value for the specific type
+ *
+ */
+ Object getNullValueForType(Class type)
+ {
+ if (!type.isPrimitive()) {
+ return null;
+ }
+ if (type == Boolean.TYPE) {
+ return Boolean.FALSE;
+ }
+ if (type == Character.TYPE) {
+ return new Character((char) 0);
+ }
+ if (type == Byte.TYPE) {
+ return new Byte((byte) 0);
+ }
+ if (type == Short.TYPE) {
+ return new Short((short) 0);
+ }
+ if (type == Integer.TYPE) {
+ return new Integer(0);
+ }
+ if (type == Long.TYPE) {
+ return new Long(0L);
+ }
+ if (type == Float.TYPE) {
+ return new Float(0f);
+ }
+ if (type == Double.TYPE) {
+ return new Double(0d);
}
+ fail("Don't know how to handle type " + type);
+ return null; // unreachable statement
}
public void testGetCharacterStreamLongNotImplemented()