executeUpdate() doesn't throw error thrown in Sql-Server - java

I have stored procedure that starts transaction that should install tool to a machine. Every machine can have multiple tools installed, but each tool can be installed to only one machine (constraints in table creation). If those constraints are broken, the exception that is thrown should be changed into more specific exception. The problem is when I run procedure in SQL-server everything works great, but calling callableStatement.executeUpdate() doesn't throw exception in java code.
I tried to use callableStatement.executeQuery() instead and it works great when exception is throw, but if procedures works without problem I still get exeption "0; the statement did not return a result set.; state=null".
SQL-server procedure
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO montaza (oznStroj, sifAlat) VALUES (#oznStroj, #sifAlat);
UPDATE alat
SET montiran = 'D'
WHERE sifAlat = #sifAlat;
UPDATE stroj
SET brojMontiranih = brojMontiranih + 1
WHERE oznStroj = #oznStroj;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
IF ERROR_NUMBER() = #primary_key_error_number
BEGIN
THROW 50511, 'Alat je zauzet', 1;
END
ELSE IF ERROR_NUMBER() = #constraint_broken_code
BEGIN
IF ERROR_MESSAGE() LIKE '%chkKapacitet%'
BEGIN
THROW 50512, 'Kapacitet strojaje popunjen', 1;
END
ELSE
BEGIN
THROW SELECT ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_STATE();
END
END
ELSE
BEGIN
THROW SELECT ERROR_NUMBER(), ERROR_MESSAGE(), ERROR_STATE();
END
END CATCH
GO
JDBC call:
try {
Connection conn = SQLConnectionProvider.getConnection();
CallableStatement callableStatement = conn.prepareCall(installToolTrans);
callableStatement.setInt(1, toolCode);
callableStatement.setString(2, machineTag);
callableStatement.executeUpdate();
callableStatement.close();
conn.close();
} catch (SQLException sqlException) {
throw new DAOException(sqlException.getErrorCode(), sqlException.getMessage(), sqlException.getSQLState());
}
Expected:
When procedure works correctly and commits changes no exception gets thrown by java code and when procedure throws exception, java code will catch it.

Related

How to check Oracle procedure is created correctly by using java?

Am making a simple tool (using) that executes Oracle script from a text file. it's working fine, but while executing create procedure or trigger if an error occurs by oracle, java not throwing any exception, and in the same scenario, any table creation or execution of select/insert/ delete it throwing the exception with error .so my question is how to catch the error while executing procedure/trigger creating script? thank you.
Example: this function (it may be a procedure, trigger )I need to create Oracle.
create or replace function fn_get_contract_invoice_amt(I_CompanyId varchar2,
I_ContractNo Varchar2, I_Date1 Date, I_Date2 Date)
return number is
V_Amount Number(13,3);
begin
begin
Select sum(nvl(Amount,0)) into v_Amount
From Invmast im
Where Company_id = I_CompanyId
and Contract_No = I_ContractNo
and Tran_Date between I_Date1 and I_Date2
and Deleted = 'N'
and Posted = 'Y';
Exception
When No_Data_Found Then
V_Amount := 0;
End;
Return nvl(V_Amount,0);
end;
Java Code to execute script
private static String runSqlStatement(String script) {
String status = "";
System.out.println(script);
Statement stmt = null;
try {
stmt = conn.createStatement();
stmt.execute(script);
} catch (SQLException ex) {
status = ex.getMessage();
System.err.println("SQLException: " + ex.getMessage());
} finally {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
System.err.println("SQLException: " + e.getMessage());
}
}
}
return status;
}
I don't think Oracle treats compilation errors when creating procedures as actual errors per say.
If you test this with sqlplus and put a WHENEVER SQLERROR EXIT FAILURE ROLLBACK then run a failed CREATE OR REPLACE you will see that only errors reported via the standard ORA-nnnnn type message is caught. The create with compliation errors result is not caught as a error.
The reason is because even it it is created with compilation errors it is still created.
The only way for you in your use case to check if the CREATE OR REPLACE succeeded is, perhaps as follows:
Execute the CREATE or REPLACE statement
Check DBA_OBJECTS (or ALL_OBJECTS or USER_OBJECTS as appropriate) :
SELECT STATUS
FROM DBA_OBJECTS
WHERE OBJECT_NAME = 'OBject_name'
AND OBJECT_TYPE = 'PACKAGE|PACKAGE BODY|PROCEDURE...'
AND OWNER = 'the_owner'
If this returns VALID then it worked and compiled cleanly, if INVALID then query DBA_ERRORS :
SELECT *
FROM DBA_ERRORS
WHERE NAME = 'Object_name'
AND TYPE = '....'
AND OWNER = 'the_owner'

