Nhibernate TooManyRowsAffectedException Oracle - oracle

There is a trigger on a table that periodically creates an insert and throws the TooManyRowsAffectedException. In Sql server, we can set the trigger to NoCount to solve the issue. Any ideas in Oracle?
FluentNHibernate 2.12
.net 4.7.2
Oracle 11g

I think you are talking about two different things:
SET NOCOUNT ON
Stops the message that shows the count of the number of rows affected
by a Transact-SQL statement or stored procedure from being returned as
part of the result set. When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
I guess you are talking about the exception Too_Many_Rows in Oracle, as the TooManyRowsAffectedException of Hibernate indicates that more rows were affected then we were expecting to be. Typically indicates presence of duplicate "PK" values in the given table.
The TOO_MANY_ROWS Exception (ORA-01422) occurs when a SELECT INTO
statement returns more than one row.
An exception in Oracle is handled within a PL/SQL program into the exception section, which its counterpart in SQL Server would be the TRY CATCH.
When a program in Oracle contains an exception block, you can control the output of one of many specific errors by changing the outcome of them, thereby you can control what the program should do when an error happens.
An exception is basically a logical expression that answers a simple question: when an error happens what do you do with it.
exception
when ... then ...
Let me show you an example
SQL> create table t ( c1 number , c2 number ) ;
Table created.
SQL> alter table t add primary key (c1) ;
Table altered.
SQL> set timing off
SQL> declare
begin
insert into t values ( 1 , 1 );
commit ;
insert into t values ( 1 , 2 );
commit;
exception
when dup_val_on_index then null;
when others then raise;
end;
/
PL/SQL procedure successfully completed.
SQL> select * from t ;
C1 C2
---------- ----------
1 1
As you can see above in that example, I just controlled the exception dup_val_on_index to prevent the program to throw an error. I could have done the same for a too_many_rows exception.
Basically, if you want to ignore the exception, you can change the code in your trigger to avoid that when the exception happens an error is raised. You can also disable the trigger, but I guess that might be not an option.
You only need to realise that both things are different. SET NOCOUNT ON is preventing message of affected rows to be delivered to the client program. An exception in Oracle PL/SQL is used to control and handling a specific error.

Related

Error while creating trigger on table in Oracle

I am creating a trigger for inserting incremental ID's in my table. But while creating I am getting below error
An error occurred while processing a recursive SQL statement
(a statement applying to internal dictionary tables).
ORA-00604: error occurred at recursive SQL level 1
ORA-01654: unable to extend index SYS.I_TRIGGERCOL1 by 64 in tablespace SYSTEM
Here is my trigger query.
create or replace TRIGGER TGR_IPCOLO_BIL
BEFORE INSERT ON ipcolo_ipfee_calc_bil
for each row
begin
IF INSERTING THEN
IF :NEW."ID" IS NULL THEN
select SEQ_IPCOLO_IPFEE_BIL.nextval into :NEW."ID" from dual;
end if;
END IF;
end;
That error sounds pretty bad (I never saw it before) ... internal dictionary tables?! What is error code? ORA-xxxxx?
Meanwhile, trigger can be simplified to this:
create or replace trigger trg_ipcolo_bil
before insert on ipcolo_ipfee_calc_bil
for each row
begin
:new.id := nvl(:new.id, seq_ipolo_ipfee_bil.nextval);
end;
/
You don't have to check if inserting; what else could it be, if it fires before insert? Also, you don't need select ... into - use sequence directly. nvl makes sure you won't overwrite id if you provided it.
Also, consider using identity column instead, if your database version supports it.

Does Oracle support RETURNING in an SQL statement?

PostgreSQL supports a RETURNING clause, for instance as in
UPDATE some_table SET x = 'whatever' WHERE conditions RETURNING x, y, z
and MSSQL supports a variant of that syntax with the OUTPUT clause.
However Oracle "RETURNING INTO" seems intended to placing values in variables, from within the context of a stored procedure.
Is there a way to have an SQL equivalent to the one above that would work in Oracle, without involving a stored procedure ?
Note: I am looking for a pure-SQL solution if there exists one, not one that is language-specific, or would require special handling in the code. The actual SQL is dynamic, the code that makes the call is database-agnostic, with only the SQL being adapted.
Oracle does not directly support using the DML returning clause in a SELECT statement, but you can kind of fake that behavior by using a WITH function. Although the below code uses PL/SQL, the statement is still a pure SQL statement and can run anywhere a regular SELECT statement can run.
SQL> create table some_table(x varchar2(100), y number);
Table created.
SQL> insert into some_table values('something', 1);
1 row created.
SQL> commit;
Commit complete.
SQL> with function update_and_return return number is
2 v_y number;
3 --Necessary to avoid: ORA-14551: cannot perform a DML operation inside a query
4 pragma autonomous_transaction;
5 begin
6 update some_table set x = 'whatever' returning y into v_y;
7 --Necessary to avoid: ORA-06519: active autonomous transaction detected and rolled back
8 commit;
9 return v_y;
10 end;
11 select update_and_return from dual;
12 /
UPDATE_AND_RETURN
-----------------
1
Unfortunately there are major limitations with this approach that may make it impractical for non-trivial cases:
The DML must be committed within the statement.
The WITH function syntax requires both client and server versions of 12.1 and above.
Returning multiple columns or rows will require more advanced features. Multiple rows will require the function to return a collection, and the SELECT portion of the statement will have to use the TABLE function. Multiple columns will require a new type for each different result set. If you're lucky, you can use one of the built-in types, like SYS.ODCIVARCHAR2LIST. Otherwise you may need to create your own custom types.
You can do it in SQL, not need to pl/sql, and this depends on your tool and/or language. Here's an example in sqlplus:
SQL> create table t0 as select * from dual;
Table created.
SQL> var a varchar2(2)
SQL> update t0 set dummy='v' returning dummy into :a;
1 row updated.
SQL> print a
A
--------------------------------
v

