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=?
Related
I want to verify if my JDBC query output has data in it or not. If it doesn't contain any data then it should print the assertion as false.
I tried using this:
System.out.println("Table contains "+rs.getRow()+" rows");
if (!rs.next())
{
Assert.assertTrue(false);
}
else
{
Assert.assertTrue(true);
}
I tried using as below:
System.out.println("Table contains "+rs.getRow()+" rows");
if (!rs.next())
{
Assert.assertTrue(false);
}
else
{
Assert.assertTrue(true);
}
But it didn't work. So can anyone suggest how to solve this?
If you only need to know, how many rows are in a table, let the DBMS count them with:
select count(*) as noRows from table
And within your java code it will look like this snippet
boolean hasRows= false;
Statement stmt = null;
ResultSet rs = null;
try {
stmt = connection.createStatement();
rs = stmt.executeQuery("select count(*) as noRows from table");
if ( rs.next() ) {
if ( rs.getInt(1) > 0 ) {
hasRows = true;
}
}
} catch (SQLException sqlex ) {
// print or log an error message
} finally {
if ( rs != null ) {
try {
rs.close();
} catch (SQlException sqlex ) {
// print or log an error message
}
}
if ( stmt != null ) {
try {
stmt.close();
} catch (SQlException sqlex ) {
// print or log an error message
}
}
}
Assert.assertTrue(hasRows);
And it could also make sense to close your connection.
This will just return the rows within a table. If you need to know the size of a particular query, I for myself would do it similarly with the query and just replace the fields from the query with the count(*) or count(DISTINCT xyz) command. Try it first out within your sql monitor, because if the query runs to long, you might not be happy.
I'm sort of having a hard time with this one. Well ok, I have two different solutions (solution1 has a WebApplication Project; solution2 has a Website Project). Inside the two solutions, there's a WCF service structure. I have the exact same code in both services (in their respective solutions). My code compiles just fine. From the service I do a simple call to a procedure that returns a cursor. When I execute the service from the WebApplication it works just fine; when I do the same from the Website I get error: "wrong number or types of arguments". They both call the same procedure, in the same DB. And I triple check my code, and is the same in both services. Any ideas or suggestions? My code is as follows in both solutions:
Service.cs
public List<A1001310> SearchClient_A1001310()
{
DataTable dataTable = new DataTable();
dataTable = DataManager.SearchClient();
List<A1001310> list = new List<A1001310>();
list = (from DataRow dr in dataTable.Rows
select new A1001310()
{
Id = Convert.ToInt32(dr["CLIENT_ID"]),
//ClientName = dr["NOM_CLIENTE"].ToString()
}).ToList();
return list;
}
DataManager.cs
public static DataTable SearchClient()
{
try
{
using (OleDbCommand cmd = new OleDbCommand(packetName + ".select_A1001310"))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlManager sqlManager = new SqlManager();
return sqlManager.GetDataTable(cmd);
}
}
catch (Exception ex)
{
//TODO; Handle exception
}
return null;
}
The call to DataTable is:
public DataTable GetDataTable(OleDbCommand cmd)
{
using (DataSet ds = GetDataSet(cmd))
{
return ((ds != null && ds.Tables.Count > 0) ? ds.Tables[0] : null);
}
}
public DataSet GetDataSet(OleDbCommand cmd)
{
using (DataSet ds = new DataSet())
{
this.ConvertToNullBlankParameters(cmd);
using (OleDbConnection conn = new OleDbConnection(cmd.Connection == null ? _dbConnection : cmd.Connection.ConnectionString))
{
cmd.Connection = conn;
cmd.CommandTimeout = _connTimeout;
conn.Open();
//cmd.ExecuteScalar();
using (OleDbDataAdapter da = new OleDbDataAdapter(cmd))
da.Fill(ds);
}
return ds;
}
}
The procedure is as follow:
PROCEDURE select_A1001310(io_cursor OUT lcursor_data)
AS
BEGIN
OPEN io_cursor FOR
--
SELECT client_id
FROM a1001310
WHERE status = 'A'
--
EXCEPTION
WHEN OTHERS THEN
IF io_cursor%ISOPEN THEN
CLOSE io_cursor;
END IF;
--REVIRE: EXCEPTION HANDLER
END select_A1001310;
So if it helps anyone, I resolved my issue by specifying the OUT parameter declared in the procedure. This resulted in me changing from Oledb to OracleClient as follow:
public static DataTable SearchClient()
{
string connection = ConfigurationManager.ConnectionStrings["DBConnection_Oracle"].ToString();
string procedure = packetName + ".p_search_client";
OracleParameter[] parameters = new OracleParameter[1];
parameters[0] = new OracleParameter("io_cursor", OracleType.Cursor, 4000, ParameterDirection.Output, true, 0, 0, "", DataRowVersion.Current, String.Empty);
DataTable dt = new DataTable();
dt = DataManager_Oracle.GetDataTable_(connection, procedure, parameters);
return dt;
}
It seems that on the Website environment it didn't like leaving out the OUT parameter; whereas on the WebApplication I did not specify it, and it worked just fine... If some one know the why , PLEASE let me know :)
String selectTableSQL = "select JobID, MetadataJson from raasjobs join metadata using (JobID) where JobCreatedDate > '2014-07-01';";
File file = new File("/users/t_shetd/file.txt");
try {
dbConnection = getDBConnection();
statement = dbConnection.createStatement();
System.out.println(selectTableSQL);
// execute select SQL stetement
ResultSet rs = statement.executeQuery(selectTableSQL);
if (!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
while (rs.next()) {
String JobID = rs.getString("JobID");
String Metadata = rs.getString("MetadataJson");
bw.write(selectTableSQL);
bw.close();
System.out.println("Done");
// Now i am only getting the output done
If I understand your question, then this
while (rs.next()) {
String JobID = rs.getString("JobID");
String Metadata = rs.getString("MetadataJson");
bw.write(selectTableSQL);
bw.close();
System.out.println("Done");
}
Should be something like (following Java capitalization conventions),
while (rs.next()) {
String jobId = rs.getString("JobID");
String metaData = rs.getString("MetadataJson");
bw.write(String.format("Job ID: %s, MetaData: %s", jobId, metaData));
}
bw.close(); // <-- finish writing first!
System.out.println("Done");
In your version, you close the output after printing the first line from the ResultSet. After that, nothing else will write (because the File is closed).
I want to test an Oracle Stored Procedure by using jmeter.I have done everything but parameters.
And here is my SQL Query:
declare
outinfo varchar2(20);
outtable sys_refcursor;
begin
{call RK_JSCX(?,?)};
end;
The outtable in Oracle is a cursor.And i used resultSet to contain it in java.However,whatever i set in parameter types ,it said invalid type.
Sample Start: 2012-10-25 16:06:41 CST
Load time: 0
Latency: 0
Size in bytes: 25
Headers size in bytes: 0
Body size in bytes: 25
Sample Count: 1
Error Count: 1
Response code: null 0
Response message: java.sql.SQLException: Invalid data type: cursor
Response headers:
oracle.jdbc.driver.T4CConnection#58ba09
SampleResult fields:
ContentType: text/plain
DataEncoding: UTF-8
How can fix it?
Thanks!
Here is my code in java:
public String RK_JSCX() throws Exception {
RK_JSCX_Response response = null;
List<RK_JSCX_Outtable> list = null;
Connection con = null;
CallableStatement cs = null;
ResultSet rs = null;
String sql = null;
try {
sql = "{call RK_JSCX(?,?)}";
con = ConnectionUtils.getInstance().getConnect();
if (con.isClosed()) {
throw new IllegalStateException("ERROR.THE CONNECTION ISCLOSED");
}
cs = con.prepareCall(sql);
cs.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
cs.registerOutParameter(2, Types.VARCHAR);
cs.execute();
rs = (ResultSet) cs.getObject(1);
list = new ArrayList<RK_JSCX_Outtable>();
while (rs.next()) {
RK_JSCX_Outtable out = new RK_JSCX_Outtable(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getInt(5), rs.getString(6));
list.add(out);
}
String outInfo = cs.getString(2);
response = new RK_JSCX_Response(list, outInfo);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (rs != null) {
rs.close();
if (cs != null) {
cs.close();
}
if (con != null) {
con.close();
}
}
} catch (SQLException e) {
System.out.println("Exception2");
e.printStackTrace();
}
}
return JSON.toJSONString(response);
}
This is how to do it:
SQL Query : call RK_JSCX(?,?)
Parameter values : OUT, OUT
Parameter types : OUT -10,OUT VARCHAR
-10 being the int value of OracleTypes.CURSOR
Variable names: cursor, outInfo
Names are what you want
JMeter allows using more types than java.sql.Types constants, in this case instead of using Constant names, you use integer values of constants.
Documentation has been clarified (in next JMeter version) , see:
https://issues.apache.org/bugzilla/show_bug.cgi?id=54048
Try with the following changes
change the syntax in calling the procedure to
cs = con.prepareCall("BEGIN RK_JSCX(?, ?); END;");
And I believe your first OUT parameter is VARCHAR2 right? so
cs.registerOutParameter(1, Types.VARCHAR);
then
use the following to cast CallableStatement
rs = ((OracleCallableStatement)cs).getCursor(2);
Update 1
I have changed your procedure to demonstrate working version
Procedure
CREATE OR REPLACE PROCEDURE rk_jscx (outtable OUT sys_refcursor,
outinfo OUT VARCHAR2
)
AS
BEGIN
OPEN outtable FOR
SELECT SYSDATE
FROM DUAL;
outinfo := 1;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
outinfo := 2;
ROLLBACK;
END rk_jscx;
Java Code
CallableStatement stmt = conn.prepareCall("BEGIN rk_jscx(?, ?); END;");
stmt.registerOutParameter(1, OracleTypes.CURSOR);
stmt.registerOutParameter(2, Types.VARCHAR);
stmt.execute();
ResultSet rs = ((OracleCallableStatement)stmt).getCursor(1);
while (rs.next()) {
System.out.println(rs.getDate("sysdate"));
}
The above prints 2012-10-23
Check your jdbc driver as well
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.