Transaction not starting unless I do modification

I'm having an issue where my transaction doesn't truly seem to be starting unless I issue a command that appears to be transaction worthy (the last part is conjecture).
Below I have a method decorated with the #Transaction attribute, it's public, it's being called via the spring proxy. I'm connecting to SQL Server, using Microsoft's JDBC driver version 4.2. And getting an app lock, if I try and get the app lock before doing something that's transaction worth the transaction doesn't appear to start. I'm guessing this based on the returned error code (-999) which is consistent with not being in a transaction.
This code works perfectly fine in my other project, but there we are doing more than just grabbing an app lock.
Here's the method (Ignore the fact that this would just lose the app lock right after fetching it)
#Transactional
public Boolean getAppLock(String lockString, Integer timeoutMilliseconds) {
try {
Session session = entityManager.unwrap(Session.class);
int result = session.doReturningWork(connection -> {
int execResult = -1;
// Works if I add this line
// connection.prepareStatement("insert into foo (baz) values('bar')").execute();
// This line works also, which is stupid, cause it doesn't even update anything
// connection.prepareStatement("update foo set baz = baz where id = 1231241").execute();
try (PreparedStatement statement = connection.prepareStatement("declare #i int; exec #i = sp_getapplock ?,?,?,?; select #i;")) {
statement.setString(1, lockString);
statement.setString(2, "Exclusive");
statement.setString(3, "Transaction");
Integer timeout = timeoutMilliseconds == null ? 0 : timeoutMilliseconds;
statement.setInt(4, timeout);
try (ResultSet resultSet = statement.executeQuery()) {
resultSet.next();
// Complains about not being in a transaction, unless
// I have a random statement that seems transaction worthy
execResult = resultSet.getInt(1);
} catch (Exception ex) {
logger.error("Failed getting the result set from the app lock", ex);
}
} catch (Exception ex) {
logger.error("Error executing statement sp_getapplock", ex);
}
return execResult;
});
// see return codes here (https://msdn.microsoft.com/en-us/library/ms189823.aspx), 0+ is good, < 0 is bad
return result >= 0;
}
catch (Exception ex){
throw new RuntimeException(ex.getMessage());
}
}
I'm not sure if this is a driver or a spring thing, I'm leaning toward driver thing.

Dynamic SQL Exception Handling in SQL Server