A unhandled exception in a "after create" trigger preventing create

I have an AFTER CREATE trigger on my schema that raises an exception; I'm trying to create a table. I understand that an unhandled exception could cause the query/operation/transaction (I couldn't find suitable word for this case) to terminate. But, when the exception is raised after creating the table, shouldn't the table already be created by then?
When creating a table after successful triggering it throws error an error:
create table test(testcol number);
Error:
SQL Error: ORA-00604: error occurred at recursive SQL level 1
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at line 4
Trigger:
create or replace trigger ddl_trig_2812
after create
on schema
declare
eirit exception;
begin
raise eirit;
end;
/
From the documentation:
In most cases, if a trigger runs a statement that raises an exception, and the exception is not handled by an exception handler, then the database rolls back the effects of both the trigger and its triggering statement.
It doesn't just cause it to terminate, as your question suggests. Your unhandled exception is causing the triggering statement - i.e. the create table - to be rolled back. When talking about DDL statements:
An implicit COMMIT occurs immediately before the database executes a DDL statement and a COMMIT or ROLLBACK occurs immediately afterward. In the preceding example, ... [if] the ALTER TABLE statement succeeds, then the database commits this statement; otherwise, the database rolls back this statement. ...
So this is expected behaviour.
The transaction begins with CREATE TABLE; then the AFTER CREATE trigger fires and raises an exception, i.e. table definition isn't "committed" into data dictionary tables (such as USER_TABLES, USER_TAB_COLUMNS, ...) but "rolled-back".
So - no, CREATE TABLE process hasn't been finished properly and you can't use that table as it isn't created because its creation was prevented by a trigger.
One good illustration to verify this would be to check if the table actually exists within the trigger.
Lets say you RAISE from the EXCEPTION block and query DBA_OBJECTS to see if object exists.
SQL> create or replace trigger ddl_trig_2812
2 after create
3 on schema
4 declare
5 v_table_name DBA_OBJECTS.OBJECT_NAME%TYPE;
6 eirit exception;
7 begin
8 select object_name into v_table_name from DBA_OBJECTS where object_name = 'ATEST';
9 raise eirit;
10 EXCEPTION
11 WHEN OTHERS THEN
12 DBMS_OUTPUT.PUT_LINE( 'TABLE CREATED '|| v_table_name );
13 RAISE;
14 END;
15
16 /
Trigger created.
Now, Lets create the table.
SQL> set serveroutput on;
SQL> create table atest ( a number);
TABLE CREATED ATEST
create table atest ( a number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at line 10
Although exception was raised, the table exists in the data dictionary as you can see above the message displayed from dbms_output.
Now, if we check whether the table exists,
SQL> select * from atest;
select * from atest
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select object_name from DBA_OBJECTS where object_name = 'ATEST'
2 ;
no rows selected
It means, Oracle changes the data dictionary in the DDL triggers but rollbacks the transaction if error occurs in the trigger.

ORA 54 resouce busy error

I have a job running in production which abends randomnly with the error ORA 54. When I checked the code, I could see that the presence of NOWAIT is causing the issue. Now I decided to test it and wrote an anonymous block as follows.
declare
cursor c1 is
select * from table where column_1=2 and column_2=2 and column_3=6
for update of column_4 nowait;
record_locked exception;
pragma exception_init (record_locked, -54);
begin
begin
open c1;
exception
when record_locked then
dbms_output.put_line('Faced a locked record. Waiting for 2 minutes..');
dbms_lock.sleep(120);
open c1;
end;
exception
when others then
dbms_output.put_line('Exception Occured '||SQLCODE||SQLERRM);
end;
I opened one session and ran the below query
select * from table
where column_1=2 and column_2=2 and column_3=6
for update of column_4 nowait;
I didn't commit or rollback and kept the session open. Now I ran the above anonymous block in another session. After waiting for 2 minutes, it failed with ORA 54 error. So my assumption is correct I believe.
Now the thing is when I ran the entire job code containing the first anonymous block in test environment in the same manner, it waited long for the locked records without abending. When I released the lock by rolling back, it updated the records and completed successfully.
I wish to know why?
You get different results from test and production because your table contents are different. Your test table doesn't contain any rows that match the where clause, therefore your sessions don't block each other.
Try adding at least one row to your test table that matches the criterion, and you should get the same results as in production.

Oracle - procedure related query

I am writing the below queries in oracle:
DBMS_OUTPUT.....'Ashish'
Select col1 into val1 from tab_1
DBMS_OUTPUT.....'Ubale'
when I run this procedure I get the output as "Ashish" only why?
also what will be the value of v_val1 variable
Note: the table does not contain any records
Since the table is empty, the "select into" statement will raise the NO_DATA_FOUND exception. That's why you don't get the second message. val1 will have the same value as before the select - i.e. null if you didn't previously assign a value.
The fact that you don't know you got the NO_DATA_FOUND exception suggests that you have made one of the biggest errors PL/SQL developers ever make:
EXCEPTION
-- Never do this in real code!!!
WHEN OTHERS THEN NULL;
END;
Did you get error? If the table doesn't have rows in it. You might get no_data_found exception.
By the way, where is your entire code?

Resources