Skip to Main Content
  • Questions
  • Oracle 18c DBMS_MVIEW.REFRESH_DEPENDENT "number_of_failures" OUT parameter is not returning value

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Wondu.

Asked: September 29, 2020 - 4:11 pm UTC

Last updated: September 30, 2020 - 9:35 am UTC

Version: Oracle 18c

Viewed 1000+ times

You Asked

We are using Oracle 18c and when I use DBMS_MVIEW.REFRESH_DEPENDENT procedure, "number_of_failures" OUT parameter is not returning any value. It is failing as I manage to catch the error in the exception. Any idea please? Is it returning number_of_failures on earlier oracle versions?

select *
from v$version;


BANNER BANNER_FULL BANNER_LEGACY CON_ID
-------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ----------
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production 0
Version 18.5.1.0.0


set serverout on

DECLARE

   n_failures NUMBER(12):=0;

BEGIN

  dbms_mview.refresh_dependent(number_of_failures => n_failures,

                                   list => 'MV_TABLE1',

                                   atomic_refresh => TRUE,

                                   nested => TRUE);

   dbms_output.put_line('Number of failures: '||n_failures);                                                                

EXCEPTION

  WHEN

    OTHERS THEN

     dbms_output.put_line('Error: '||SQLERRM||', Number of failures in EXCEPTION: '||n_failures);

END;

/


Error: ORA-12008: error in materialized view or zonemap refresh path
ORA-01427: single-row subquery returns more than one row, Number of failures in EXCEPTION: 0


PL/SQL procedure successfully completed.

and Chris said...

The whole call has failed when you get this exception. So the value of number_of_failures is kinda irrelevant because nothing's worked!

If you share a test case (create table, create MVs, insert into, etc.) showing the problem we can help you figure out why you're getting this exception.

