I am working with a table (Oracle), that has a CLOB column. And I am using Hibernate to query the table. Here is a quick look at the class that I am using to map the Oracle table:
#Entity
#Table(name="D2D_OPD_ORDERDELIVERY")
public class D2dOpdOrderDelivery implements Serializable {
// other column mappings omitted for brevity
#Column(name="POD_SIGNATURE_IMG", nullable=true)
#Lob
private Clob podSignatureImage;
I have successfully managed to run the Hibernate query, which returns a single row from the database:
// Create a Hibernate query (HQL)
Query query = session.createQuery("FROM D2dOpdOrderDelivery WHERE orderNumber = :orderNumber");
query.setParameter("orderNumber", orderNumber);
Elsewhere in my code, I perform a null check on my Clob - it is NOT null. Next, I try to get the length of my Clob. And this is where I run into a problem. I get the following error:
java.sql.SQLException: Closed Connection
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:113)
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:147)
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:209)
oracle.sql.CLOB.getDBAccess(CLOB.java:1212)
oracle.sql.CLOB.length(CLOB.java:223)
Sorry, I just don't understand why I am getting this error. I have already run my query (all the other fields in the row are present). Why can't I get the length of my CLOB?
Can someone please point out where I have gone wrong?
Thank you.
OK, after posting this question, I went back and searched the Internet some more. I thought I had done a pretty good job of that before I posted my question - but that is another matter...
Anyway, I found a useful link here:
http://www.javavids.com/video/how-to-read-data-from-blob-using-jpa-hibernate.html
And the change I made to my code:
#Column(name="POD_SIGNATURE_IMG", nullable=true)
#Lob
#Basic(fetch=FetchType.LAZY)
private char[] podSignatureImage;
I was then able to call .length on my char[]
Hope this is helpful to someone else...
Related
I am getting below exception, when trying to insert a batch of rows to an existing table
ORA-00942: table or view does not exist
I can confirm that the table exists in db and I can insert data to that table using oracle
sql developer. But when I try to insert rows using preparedstatement in java, its throwing table does not exist error.
Please find the stack trace of error below
java.sql.SQLException: ORA-00942: table or view does not exist
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.ttc7.TTIoer.processError(TTIoer.java:289)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:573)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1889)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:1093)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.java:2047)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.java:1940)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout>>(OracleStatement.java:2709)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:589)
at quotecopy.DbConnection.insertIntoDestinationDb(DbConnection.java:591)
at quotecopy.QuoteCopier.main(QuoteCopier.java:72)
Can anyone suggest the reasons for this error ?
Update : Issue solved
There was no problem with my database connection properties or with my table or view name. The solution to the problem was very strange. One of the columns that I was trying insert was of Clob type. As I had a lot of trouble handling clob data in oracle db before, gave a try by replacing the clob setter with a temporary string setter and the same code executed with out any problems and all the rows were correctly inserted!!!.
ie. peparedstatement.setClob(columnIndex, clob)
was replaced with
peparedstatement.setString(columnIndex, "String")
Why an error table or view does exist error was throws for error in inserting clob data. Could anyone of you please explain ?
Thanks a lot for your answers and comments.
Oracle will also report this error if the table exists, but you don't have any privileges on it. So if you are sure that the table is there, check the grants.
There seems to be some issue with setCLOB() that causes an ORA-00942 under some circumstances when the target table does exist and is correctly privileged. I'm having this exact issue now, I can make the ORA-00942 go away by simply not binding the CLOB into the same table.
I've tried setClob() with a java.sql.Clob and setCLOB() with an oracle.jdbc.CLOB but with the same result.
As you say, if you bind as a string the problem goes away - but this then limits your data size to 4k.
From testing it seems to be triggered when a transaction is open on the session prior to binding the CLOB. I'll feed back when I've solved this...checking Oracle support.
There was no problem with my database connection properties or with my table or view name. The solution to the problem was very strange. One of the columns that I was trying insert was of Clob type. As I had a lot of trouble handling clob data in oracle db before, gave a try by replacing the clob setter with a temporary string setter and the same code executed with out any problems and all the rows were correctly inserted!!!.
ie. peparedstatement.setClob(columnIndex, clob)
was replaced with
peparedstatement.setString(columnIndex, "String")
#unbeli is right. Not having appropriate grants on a table will result in this error. For what it's worth, I recently experienced this. I was experiencing the exact problem that you described, I could execute insert statements through sql developer but would fail when using hibernate. I finally realized that my code was doing more than the obvious insert. Inserting into other tables that did not have appropriate grants. Adjusting grant privileges solved this for me.
Note: Don't have reputation to comment, otherwise this may have been a comment.
We experienced this issue on a BLOB column. Just in case anyone else lands on this question when encountering this error, here is how we resolved the issue:
We started out with this:
preparedStatement.setBlob(parameterIndex, resultSet.getBlob(columnName)); break;
We resolved the issue by changing that line to this:
java.sql.Blob blob = resultSet.getBlob(columnName);
if (blob != null) {
java.io.InputStream blobData = blob.getBinaryStream();
preparedStatement.setBinaryStream(parameterIndex, blobData);
} else {
preparedStatement.setBinaryStream(parameterIndex, null);
}
I found how to solve this problem without using JDBC's setString() method which limits the data to 4K.
What you need to do is to use preparedStatement.setClob(int parameterIndex, Reader reader). At least this is what that worked for me. Thought Oracle drivers converts data to character stream to insert, seems like not. Or something specific causing an error.
Using a characterStream seems to work for me. I am reading tables from one db and writing to another one using jdbc. And i was getting table not found error just like it is mentioned above. So this is how i solved the problem:
case Types.CLOB: //Using a switch statement for all columns, this is for CLOB columns
Clob clobData = resultSet.getClob(columnIndex); // The source db
if (clobData != null) {
preparedStatement.setClob(columnIndex, clobData.getCharacterStream());
} else {
preparedStatement.setClob(columnIndex, clobData);
}
clobData = null;
return;
All good now.
Is your script providing the schema name, or do you rely on the user logged into the database to select the default schema?
It might be that you do not name the schema and that you perform your batch with a system user instead of the schema user resulting in the wrong execution context for a script that would work fine if executed by the user that has the target schema set as default schema. Your best action would be to include the schema name in the insert statements:
INSERT INTO myschema.mytable (mycolums) VALUES ('myvalue')
update: Do you try to bind the table name as bound value in your prepared statement? That won't work.
It works for me:
Clob clob1;
while (rs.next()) {
rs.setString(1, rs.getString("FIELD_1"));
clob1 = rs.getClob("CLOB1");
if (clob1 != null) {
sta.setClob(2, clob1.getCharacterStream());
} else {
sta.setClob(2, clob1);
}
clob1 = null;
sta.setString(3, rs.getString("FIELD_3"));
}
Is it possible that you are doing INSERT for VARCHAR but doing an INSERT then an UPDATE for CLOB?
If so, you'll need to grant UPDATE permissions to the table in addition to INSERT.
See https://stackoverflow.com/a/64352414/1089967
Here I got the solution for the question. The problem is on glass fish if you are using it. When you create JNDI name make sure pool name is correct and pool name is the name of connection pool name that you are created.
I'm getting following exception, while updating table in Hibernate
ORA-24816: Expanded non LONG bind data supplied after actual LONG or LOB column
I have extracted sql query as well, it looks like
Update table_name set columnName (LOB)=value, colmun2 (String with 4000)=value where id=?;
Entity class
class Test{
#Lob
private String errorText;
#Column(length = 4000)
private String text;
}
Please help me, what is wrong in this
Thanks
Ravi Kumar
Running oerr ora 24816 to get the details on the error yields:
$ oerr ora 24816
24816, ... "Expanded non LONG bind data supplied after actual LONG or LOB column"
// *Cause: A Bind value of length potentially > 4000 bytes follows binding for
// LOB or LONG.
// *Action: Re-order the binds so that the LONG bind or LOB binds are all
// at the end of the bind list.
So another solution that uses only 1 query would be to move your LOB/LONG binds after all your non-LOB/LONG binds. This may or may not be possible with Hibernate. Perhaps something more like:
update T set column2 (String with 4000)=:1, columnName (LOB)=:3 where id=:2;
This DML limitation appears to have been around since at least Oracle 8i.
References:
http://openacs.org/forums/message-view?message_id=595742
https://community.oracle.com/thread/417560
I do realise that this thread is quite old, but I thought I'd share my own experience with the same error message here for future reference.
I have had the exact same symptoms (i.e. ORA-24816) for a couple of days. I was a bit side-tracked by various threads I came across suggesting that this was related to order of parameter binding. In my case this was not a problem. Also, I struggled to reproduce this error, it only occurred after deploying to an application server, I could not reproduce this through integration tests.
However, I took a look at the code where I was binding the parameter and found:
preparedStatement.setString(index, someStringValue);
I replaced this with:
preparedStatement.setClob(index, new StringReader(someStringValue));
This did the trick for me.
This thread from back in 2009 was quite useful.
I found issue.
1. When hibernate updating data in DB and entity has 4000 chars column and lob type column then hibernate throwing this exception
I have solved this issue by writing two update queires
1. First i have saved entity by using Update()
2. Written another update query for lob column update
Thanks
ravi
I have also encountered same error in oracle db and foudn that Hibernate Guys fixed here
In my case we were already using hiberante 4.3.7 but didnt mention that field is Lob in Entity
Reproducing Steps
Have fields with varchar2 datatype and clob data type.Make sure your column name are in this alphabetic order clob_field,varchar_two_field1,varchar_two_field2.
Now update clob_field with < 2000 bytes and varchar_two_field1 with 4000 bytes size.
This should end up with error ORA-24816: Expanded non LONG bind data supplied after actual LONG or LOB column
Solution
Make sure you have hiberante 4.1.8, < 4.3.0.Beta1
Annotate your clob/blob field in respective Entity as
import javax.persistence.Lob;
...
#Lob
#Column(name = "description")
private String description;
....
If you want to see the difference , by after making above changes enable debug for sql statements by setting "true" for "hibernate.show_sql" in persistence.xml.
I came across this issue today while trying to Insert the data into a table. To avoid this error, Just keep all the fields having "LOB" data type at the end of the insert statement.
For Example
Table1 has 8 Fields (Field1,Field2,.... Field8 etc..),
of which
Field1 and Field2 are of CLOB data types
and the rest are Varchar2 Data types
. Then while inserting the data make sure you keep Field1 and Field2 values at the end like below.
INSERT INTO TABLE1 ( Field3,Field4,Field5,Field6,Field7,Field8,Field1,Field2)
Values ('a','b','c','d','e','f','htgybyvvbshbhabjh','cbsdbvsb')
Place your LOB binding at the last. See if that solves the issue..
I am having difficulty while reading from oracle database using hibernate. The column is of clob type and mapped class property is of String type. The database is Oracle 11G. I have tried to update my driver as suggested by some posts, But it was of no use. The problem is that All other columns(which are not clob) are read properly and the column which is clob is returned null besides it has data. Thanks in advance.
The query is :
select id,about_us,other_details,periodicity,active,createts,updatets from Details where id = ?
This above the HQL query where about_us and other_details are clob type in database. The java entity contains it as type String.
Rahul
I tried many solutions as suggested in different posts, It includes:
1) Updating odbc jar.
2) Using #lob on the porperty in hibernate mapping/entity.
Both of the above solutions did not work for me, Rather I used the hibernate function str(clob_property) to read it, It worked for me and I could get the property read.
Regards
Rahul
Have you tried something like this?
#Lob #Column(name = "long_text")
private String longText;
I am trying to test a batch reading data from a database.
I have an entity such as:
#Entity
#Table(name = "CLIENT")
public class ClientEntity {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "START", nullable = false)
#Temporal(TemporalType.DATE)
private Date start;
}
When unit testing my batch, I insert data into a memory database thanks to a SQL script read with the hibernate.hbm2ddl.import_files option while the hibernate.hbm2ddl.auto option is set on create:
Insert into CLIENT(ID, START) values (1,'2006-02-01')
Insert into CLIENT(ID, START) values (2,'2010-02-01')
I can see in the log that the table is properly created. Yet, when retrieving the CLIENTs further in my code (perhaps through some join), an exception is raised:
ERROR - Column "CLIENTENTI0_.START" not found; SQL statement:
select cliententi0_.ID as ID1_10_, cliententi0_.START
as START2_10_ from CLIENT cliententi0_ [42122-165]
I have to add that when plugged to an exising Oracle database, the code runs perfectly!
What is wrong with my code? How can I get it to work?
Thanks for your help!
Well shame on me.
The error came from the fact that the goal of my batch is reading data from a database A and to write data to a database B.
To test my batch, I set two memory instances. But a mistaken copy and paste made me create twice the same instance... And since there is one CLIENT table in A and one other CLIENT table in B, an error was raised when retrieving the data: one of those tables was unproperly created!
Hope this might help someone else!
I able to save (spring-hibernate saveorupdate()) field
#Lob
#Column(name = "FILENAME")
private String filename;
into oracle database datatype is clob
but when i try retrieve it, i get error
ERROR -
JDBCExceptionReporter.logExceptions(72)
| ORA-00932: inconsistent datatypes:
expected - got CLOB
below is how i retrive from database
DetachedCriteria crit = DetachedCriteria.forClass(Storagefile.class);
crit.addOrder(bSortOrder ? Order.asc(sortColumnId) : Order.desc(sortColumnId));
List<Storagefile> result = (List<Storagefile>) getHibernateTemplate().findByCriteria(crit, nFirst, nPageSize);
It's not clear from your sample code, but my guess is that you're trying to sort by the CLOB column, and Oracle does not permit that. That error code is Oracle's charming way of telling you this.
Are you sure you need to use a CLOB to store a filnename? Oracle can store up to 4000 characters in a VARCHAR2 column, surely that's enough for a filename? If you want to sort by the filename, then that's what you'll need to do.
Have you waded through this:
https://www.hibernate.org/56.html
There seems to be an issue with the Oracle 9i driver and LOBs (not sure what your setup is).