code_junkie

ORA-04091: table [blah] is mutating, trigger/function may not see it

Nov 13th, 2011
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.78 KB | None | 0 0
  1. ORA-04091: table SCMA.TBL1 is mutating, trigger/function may not see it
  2. ORA-06512: at "SCMA.TRG_T1_TBL1_COL1", line 4
  3. ORA-04088: error during execution of trigger 'SCMA.TRG_T1_TBL1_COL1'
  4.  
  5. create or replace TRIGGER TRG_T1_TBL1_COL1
  6. BEFORE INSERT OR UPDATE OF t1_appnt_evnt_id ON TBL1
  7. FOR EACH ROW
  8. WHEN (NEW.t1_prnt_t1_pk is not null)
  9. DECLARE
  10. v_reassign_count number(20);
  11. BEGIN
  12. select count(t1_pk) INTO v_reassign_count from TBL1
  13. where t1_appnt_evnt_id=:new.t1_appnt_evnt_id and t1_prnt_t1_pk is not null;
  14. IF (v_reassign_count > 0) THEN
  15. RAISE_APPLICATION_ERROR(-20013, 'Multiple reassignments not allowed');
  16. END IF;
  17. END;
  18.  
  19. dev> create or replace function f( a number, b number ) return number deterministic as
  20. 2 begin
  21. 3 if a is null then return 0-b; else return a; end if;
  22. 4 end;
  23.  
  24. CREATE UNIQUE INDEX my_index ON my_table
  25. ( t1_appnt_event, f( t1_prnt_t1_pk, primary_key_column) );
  26.  
  27. CREATE UNIQUE INDEX cappec_ccip_uniq_idx
  28. ON tbl1 (t1_appnt_event,
  29. CASE WHEN t1_prnt_t1_pk IS NOT NULL THEN 1 ELSE t1_pk END);
  30.  
  31. CREATE OR REPLACE PACKAGE trigger_pkg;
  32. PROCEDURE before_stmt_trigger;
  33. PROCEDURE for_each_row_trigger(row IN ROWID);
  34. PROCEDURE after_stmt_trigger;
  35. END trigger_pkg;
  36.  
  37. CREATE OR REPLACE PACKAGE BODY trigger_pkg AS
  38. TYPE rowid_tbl IS TABLE OF(ROWID);
  39. modified_rows rowid_tbl;
  40.  
  41. PROCEDURE before_stmt_trigger IS
  42. BEGIN
  43. modified_rows := rowid_tbl();
  44. END before_each_stmt_trigger;
  45.  
  46. PROCEDURE for_each_row_trigger(row IN ROWID) IS
  47. BEGIN
  48. modified_rows(modified_rows.COUNT) = row;
  49. END for_each_row_trigger;
  50.  
  51. PROCEDURE after_stmt_trigger IS
  52. BEGIN
  53. FOR i IN 1 .. modified_rows.COUNT LOOP
  54. SELECT ... INTO ... FROM the_table WHERE rowid = modified_rows(i);
  55. -- do whatever you want to
  56. END LOOP;
  57. END after_each_stmt_trigger;
  58. END trigger_pkg;
  59.  
  60. CREATE OR REPLACE TRIGGER before_stmt_trigger BEFORE INSERT OR UPDATE ON mytable AS
  61. BEGIN
  62. trigger_pkg.before_stmt_trigger;
  63. END;
  64.  
  65. CREATE OR REPLACE TRIGGER after_stmt_trigger AFTER INSERT OR UPDATE ON mytable AS
  66. BEGIN
  67. trigger_pkg.after_stmt_trigger;
  68. END;
  69.  
  70. CREATE OR REPLACE TRIGGER for_each_row_trigger
  71. BEFORE INSERT OR UPDATE ON mytable
  72. WHEN (new.mycolumn IS NOT NULL) AS
  73. BEGIN
  74. trigger_pkg.for_each_row_trigger(:new.rowid);
  75. END;
  76.  
  77. Session 1> update tbl1
  78. set t1_appnt_evnt_id=123
  79. where t1_prnt_t1_pk =456;
  80. /* OK, trigger sees count of 0 */
  81.  
  82. Session 2> update tbl1
  83. set t1_appnt_evnt_id=123
  84. where t1_prnt_t1_pk =789;
  85. /* OK, trigger sees count of 0 because
  86. session 1 hasn't committed yet */
  87.  
  88. Session 1> commit;
  89.  
  90. Session 2> commit;
  91.  
  92. select appe_id
  93. into v_app_id
  94. from parent_table
  95. where appe_id = :new.t1_appnt_evnt_id
  96. for update;
Add Comment
Please, Sign In to add comment