I am inserting clob data into mysql database...here is my code
Clob cl=dbCon.createClob();
cl.setString(1,userAbout);
dbCon.setAutoCommit(false);
PreparedStatement insertClob=dbCon.prepareStatement("UPDATE user_data SET user_about=? WHERE user_id=?");
insertClob.setClob(1,cl);
insertClob.setInt(2,userId);
int count= insertClob.executeUpdate();
if(count==1){dbCon.commit();dbCon.close();out.write("success");}
else{dbCon.rollback();dbCon.close();out.print("error");}
this is throwing an exception
java.lang.AbstractMethodError: org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.createClob()Ljava/sql/Clob;
whats the problem here? and How can I solve it?
You don't need createClob() anyway. I find using setCharacterStream() to be much more stable (and much better supported by all JDBC drivers).
StringReader reader = new StringReader(userAbout);
PreparedStatement insertClob = dbCon.prepareStatement("UPDATE user_data SET user_about=? WHERE user_id=?");
insertClob.setCharacterStream(1, reader, userAbout.length());
insertClob.setInt(2,userId);
int count= insertClob.executeUpdate();
This also works with an INSERT statement. No need to create any intermediate clob (or blob) objects.
Note that I changed the wrong index 8 to the correct index 2 to match the placeholders in the UPDATE statement.
Many modern drivers also handle a "simple" setString() just as well for CLOB columns. It's worth trying out - would reduce the code even more.
Related
I have an Oracle procedure with an input Clob and returns an output Clob.
When i'm trying to recover the value, i reach the object, if i try to read the toString fro the object, i take the "oracle.sql.CLOB#625a8a83" . But when i want to read the object, in anyways i tryed, allways get a connection closed exception.
in my code:
MapSqlParameterSource parametros = new MapSqlParameterSource();
// setting input parameter
parametros.addValue("PE_IN", new SqlLobValue("IN DATA CLOB", new DefaultLobHandler()),
Types.CLOB);
// Executing call
Map<String, Object> out = jdbcCall.execute(parametros);
salida.setDatosRespuesta(out.get("PS_OUT").toString());
if i change the last line for this:
Clob clob = (Clob) out.get("PS_OUT");
long len = clob.length();
String rtnXml = clob.getSubString(1, (int) len);
i get the connection close error. I tryed in several ways and i can't solve this problem. Any ideas?
I think yo are using the SimpleJdbcCall of the spring framework. If so the database configuration are the default configurations for the oracle driver, you need to increase the time out for the reading of the values for the connection. Check the DatabaseMetaData documentation, also check the OracleConnection properies CONNECTION_PROPERTY_THIN_READ_TIMEOUT_DEFAULT. This happends because you are reading a large data from the database remember that de CLOB can have until 4gb of data
You need to keep in mind that is this process is very common in your application you need to consider the quantity of the connections to the database in order to have always enable connections to your database to guarantee your application availability
Regarding the out.get("PS_OUT").toString() this basically only show the hash that represents your object that the reason beacause why that line works fine
I have a need to store a large string into Oracle database the length of which would be at most 10000 bytes. I understand that there is some configuration in Oracle 12c that can increase the 4000 byte limit of varchar2. But I do not have the option to use that configuration.
So I am inclined to use the CLOB data type. I have no previous experience in using CLOB. So I have my concerns.
I saw the following on SO
Java: How to insert CLOB into oracle database
I did not want to use any oracle package to handle the CLOB type. My question is, is the following safe enough for my purpose?
To store:
try {
String myclobstring = "xx ........";
String sql = "Insert into mytable (clobfield) values (?)";
Statement stmt = conn.prepareStatement(sql);
stmt.setString(1, myclobstring);
.
.
}
To Retrieve:
try {
String sql = "select clobfield from mytable";
stmt = conn.createStatement();
ResultSet result = stmt.executeQuery(sql);
String s = result.getString ("clobfield');
.
.
}
You can create the CLOB as a String, though using a stmt.setCharacterStream might be a bit better for something very large. Here is an example I found that shows this nicely:
Storing Clobs
You can also use the java.sql.Clob if you're wanting to not use the Oracle specific code.
From Oracle's documentation on CLOB
Use the java.sql.Clob and create the CLOB with the connection's createClob function.
I thought I will post an answer as I did not see an explicit answer. So far setString()/setString() is storing up to 10K characters into the CLOB field. I am getting back what I am storing without a problem.
I did see the following related SO post that gives me a bit more confidence.
How to use setClob() in PreparedStatement inJDBC
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 am interfacing with an Oracle database via Spring's JdbcTemplate utility class, and I have tried these two variants of code:
jdbcTemplate.update("INSERT INTO my_table (title, content) VALUES (?, ?)", title, content);
-- or --
jdbcTemplate.update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
OraclePreparedStatement ps = (OraclePreparedStatement)conn.prepareStatement("INSERT INTO my_table (title, content) VALUES (?, ?)");
ps.setString(1, title);
ps.setStringForClob(2, content);
return ps;
}
});
Where title is a traditional VARCHAR2, and content is a CLOB.
Either of these alternatives work for smaller values for content. However, when I have larger amounts of content, nothing gets inserted into the CLOB column.
Interestingly enough, in both cases, title gets updated. It's as if the query just ignores content if there's too much, but never throws an error.
Does anybody know how I should solve this?
Thanks.
EDIT:
Per the answer from #GreyBeardedGeek, I tried using OracleLobHandler and DefaultLobHandler, to the same effect. Things work until my CLOB's reach a certain size.
I also tried the following code, again to the same effect:
Connection conn = db.getDataSource().getConnection();
CLOB clob = CLOB.createTemporary(conn, false, CLOB.DURATION_SESSION);
clob.setString(1, myString);
OraclePreparedStatement ps = (OraclePreparedStatement)conn.prepareStatement("UPDATE my_table SET blob = ?");
ps.setCLOB(1, clob);
ps.execute();
I'm baffled as to why every one of these methods would work for smaller CLOB's, but then suddenly break for large ones. Is there some type of configuration in the DB that I'm missing? Or is the problem with the code?
Okay, I feel pretty silly. As it turns out, even this simple code was storing the CLOB correctly:
jdbcTemplate.update("UPDATE my_table SET title = ?, content = ? WHERE id = ?", getTitle(), getContentString(), getId());
The issue was my code that retrieved the CLOB back from the database. The following is my speculation based on my code (and the fix): it seems as though smaller CLOB's get cached in memory, and can be read at a later time (namely, after the connection is closed, they can still be read). However, for larger CLOB's, they must be read while the connection is still open.
For me, this meant the fix was as simple as reading the CLOB's contents as soon as it was available to my object. In my case, I'm not really worried about memory issues, because I don't expect that my CLOB's will contain inordinately sized contents, and so reading the value into memory immediately is an acceptable approach.
Oracle has, for as long as I can remember, required special handling for BLOBs and CLOBs.
Spring JDBC has org.springframework.jdbc.support.lob.OracleLobHandler for setting the value of BLOBs and CLOBs.
There's a pretty good full example of how to use it at http://techdive.in/spring/spring-handling-blobclob but basically, instead of ps.setStringForClob, you would do
oracleLobHandler.getLobCreator().setClobAsString(ps, 2, content);
SqlLobValue(String content) can be used for CLOB.
Follow the link:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/support/SqlLobValue.html
.
I'm writing some JDBC code which calls a Oracle 11g PL/SQL procdedure which has a Custom Object return type. Whenever I try an register my return types, I get either ORA-03115 or PLS-00306 as an error when the statement is executed depending on the type I set. An example is below:
PLSQL Code:
Procedure GetDataSummary (p_my_key IN KEYS.MY_KEY%TYPE,
p_recordset OUT data_summary_tab,
p_status OUT VARCHAR2);
More PLSQL Code (Custom Object Details):
CREATE OR REPLACE TYPE data_summary_obj
AS
OBJECT (data_key NUMBER,
data_category VARCHAR2 (100),
sensitive_flag VARCHAR2 (1),
date_created DATE,
date_rep_received DATE,
date_first_offering DATE,
agency_data_ref VARCHAR2 (13),
change_code VARCHAR2 (120),
data_ref VARCHAR2 (50),
data_status VARCHAR2 (100),
data_count NUMBER)
/
CREATE OR REPLACE TYPE data_summary_tab AS TABLE OF data_summary_obj
/
Java Code:
String query = "begin manageroleviewdata.getdatasummary(?, ?, ?); end;");
CallableStatement stmt = conn.prepareCall(query);
stmt.setInt(1, 83);
stmt.registerOutParameter(2, OracleTypes.CURSOR); // Causes error: PLS-00306
stmt.registerOutParameter(3, OracleTypes.VARCHAR);
stmt.execute(stmt); // Error mentioned above thrown here.
Can anyone provide me with an example showing how I can do this? I guess it's possible. However I can't see a rowset OracleType. CURSOR, REF, DATALINK, and more fail.
Apologies if this is a dumb question. I'm not a PL/SQL expert and may have used the wrong terminology in some areas of my question. (If so, please edit me).
Thanks in advance.
Regs, Andrew
I finally (with a little help from others) found out the answer to this. It came in three parts:
The first was that I needed to use an:
OracleCallableStatement stmt = (OracleCallableStatement) conn.prepareCall(query);
rather than the simple JDBC CallableStatement I had been trying to use.
The second part was that I had to register my "out" parameter as follows:
stmt.registerOutParameter(2, OracleTypes.STRUCT, "DATA_SUMMARY_TAB");
The third part, and it is implicit in part 2 above, was that "DATA_SUMMARY_TAB" had to be in UPPER CASE. If you put it in lower case, then you get a cryptic error message as follows:
java.sql.SQLException: invalid name pattern: MYTEST.data_summary_tab
at oracle.jdbc.oracore.OracleTypeADT.initMetadata(OracleTypeADT.java:553)
at oracle.jdbc.oracore.OracleTypeADT.init(OracleTypeADT.java:469)
at oracle.sql.StructDescriptor.initPickler(StructDescriptor.java:390)
at oracle.sql.StructDescriptor.(StructDescriptor.java:320)
That's it.
Also, please note our custom object type was not in any packages. If it is, you might need to hack the third parameter around a little.
You two different and perhaps contradictory error messages there.
PLS-00306: wrong number or types of arguments in call to 'string'
What is the dexcription of user defined type data_summary_tab? OracleTypes.CURSOR expects a REF CURSOR, which is equivalent to a JDBC ResultSet. Whereas data_summary_tab sounds like it might be a varray or nested table.
ORA-03115: unsupported network datatype or representation
This suggests you are using an older version of the client than the database server (say 10g or even 9i). Normally we can get away with it, but sometime it can cause bugs where we're doing uncommon things. I'm not sure whether calling user-defined types over JDBC ought to count as an "uncommon thing" but I suspect it may.