Rating

  (2 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

DBMS_MVIEW.REFRESH_DEPENDENT procedure number_of_failures OUT parameter issue on Oracle 18c

A reader, September 29, 2020 - 6:12 pm UTC

Hi Chris, Thank you for the prompt reply! I created an example to demonstrate the issue. Here is the URL link on LiveSQL and I also pasted the script below (let me know if you can't access it)
https://livesql.oracle.com/apex/f?p=590:43:11624330239868::NO:RP:P43_ID:234570232171845590041795861264537934038&success_msg=TmV3IFNjcmlwdCAmcXVvdDtkYm1zX212aWV3LnJlZnJlc2hfZGVwZW5kZW50X3Rl.,c3QmcXVvdDsgc2F2ZWQgd2l0aCAxNSBzdGF0ZW1lbnRz%2Fj4436TyJMbt6IUlrrWbwPeYeqhdSAk0ZhLqENrcArSEdSlxhdUF-_DU5mKbaQu6YbHRRDTTWQMHVF948E9Yrvw


-- raw script
/*
1. DROP table and materialized View
2. Create table
3. Add two records with unique ID column values
4. Create materialized view
5. Add primary key to materialized view
6. Run dbms_mview.refresh_dependent with SUCCESS
7. Display materialized view data after first refresh
8. Add additional record to table with duplicate ID that would error the materialized view when refreshed
9. Refresh the materialized view for the second time
10. Error thrown but no value for "number_of_failures" (even when repeating the process multiple times)
*/
set serverout on
--set feedback off
--#1
DECLARE
mv_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(mv_does_not_exist, -12003);
BEGIN
EXECUTE IMMEDIATE 'DROP MATERIALIZED VIEW MV_TABLE1';

EXCEPTION
WHEN mv_does_not_exist THEN
NULL;
END;
/
DECLARE
table_view_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_view_does_not_exist, -942);
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE T_SALARY CASCADE CONSTRAINTS PURGE';
EXCEPTION
WHEN table_view_does_not_exist THEN
NULL;
END;
/
--#2
CREATE TABLE t_salary (
id NUMBER,
salary NUMBER
);

--#3
INSERT INTO T_SALARY values(1,10000);
INSERT INTO T_SALARY values(2,20000);
COMMIT;

--#4
CREATE MATERIALIZED VIEW mv_table1 AS
SELECT *
FROM t_salary;
--#5
ALTER TABLE mv_table1 ADD CONSTRAINT pk_mv_table1 PRIMARY KEY ( id );
--#6
DECLARE
n_failures number;
BEGIN
dbms_output.put_line('Materialized view first refresh');
dbms_output.put_line('============== 111 =============');
dbms_mview.refresh_dependent(number_of_failures => n_failures,
list => 'MV_TABLE1'
,atomic_refresh => TRUE
,nested => TRUE
);
dbms_output.put_line('Number of failures: '||n_failures);
EXCEPTION
WHEN
OTHERS THEN
dbms_output.put_line('Error: '||SQLERRM||', Number of failures in EXCEPTION: '||n_failures);
END;
/

--#7
BEGIN
dbms_output.put_line('Materialized view data after first refresh');
dbms_output.put_line('==========================================');
END;
/

SELECT *
FROM mv_table1;
--#8
BEGIN
dbms_output.put_line('AFTER adding a duplicate record, the refrsh will raise error and refresh won''t happen successfully');
END;
/

INSERT INTO T_SALARY values(1,11000);

--#9
DECLARE
n_failures number:=0;
BEGIN
dbms_output.put_line('Materialized view second refresh');
dbms_output.put_line('============== 222 =============');
dbms_mview.refresh_dependent(number_of_failures => n_failures,
list => 'MV_TABLE1'
,atomic_refresh => TRUE
,nested => TRUE
);
dbms_output.put_line('Number of failures: '||n_failures);
EXCEPTION
WHEN
OTHERS THEN
dbms_output.put_line('Error: '||SQLERRM||', Number of failures in EXCEPTION: '||n_failures);
END;
/

--#10
/*
Output expected but NO value for number_of_failures (n_failures) in dbms_output line
PL/SQL procedure successfully completed.

Error: ORA-12008: error in materialized view or zonemap refresh path
ORA-01502: index 'PK_MV_TABLE1' or partition of such index is in unusable state, Number of failures in EXCEPTION:
*/

Chris Saxon
September 30, 2020 - 9:35 am UTC

The number_of_failures parameter has a complicated relationship with the other parameters.

If refresh_after_errors is false (the default), the call will stop, raising the exception that caused the error. number_of_failures will not be set.

If you set refresh_after_errors to true, you then need to consider the value for atomic_refresh. When this is true (the default), the process will stop if it encounters any failures. So there can only ever be one error, which is the one raised to you.

So if you set

refresh_after_errors  => true,
atomic_refresh => false

the process will continue when encountering an exception. For reasons I don't know, this still leaves number_of_failures at zero when there's a problem. To get this to report the count of errors, it seems you also need to set:

nested => true,
out_of_place => true, 


For example:

delete t_salary;
insert into t_salary values ( 1,11000 );
insert into t_salary values ( 1,11000 );
commit;

declare
  n_failures number := 0;
begin
  dbms_output.put_line ('Materialized view first refresh');
  dbms_output.put_line ('============== 111 =============');
  dbms_mview.refresh_dependent (
     number_of_failures => n_failures,
     list => 'MV_TABLE1',
     atomic_refresh => false,
     refresh_after_errors => true
  );

  dbms_output.put_line ('Number of failures: ' || n_failures);
exception
  when others then
    dbms_output.put_line ('Error: '
                          || sqlerrm
                          || ', Number of failures in EXCEPTION: '
                          || n_failures);
end;
/
Materialized view first refresh
============== 111 =============
Number of failures: 0

delete t_salary;
insert into t_salary values ( 1,11000 );
insert into t_salary values ( 1,11000 );
commit;

declare
  n_failures number := 0;
begin
  dbms_output.put_line ('Materialized view second refresh');
  dbms_output.put_line ('============== 222 =============');
  dbms_mview.refresh_dependent (
     number_of_failures => n_failures,
     list => 'MV_TABLE1',
     atomic_refresh => false,
     nested => true,
     out_of_place => true, 
     refresh_after_errors => true
  );

  dbms_output.put_line ('Number of failures: ' || n_failures);
exception
  when others then
    dbms_output.put_line ('Error: '
                          || sqlerrm
                          || ', Number of failures in EXCEPTION: '
                          || n_failures);
end;
/
Materialized view second refresh
============== 222 =============
Number of failures: 1


TL:DR Your current parameter settings mean that the refresh stops as soon as it hits an error, making the number_of_failures value moot - there can only be one which is the exception raised to you. Changing these allows the refresh to continue after hitting an error.

There may be a bug where number_of_failures is incorrectly reported when continuing past errors, this is something you need to take up with support.

PS - to share Live SQL scripts, you need to save them as a (private) script. The URL of your worksheet is specific to you - others can't access this.

Wondu, October 02, 2020 - 4:16 pm UTC

Thank you Chris!
I can't choose the "number_of_failures" counter over the actual error. It is best to get both. I raised SR with Oracle.

Thank you for the comments and alternative options

More to Explore

Design

New to good database design? Check out Chris Saxon's full fundamentals class.