Search code examples
sqldatabaseoracle-databaseoracle11guser-defined-types

Trigger on delete to avoid dangling references


I have a problem with the implementation of some triggers in Oracle.

I have two types "t_movie" and "t_video" defined as

CREATE TYPE t_movie AS OBJECT( 
name VARCHAR(20),
year INTEGER);

And

CREATE TYPE t_video AS OBJECT( 
type CHAR,
movie REF t_movie);

And I have also the associated tables

CREATE TABLE movies OF t_movie


CREATE TABLE videos OF t_video

If I delete a tuple from the table movies I will have some tuples in the other table with references to object that doesn't exist anymore. How can I avoid this? I thought that a trigger is necessary but I have no idea of how to implement it. Can anyone help me?

Thanks.

Edit:

I tried a trigger like this:

CREATE or REPLACE TRIGGER delete_movie_cascade 
  before delete on movies
  for each row
DECLARE
  movie_ref (REF t_movie);
BEGIN
  movie_ref = ref :old;
  dbms_output.put_line(deref(movie_ref).name);
  DELETE FROM videos WHERE movie = movie_ref;
END;

But, as expected, I get the error

Error(6,13): PLS-00103: Encountered the symbol "(" when expecting one of the following:     
constant exception <an identifier>    <a double-quoted delimited-identifier> table long 
double ref    char time timestamp interval date binary national character    nchar

Solution

  • The Oracle Objection Developer's documentation talks of preventing dangling refs:

    A REF column may be constrained with a REFERENTIAL constraint similar to the specification for foreign keys.

    Unfortunately the documentation doesn't provide an actual example of how do to this. The formatting of REFERENTIAL suggests that it is a keyword but that turns out to be a red herring.

    The solution really is to define an actual foreign key but using object references instead. So, taking the code you posted, change the definition of videos to this:

    CREATE TYPE t_video AS OBJECT( 
        type CHAR,
        movie REF t_movie
    );
    /
    CREATE TABLE videos OF t_video (
        foreign key (movie) references movies
    )
    /
    

    Now if you attempt to delete a movie which is referenced by a video Oracle will hurl ORA-02292: integrity constraint.


    Triggers are never the correct solution to enforcing foreign key constraints on regular or object tables. Because

    1. Querying the referencing table in a FOR EACH ROW trigger is inefficient, especially for multi-row deletions. Foreign keys are optimised for this task.
    2. The operation is unsafe in a multi-user environment, due to read committed isolation level. The trigger will pass our deletion while another user is adding a child row in a different session.
    3. Foreign key constraints are the standard. Deviating from the standard is bad practice, because it makes our code harder to maintain.
    4. Rules enforced in triggers don't appear in the data dictionary. This will confuse our co-workers, prevent reverse engineering of the data model and will deprive the optimiser of some useful information for deriving efficient execution plans.