I'm executing the following Dynamic SQL on SQL Server 2008 via Java:
BEGIN TRY
BEGIN TRAN T1;
DELETE FROM [MyDatabase].[dbo].[MyTable];
DECLARE #bulk_cmd nvarchar(max);
SET #bulk_cmd = 'BULK INSERT ... ';
EXEC (#bulk_cmd);
COMMIT TRAN T1;
END TRY
BEGIN CATCH
ROLLBACK TRAN T1;
DECLARE #ErrorMessage NVARCHAR(4000), #ErrorSeverity INT, #ErrorState INT;
SELECT #ErrorMessage = ERROR_MESSAGE(), #ErrorSeverity = ERROR_SEVERITY(), #ErrorState = ERROR_STATE();
RAISERROR (#ErrorMessage, #ErrorSeverity, #ErrorState);
END CATCH;
If the SQL provided in #bulk_cmd contains an error, I can see that in SSMS, but when I execute in Java, the exception is not being caught. The Java is pretty standard:
Statement stmt = null;
try {
stmt = conn.createStatement();
stmt.executeUpdate(sql);
logger.debug("SQL command executed.");
} catch (Exception ex) {
logger.debug("SQL command failed.");
throw ex;
} finally {
if (stmt != null) {
stmt.close();
}
}
If I mess up the SQL (outside of the dynamic part), it will catch the syntax error. But why are the errors generated by the dynamic SQL not being caught by Java?
Found solution here.
Adding SET NOCOUNT ON; at the beginning of the SQL fixed the issue. Now my exceptions are being caught in Java.
Hard to handle, you can check for
dbo.spGet_LastErrorMessage;
or checking for
##error
But if you are sending the command from java, why do you have bussines logic in the DDBB? Why don't you build the query using java and then execute the command as a regular SQL query?

resultSet.next() throwing null pointer exception

I'm working in java using the JDBC to perform queries on a database. For some reason, this code:
public static void checkAllFlights() {
String SQLStatement = "SELECT Flight.FlightID,"
+"(CASE WHEN (SUM(NumSeats) > 0) THEN SUM(NumSeats) ELSE 0 END)"
+"AS Booked_Seats,"
+"(CASE WHEN (MaxCapacity-SUM(NumSeats) > 0) THEN MaxCapacity-SUM(NumSeats) ELSE MaxCapacity END) AS Available_Seats,"
+"MaxCapacity"
+"FROM Flight LEFT JOIN FlightBooking ON Flight.FlightID = FlightBooking.FlightID"
+"GROUP BY Flight.FlightID, Flight.MaxCapacity"
+"ORDER BY Flight.FlightID";
try {
dbAccess.getConnection();
ResultSet resultSet = dbAccess.runSimpleQuery(SQLStatement);
System.out.println("FlightID "+"Booked_Seats "+"Available_Seats "+"Max_Capacity");
while (resultSet.next()) {
int ID = resultSet.getInt(1);
System.out.println(ID);
}
DBAccess.disconnect();
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
is throwing me the error:
java.lang.NullPointerException
at databases2.Databases2.checkAllFlights(Databases2.java:245)
at databases2.Databases2.main(Databases2.java:26)
(line "245" refers to the "while (resultSet.next())")
resultSet.next() and resultSet.close() on their own also produce the same error.
I've used essentially the same code further up to cycle over a resultset and it worked fine and I've run the SQL directly and that returns the correct results so I'm confused as to why the resultSet.next() could be throwing a null pointer exception?
The runSimpleQuery method:
public ResultSet runSimpleQuery(String sql)
throws Exception {
try {
// Create a statement variable to be used for the sql query
statement = connection.createStatement();
// Perform the update
return statement.executeQuery(sql);
} catch (SQLException e) {
// Problem encountered
statement = null;
return null;
}
Update: After stepping through it, it does appear that runSimpleQuery is returning null which is something it shouldn't be doing unless an sql exception is throw....
Update: Solved. Whilst the query was right, apparently I messed up my string concatenation so that it didn't include spaces where it should and it worked when testing because I was an idiot and tested the query by copy-pasting from code rather than pulling the actual variable out of the debugger....
Have you checked connection object? is it returning proper connection ? it might be possible that connection is null..and it caught in catch block and returning null. You should debug that .. by printing the exception in catch block ..so that you may come to know the exact reason for this null
I ran into the same issue and I discovered that if other thread uses the same connection the ResultSet will throw a NullPointerException after the other sql is executed.
sys.scheduler 06:28:00,017 [SchedulerReloader] ERROR - java.lang.NullPointerException
sys.scheduler 06:28:00,018 [SchedulerReloader] ERROR - com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:7009)
My process is a long running process with 200k rows... I will use a particular connection for this and discard it after the process is done.
Debug your runSimpleQuery method, it returns null, that's why resultset.getNext() throw NullPointerException

Retain jdbc batch statements after exception

I am inserting data from java in to postgresql database. I am using jdbc postgresql driver to make connection. I am creating a batch of statements and sending to insert in one go. But if connection is lost then java tries to connect with database again using connection pooling. I tried to execute the batch again but no record is inserted.
PreparedStatement pstmt = connection.prepareStatement(INSERT_RECORD_TABLE_SQL);
while (iterator.hasNext()) {
pstmt.setLong(1, toLong(fields[0]));
pstmt.setLong(2, toLong(fields[1]));
....
pstmt.addBatch();
}
try{
pstmt.executeBatch();
} catch (Exception e) {
Thread.sleep(60000);
pstmt.executeBatch();
}
My question is that Can I retain the batch of statements that can be executed if exception occurs?
Thanks,
Saurabh Gupta
It is a bad thing to catch the general Exception.
It is a bad thing to sleep for a minute, or any other "human" time value.
It is a bad thing to re-execute the same code in the catch block just like if nothing had occurred, but you're handling an exception there! And you should catch the new possible exception in the catch block.
Better to:
try
{
int[] updateCounts = pstmt.executeBatch();
}
catch (BatchUpdateException be)
{
// if one of the commands sent to the database fails to execute properly
// or attempts to return a result set
handleException(be);
return;
}
catch (SQLException se)
{
//if a database access error occurs, this method is called on a closed Statement
//or the driver does not support batch statements
handleException(se);
return;
}
Do you need a transaction? That is, if an error occurs should you rollback to the state the db was before you started, or is it ok to retry?

Resources