ResultSet.getBlob() Exception - oracle

The Code:
ResultSet rs = null;
try {
conn = getConnection();
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while (rs.next()) {
Blob blob = rs.getBlob("text");
byte[] blobbytes = blob.getBytes(1, (int) blob.length());
String text = new String(blobbytes);
The result:
java.sql.SQLException: Invalid column type: getBLOB not implemented for class oracle.jdbc.driver.T4CClobAccessor
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:145)
at oracle.jdbc.driver.Accessor.unimpl(Accessor.java:357)
at oracle.jdbc.driver.Accessor.getBLOB(Accessor.java:1299)
at oracle.jdbc.driver.OracleResultSetImpl.getBLOB(OracleResultSetImpl.java:1280)
at oracle.jdbc.driver.OracleResultSetImpl.getBlob(OracleResultSetImpl.java:1466)
at oracle.jdbc.driver.OracleResultSet.getBlob(OracleResultSet.java:1978)
I have class12_10g.zip in my class path. I've googled and have found essentially only one site on this particular problem, and it wasn't helpful at.
Does anyone have any ideas on this?
A little background:
We were converting one of our databases from MySQL to Oracle. Within the MySQL DB, one of the fields is a longtext which is treated as a BLOB in the code. The SQL developer workbench by default converts longtext to CLOB (make sense to me) but the code was expecting Blob. I guess the error wasn't that nice: oracle.jdbc.driver.T4CClobAccessor (though it does mention Clob).
When I tried the following:
rs = stmt.executeQuery();
while (rs.next()) {
byte[] blobbytes = rs.getBytes("text");
String text = new String(blobbytes);
}
it threw an unsupported exception - all I had to do in the first place was compare the types in the newly created Oracle DB with what the code was expecting (unfortunately I just assumed they would match).
Sorry guys! Not that I've put much thought into it, now I have to figure out why the original developers used BLOB types for longtext

Not sure about making the Blob object work -- I typically skip the Blob step:
rs = stmt.executeQuery();
while (rs.next()) {
byte[] blobbytes = rs.getBytes("text");
String text = new String(blobbytes);
}

try to use the latest version of the drivers (10.2.0.4). Try also the drivers for JDK 1.4/1.5 since classes12 are for JDK 1.2/1.3.

Try...
PreparedStatement stmt = connection.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
rs.next();
InputStream is = rs.getBlob(columnIndex).getBinaryStream();
...instead?

I have a utility method in a DAO superclass of all my DAOs:
protected byte[] readBlob(oracle.sql.BLOB blob) throws SQLException {
if (blob != null) {
byte[] buffer = new byte[(int) blob.length()];
int bufsz = blob.getBufferSize();
InputStream is = blob.getBinaryStream();
int len = -1, off = 0;
try {
while ((len = is.read(buffer, off, bufsz)) != -1) {
off += len;
}
} catch (IOException ioe) {
logger.debug("IOException when reading blob", ioe);
}
return buffer;
} else {
return null;
}
}
// to get the oracle BLOB object from the result set:
oracle.sql.BLOB blob= (oracle.sql.BLOB) ((OracleResultSet) rs).getBlob("blobd");
Someone will now say "why didn't you just do XYZ", but there was some issue at the time that made the above more reliable.

When JDBC returns a ResultSet from an Oracle database it always returns an OracleResultSet. If you are typing it as a ResultSet, java upcasts it to the standard SQL ResultSet.
OracleResultSet overrides most of the data type methods, because Oracle datatypes are not standard SQL types.
In other words, that worked because you cast the rs as an OracleResultSet, and used it's getBlob method.

Related

Read packed decimal and convert to numeric in spring boot

All,
I am using a Spring boot application to store data in DB. I am getting this data from IBM MQ through Kafka topic.
I am getting messages in EBCDIC format, so used cobol copybook, JRecord, cb2xml jars to convert to readable format and store in DB.
Now i am getting another file also in the same manner, but after conversion the data looks like this:
10020REFUNDONE
10021REFUNDTWO ·" ÷/
10022REFUNDTHREE oú^ "
10023REFUNDFOUR ¨jÄ ò≈
Here is how i am converting to readable format from ebcdic:
AbstractLineReader reader = null;
StringBuffer finalBuffer = new StringBuffer();
try {
String copybook = "/ds_header.cbl";
reader = CustomCobolProvider.getInstance().getLineReader(copybook, Convert.FMT_MAINFRAME, new BufferedInputStream(new ByteArrayInputStream(salesData)));
AbstractLine line;
while ((line = reader.read()) != null) {
if (null != line.getFieldValue(REC_TYPE)){
finalBuffer.append(line.getFullLine());
}
}
}
and this is my getLineReader method:
public AbstractLineReader getLineReader(String copybook, int numericType, InputStream fileStream) throws Exception {
String font = "";
if (numericType == 1) {
font = "cp037";
}
InputStream stream = CustomCobolProvider.class.getResourceAsStream(copybook);
if(stream == null ) throw new RuntimeException("Can't Load the Copybook Metadata file from Resource....");
LayoutDetail copyBook = ((ExternalRecord)this.copybookInt.loadCopyBook(stream, copybook, CopybookLoader.SPLIT_REDEFINE, 0, font, CommonBits.getDefaultCobolTextFormat(), Convert.FMT_MAINFRAME, 0, (AbsSSLogger)null).setFileStructure(Constants.IO_FIXED_LENGTH)).asLayoutDetail();
AbstractLineReader ret = LineIOProvider.getInstance().getLineReader(copyBook, (LineProvider)null);
ret.open(fileStream, copyBook);
return ret;
}
I am stuck here with the numeric conversion, i got to know it is coming in packed decimal.
I have nil knowledge on cobol and mainframe, referred few sites and got to know how to convert from ebcdic to readable format. Please help!
The problem is getFullLine() method does not do any field translation; you need to access individual fields. You can use the line.getFieldIterator(0) to get a field iterator for the line.
Also unless you are using an ancient version of JRecord, you are better off using the JRecordInterface1 class.
Some thing like the following should work:
StringBuffer finalBuffer = new StringBuffer();
try {
ICobolIOBuilder iob = JRecordInterface1.COBOL .newIOBuilder(copybookName)
.setFont("cp037")
.setFileOrganization(Constants.IO_FIXED_LENGTH)
;
AbstractLineReader reader = iob.newReader(dataFile);
while ((line = reader.read()) != null) {
String sep = "";
for (AbstractFieldValue fv : line.getFieldIterator(0)) {
finalBuffer.append(sep).append(fv);
sep = "\t";
}
finalBuffer.append("\n");
}
reader.close();
} catch (Exception e) {
// what ever ....
}
Other points
With MQ data source you do not need to create line-readers. You can create lines directly from a byte array:
ICobolIOBuilder iob = JRecordInterface1.COBOL .newIOBuilder(copybookName)
.setFont("cp037")
.setFileOrganization(Constants.IO_FIXED_LENGTH)
;
AbstractLine line = iob.newLine(byteArrayFromMq);
for (AbstractFieldValue fv : line.getFieldIterator(0)) {
// what ever
}

Ibatis TypeHandler and empty Varchar parameters in types in stored procedure

In a mybatis, spring application I have a TypeHandler which fills data for an ARRAY of STRUCTS required to call Oracle's stored procedure. A blob entry is properly filled and visible in the stored procedure; String entries are not, no string data is sent. No error or warning printed in logs. Data is not null and valid in application. The data simply disappears between application and oracle.
My handler's setParameter implementation looks like this:
public void setParameter(PreparedStatement ps, int i, List<MailAttachment> parameter,
JdbcType jdbcType) throws SQLException
{
List<MailAttachment> attachmentList = parameter;
OracleConnection oracleConnection = ps.getConnection().unwrap(OracleConnection.class);
StructDescriptor structDescriptor = StructDescriptor.createDescriptor(ATTACHMENT, oracleConnection);
Object[] structs = null;
structs = new Object[attachmentList == null ? 0 :attachmentList.size()];
if (attachmentList != null) {
//CharacterSet chs = CharacterSet.make(CharacterSet.UTF8_CHARSET);
for (int index = 0; index < attachmentList.size(); index++) {
MailAttachment mailAttachment = attachmentList.get(index);
BLOB blob = null;
if (mailAttachment.getData() != null){
blob = BLOB.createTemporary(oracleConnection,false,BLOB.DURATION_SESSION);
// filling blob works
}
CHAR attachName = new CHAR(mailAttachment.getFilename(), CharacterSet.make(CharacterSet.UTF8_CHARSET) );
CHAR contentType = new CHAR(mailAttachment.getContentType(), CharacterSet.make(CharacterSet.UTF8_CHARSET) );
STRUCT struct = new STRUCT(structDescriptor, oracleConnection,
new Object[] {blob, attachName, contentType, null}
);
structs[index] = struct;
}
}
ArrayDescriptor arrayDesc = ArrayDescriptor.createDescriptor(ATTACHMENT_LIST, oracleConnection);
ARRAY oracleArray = new ARRAY(arrayDesc, oracleConnection, structs);
ps.setObject(i, oracleArray);
}
This issue is connected with Oracle JDBC driver and it's support for internationalization.
Remember to include orai18n.jar in classpath/pom file in correct version for your ojdbc jar file.
If orai18n.jar is missing:
setParameters: varchar2 parameters in Oracle type will be set to null
getResult/getNonNullParameter: varchar2 parameters will be loaded to java class as "???" string.

Using JDBC Driver for Informix + SQLException being thrown when NULL Value is encountered

I'm using the JDBC driver for Informix. I connect to my host just fine, but when the query is executed a null value is returned for one of the fields specified in my select. Instead of just retrieving that value, and SQLException gets thrown:
Column (colname) not found in any table in the query (or SLV is undefined).
I'm using the driver this way:
try{
PreparedStatement pstmtDist = conn.prepareStatement(query2);
ResultSet rsDist = pstmtDist.executeQuery();
while(rsDist.next()){
int distCaseId = 0;
String distCaseIdStr = new String();
int distCaseDefNum = 0;
String distCaseDefNumStr = new String();
distCaseIdStr = rsDist.getObject("colname").toString();
distCaseId = Integer.parseInt(distCaseIdStr.trim());
distCaseDefNumStr = rsDist.getObject("colname2").toString();
distCaseDefNum = Integer.parseInt(distCaseDefNumStr.trim());
//System.out.println(String.format("distCaseId == %d distCaseDefNum == %d\n",distCaseId,distCaseDefNum));
}// end while district cases
rsDist.close();
pstmtDist.close();
connDist.close();
}
catch (SQLException e){
System.out.println("EXCEPTION: "+e.getMessage());
}
Any tips are welcomed!
-TU
I think problem is in line:
distCaseDefNumStr = rsDist.getObject("colname2").toString();
and with similar lines where getObject() can return null.
If your colname2 has null value then getObject() returns null and then Java tries to run toString() method on null object.
Yes, the message about column not found in result is strange, but I think that you really observe null pointer exception. Use getString() or getInt() methods of ResultSet.

convert system.data.linq.binary to byte[]

I am storing bytes in a database table. When I retrieve it with Linq 2 sql I get the return type in system.data.linq.Binary.
I am not able to convert the system.data.linq.binary to byte array(byte[]).
How do I convert it?
///my datacontext
var db = new db();
//key is an value from user
var img = from i in db.images
where i.id == key
select i.data;
the i.data is in linq.binary I want it to be in byte[].
I tried with (byte[])img but it did not work.
Have you tried calling ToArray() on i.data?
var img = from i in db.images
where i.id == key
select i.data.ToArray();
System.Data.Linq.Binary has a ToArray method just for that purpose.
Probably its too late by now but may help others :)
//testTable PK:ID, binaryData :binary(32)
public void insertDummyData()
{
DBML.testTable v = new DBML.testTable ();
v.ID = 1;
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
v.binaryData = new System.Data.Linq.Binary(encoding.GetBytes("11111111000000001111111100000000"));
db.testTable.InsertOnSubmit(v);
db.SubmitChanges();
}
Or else, Click on the Binary field from .dbml file, open properties and then change the field type from Binary to byte[] as found here
(byte[])linqBinaryField.ToArray()
You can try MemoryStream. I wrote a function in my project to convert an image to byte array like the following:
public static byte[] Image2ByteArr(string filename)
{
Bitmap bm = new Bitmap(getPath(filename));
MemoryStream ms = new MemoryStream();
bm.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
return ms.ToArray();
}
Hope that helpful for you!

How to append text to an oracle clob

Is it possible to append text to an oracle 9i clob without rereading and rewriting the whole content?
I have tried this:
PreparedStatement stmt = cnt.prepareStatement(
"select OUT from QRTZ_JOBEXEC where EXEC_ID=? "
+ "for update",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
try {
stmt.setLong(1, id);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
Clob clob = rs.getClob(1);
long len = clob.length();
Writer writer = clob.setCharacterStream(len+1);
try {
PrintWriter out = new PrintWriter(writer);
out.println(line);
out.close();
} finally {
writer.close();
}
rs.updateClob(1, clob);
rs.updateRow();
}
rs.close();
} finally {
stmt.close();
}
But I'm getting an "Unsupported feature" exception on the call to setCharacterStream.
DBMS_LOB.APPEND is the key.
if you are just adding text then you could try a simple
UPDATE qrtz_jobexec SET out = out || ? WHERE exex_id=?

Resources