I am currently having a block like below. So with this we set autocommit off and and do a commit/rollback. Now at the rollback line , we are getting a failure saying that "rollback ineffective with AutoCommit enabled at" . How could this happen since AutoCommit was indeed disabled by the begin_work. This problem was not there for a long time and it is suddenly occuring.
On investigating further , i found that the update_sql1 created a #temp table , and update_sql2,update_sql3,update_sql4 query the same #temp table, and are failing with Invalid object name '#temp' error. Immediately control flows to if($#) where $dbh->{AutoCommit} is set to 1. First of all its really wierd as to why update_sql2 and onwards count not find object #temp , when update_sql1 was indeed successful.
Any pointers ?
====
$dbh->db_Main()->begin_work;
eval {
$dbh->do($update_sql1);
$dbh->do($update_sql2);
$dbh->do($update_sql3);
$dbh->do($update_sql4);
$dbh->commit;
1;
}
if ($#) {
$logger->info("inside catch");
$logger->info("autocommit is $dbh->{AutoCommit}");
$dbh->rollback;
}
===
Here is the full error message
Issuing rollback() due to DESTROY without explicit disconnect() of DBD::ODBC::db handle ..
rollback ineffective with AutoCommit enabled ...
Under autocommit, the begin starts a transaction, which is automatically committed. You have to turn off AutoCommit to get a transaction.
Related
Need to handle a error while inserting records into table (Ecpg PostgreSQL), but job should not abort/commit/rollback if any duplicate record (Primary Key).Job should skip and continue for next.
Note:SQL_CODE = sqlca.sqlcode
if ( SQL_CODE == -403 ) Other Way (sqlca.sqlcode == ECPG_DUPLICATE_KEY)
{
Log_error_tab();
}
else if ( SQL_CODE != SQL_SUCCESS )
{
Job_fail();
}
If i will handle as above its handling the error by calling function Log_error_tab(),but its failing in next DML operation with error "sqlerrm.sqlerrmc: current transaction is aborted, commands ignored until end of transaction block on line (sqlstate: 25P02)"
That's the way PostgreSQL works: if a statement inside a transaction fails, the transaction is aborted, and all subsequent statements will fail with that message.
So you should EXEC SQL ROLLBACK before you attempt your next SQL statement.
If you don't want to rollback the whole transaction, you can set a savepoint prior to executing the “dangerous” SQL statement:
SAVEPOINT sname
Then, when the critical part is over, you can release the savepoint:
RELEASE SAVEPOINT sname
If you hit an error, you can roll back everything since the savepoint was set, including the error, with
ROLLBACK TO SAVEPOINT sname
Note that you should use savepoints sparingly if you want decent performance.
I've got an insert/update trigger set up which prevents an employee from existing in two tables at the same time. It works fine with catching illegal insertions/updates but i'm also getting another error report when testing the trigger with illegal insertions/updates.
Here's my code:
CREATE OR REPLACE TRIGGER check_foobar
BEFORE INSERT OR UPDATE OF VarX ON FOOBAR
FOR EACH ROW
DECLARE
counter NUMBER(38);
BEGIN
SELECT count(*)
INTO counter
FROM BARFOO
WHERE VarX = :NEW.VarX
GROUP BY VarX;
IF counter > 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'This is an illegal insertion/update');
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN DBMS_OUTPUT.PUT_LINE('TEST');
END;
/
And the errors ORA-06512 and ORA-04088 i'm not sure of:
SQL> INSERT INTO DRIVER VALUES(2, 10345, 'AVAILABLE');
Error starting at line : 26 File #test.sql
In command -
INSERT INTO FOOBAR VALUES(2)
Error report -
ORA-20001: This is an illegal insertion/update
ORA-06512: at "HR.CHECK_FOOBAR", line 11
ORA-04088: error during execution of trigger 'HR.CHECK_FOOBAR'
When i add an exception handler for the select statement my trigger stops working properly and the illegal insertion isn't prevented. But the execution error is prevented.
UPDATE: I've added a group by and an exception to the trigger, so now the trigger still works with an exception handler but the errors ORA-06512 and ORA-04088 are still coming up with the illegal insertion/update.
Line 11 mentioned in the error is
GROUP BY VarX;
Any advice would be much appreciated.
There is no problem here, it is working as expected.
Error starting at line : 26 File #test.sql
In command -
INSERT INTO FOOBAR VALUES(2)
This is referring to the line in your script where you have the INSERT statement. It's telling you an exception was raised at this point.
Error report -
This is showing the error stack:
ORA-20001: This is an illegal insertion/update
This is the actual exception that was raised.
ORA-06512: at "HR.CHECK_FOOBAR", line 11
ORA-04088: error during execution of trigger 'HR.CHECK_FOOBAR'
These are additional messages just to tell you where the exception was originally raised, in this case, in your trigger on line 11, where the RAISE_APPLICATION_ERROR is, as you might expect. Note that line numbers for triggers refer to the executable portion of the trigger, so in your case the DECLARE is line 1.
The ORA-04088 error means that the trigger has an un-handled exception. You are raising a application error but then not handling it. You need to handle this exception as per below.
CREATE OR REPLACE TRIGGER check_foobar
BEFORE INSERT OR UPDATE OF VarX ON FOOBAR
FOR EACH ROW
DECLARE
counter NUMBER(38);
BEGIN
SELECT count(*)
INTO counter
FROM BARFOO
WHERE VarX = :NEW.VarX
GROUP BY VarX;
IF counter > 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'This is an illegal insertion/update');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('TEST');
WHEN OTHERS THEN
IF SQLCODE = -20001 THEN
-- do some logging
RAISE;
ELSE
-- do some logging and any other actions you feel are needed. Then depending on needs you can raise or not.
END IF;
END;
/
I notice when this error is triggered within the stored procedure it returns 50,000. Is there a way to modify this to say 50,999 so the front-end app can specifically pick the error up and not confuse it with anything else.
RAISERROR('Client already has an Active Visit!',16,1)
As per the documentation of RAISERROR (Transact-SQL):
The message is returned as a server error message to the calling
application or to an associated CATCH block of a TRY…CATCH construct.
New applications should use THROW instead.
Emphasis mine. (THROW (Transact-SQL))
I don't know what your SQL statement looks like, but, instead you can therefore do something like:
BEGIN TRY
--Your INSERT statement
SELECT 0/0; --Causes an error
END TRY
BEGIN CATCH
THROW 50099, 'Client already has an Active Visit!',1;
END CATCH
With RAISEERROR, if you use message as the first parameter then you can't specify an error ID and it is implicitly 50000. However, you can create a custom message with parameters and pass your code there. ie:
RAISERROR('Client already has an Active Visit! - Specific Err.Number:[%d]',16,1, 50999)
Also Try\Catch is the suggested method for new applications.
You need to specify the first parameter of the raiseerror function, like so:
--configure the error message
sp_addmessage #msgnum = 50999,
#severity = 16,
#msgtext = N'Client %s already has an Active Visit!';
GO
-- throw error
RAISERROR (50999, -- Message id.
16, -- Severity,
1, -- State,
N'123456789'); -- First argument supplies the string.
GO
Output will be
Msg 50999, Level 16, State 1, Line 8
Client 123456789 already has an Active Visit!
If you don't specify the error number, the raiserror will be assumed to be 50000. Documentation here...
While inserting into MSSQL using PHP PDO Dblib I am having this error
exit signal Segmentation fault in apache error log
When I checked the free tds log the error is
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION
However this is happening for a particular case only that is when I have string for a float data type. Below is my code:
$conn = new PDO('dblib:host=hostname;dbname=mydbname', 'user', 'password');
$conn->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$conn->beginTransaction();
$query = 'INSERT INTO [TestTable] ([RecordNo], [Paymode], [VATVALUE])
VALUES (:RecordNo, :Paymode, :VATVALUE)';
$stmt = $conn->prepare($query);
try {
$stmt->execute( [":VATVALUE" => "158.4'", ":Paymode" => "CREDIT",
":RecordNo" => "ABC-312735"] );
$conn->commit();
} catch(PDOException $e) {
$conn->rollback();
}
Please note the vat value which I have set it as
158.4'
for replicating the error. However when I remove the transaction statements then it is throwing the proper error i.e.
Error converting data type varchar to float
Interestingly the beginTransaction() is working perfectly if I specify a wrong column name in the statement. The transaction is not working only for this conversion error and throwing signal segmentation fault error.
I am using PHP 7.0 in ubuntu 16.04. Wondering why rollback working fine in all cases like wrong column names or table name but not in the conversion case.
There are errors in SQL Server which will automatically roll back your transaction, and it's an error to attempt a rollback after that. Instead of
$conn->rollback();
try executing the batch
if ##trancount>0 rollback;
I don't know PHP but perhaps something like:
$conn->prepare("if ##trancount>0 rollback;")->execute();
Hi i have the following stored procedure...
CREATE OR REPLACE PROCEDURE DB.INSERTGOOD
(
--CapRefCursor OUT Cap_Cur_Pkg.CapCur,
p_APPLIANT_TLT IN GOODRIGHT_MANUAL.APPLICANT_TLT%TYPE,
p_APPLIANT_NME IN GOODRIGHT_MANUAL.APPLICANT_NME%TYPE,
p_APPLICANT_SURNME IN GOODRIGHT_MANUAL.APPLICANT_SURNME%TYPE,
p_COMPANY_NME IN GOODRIGHT_MANUAL.COMPANY_NME%TYPE,
p_ID_CDE IN GOODRIGHT_MANUAL.ID_CDE%TYPE,
p_ADD1 IN GOODRIGHT_MANUAL.ADD1%TYPE,
p_OCCUPATION1 IN GOODRIGHT_MANUAL.OCCUPATION1%TYPE,
p_REMARK1 IN GOODRIGHT_MANUAL.REMARK1%TYPE,
p_SOURCE IN GOODRIGHT_MANUAL.SOURCE%TYPE
)
IS
BEGIN
INSERT
INTO GOODRIGHT_MANUAL
(
SEQ_ID,
APPLICANT_TLT,
APPLICANT_NME,
APPLICANT_SURNME,
COMPANY_NME,
ID_CDE,
ADD1,
OCCUPATION1,
REMARK1,
GOODRIGHT_MANUAL.SOURCE
)
VALUES
(
goodright_seq.nextval,
p_APPLIANT_TLT,
p_APPLIANT_NME,
p_APPLICANT_SURNME,
p_COMPANY_NME,
lower(p_ID_CDE),
p_ADD1,
p_OCCUPATION1,
p_REMARK1,
p_SOURCE
);
COMMIT;
-- OPEN CapRefCursor FOR
--select 'True';
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN ROLLBACK;
-- select 'False';
END DB.INSERTGOOD;
/
Here i want to return a string TRUE if the transaction commit successfully and FALSE if transaction rollback.
An Output Variable CapRefCursor is defined but i don't know how to assign true false to that variable and return it.
Thanks in advance.
You have defined a procedure with no OUT parameter, therefore it can not return anything.
You have several options to return success information:
define a function instead of a procedure. A function always returns something, you can define a string to be returned as VARCHAR2 for example in your case.
add an OUT parameter to the procedure. OUT parameters are logically equivalent to function returned values. You can have more than one such parameters.
modify your logic so that the procedure returns nothing when it works and throws an exception when it fails.
I would go with solution (3) because:
solution (1) and (2) are bug-prone: you may easily forget to check the return code in which case your program will continue as if no error had happened in case of failure. Ignoring error is the surest way to transform a benign bug into a monstrosity because it can lead to extensive data corruption. Your program may go on for months without you realising that it is intermittently failing!
Exception logic is designed to overcome this problem and makes the code cleaner and clearer. No more ugly if-then-else after every single procedure call. For this reason alone, solutions (1) and (2) are considered code-smell (anti-pattern) when used extensively to return success/error state.
Less code is involved, just remove the EXCEPTION block and let the error propagate.
procedures that fail will undo their work without rolling back the whole transaction if you let the exception propagate (and don't issue intermediate commits).
Finally, in general you should not control transaction logic in your sub-procedures. A procedure that does a single insert is probably part of a larger transaction. You should not let this procedure either commit or rollback. Your calling code, be it PL/SQL, GUI or script should decide if the transaction should move forward and complete or be rolled back.