Triggers and deferrable constraints – internal mechanism

Throughout the prevoius topic the essential question is – what is diagnostic area, where it is located and what mechanism Oracle uses to handle it.
Let’s check what is temp segment usage in our case. Maybe we’ll see something interested.

SQL> create table parent_t (x int);
Table created.
SQL> create table child_t (x int, y int);
Table created.
SQL> alter table parent_t add constraint parent_t_pk primary key (x);
Table altered.
SQL> alter table child_t add constraint child_t_fk
2 foreign key (y) references parent_t (x) deferrable;

Table altered.

At the beginning we will execute INSERT statement which should not generate any constraint violations for not-deferred constraint mode and check temp segment usage.

SQL> insert into child_t select rownum, null from dual connect by level  select sid from v$mystat where rownum = 1;

       SID
----------
       127

SQL> select x.segtype, x.extents, x.blocks, x.segfile#, x.segblk#
  2  from v$tempseg_usage x, v$session y
  3  where x.session_addr = y.saddr and y.sid = 127
  4  /

no rows selected

Well, nothing unexpected.

Now let’s set DEFERRED MODE and insert next 10000 rows:

SQL> set constraint all deferred;

Constraint set.

SQL> insert into child_t select rownum, null from dual connect by level  select x.segtype, x.extents, x.blocks, x.segfile#, x.segblk#
  2  from v$tempseg_usage x, v$session y
  3  where x.session_addr = y.saddr and y.sid = 127
  4  /

no rows selected

And finally let’s insert rows what force constraint violation – Y column value
will contain values from 0 to 3 inclusively and no one has parent key:

SQL> insert into child_t select rownum, mod(rownum,4) from dual connect by level  select x.segtype, x.extents, x.blocks, x.segfile#, x.segblk#, x.segrfno#
  2  from v$tempseg_usage x, v$session y
  3  where x.session_addr = y.saddr and y.sid = 127
  4  /

SEGTYPE      EXTENTS     BLOCKS   SEGFILE#    SEGBLK#   SEGRFNO#
--------- ---------- ---------- ---------- ---------- ----------
INDEX              1        128        202     255753          2

Now we see temporary segment usage and it’s type is INDEX.
Let’s dump sereval blocks from this structure.

SQL> alter system dump tempfile 2 block min 255753 block max 255760;

System altered.

We will see segment header and index leaf block:

Start dump data blocks tsn: 3 file#: 2 minblk 255753 maxblk 255880
buffer tsn: 3 rdba: 0x0083e709 (2/255753)
scn: 0x0875.7bd4b765 seq: 0x00 flg: 0x08 tail: 0xb7651000
frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED
  Extent Control Header
  -----------------------------------------------------------------
  Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 127
                  last map  0x00000000  #maps: 0      offset: 4128
      Highwater::  0x0083e70b  ext#: 0      blk#: 1      ext size: 127
  #blocks in seg. hdr's freelists: 0
  #blocks below: 1
  mapblk  0x00000000  offset: 0
                   Unlocked
     Map Header:: next  0x00000000  #extents: 1    obj#: 8644361 flag: 0x40000000
  Extent Map
  -----------------------------------------------------------------
   0x0083e70a  length: 127

  nfl = 1, nfb = 1 typ = 2 nxf = 0 ccnt = 0
  SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 


buffer tsn: 3 rdba: 0x0083e70a (2/255754)
scn: 0x0875.7bd4b7d3 seq: 0x00 flg: 0x08 tail: 0xb7d30600
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x0083e70a
 Object id on Block? Y
 seg/obj: 0x83e709  csc: 0x875.7bd4b764  itc: 2  flg: -  typ: 2 - INDEX
     fsl: 0  fnx: 0x0 ver: 0x01

 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x0006.02b.000050aa  0x00873a96.165c.02  ----    4  fsc 0x0000.00000000

Leaf block dump
===============
header address 242391644=0xe729a5c
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y
kdxconco 1
kdxcosdc 0
kdxconro 4
kdxcofbo 44=0x2c
kdxcofeo 7997=0x1f3d
kdxcoavs 7953
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 4
kdxlebksz 8032
row#0[8024] flag: ------, lock: 2, len=8, data:(4):  c4 09 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

Let’s now delete from the CHILD_T table all rows with y = 2 and check
if there will be any changes in this segment:

SQL> delete from child_t where y = 1;

2500 rows deleted.
row#0[8024] flag: ------, lock: 2, len=8, data:(4):  c4 09 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ---D--, lock: 2, len=9, data:(4):  01 00 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

OK, the record for key value = 1 has been marked as deleted.

Now go forward and create parent row for Y=2:

SQL> insert into parent_t values(2);

1 row created.

As we can see, now the row for key value = 2 has been marked as DELETED too:

row#0[8024] flag: ------, lock: 2, len=8, data:(4):  c4 09 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ---D--, lock: 2, len=9, data:(4):  01 00 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ---D--, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

And finally we can create parent row for Y=0 in AUTONOMOUS transaction:

SQL> declare
  2   pragma autonomous_transaction;
  3  begin
  4   insert into parent_t values(0);
  5   commit;
  6  end;
  7  /

PL/SQL procedure successfully completed.
row#0[8024] flag: ------, lock: 2, len=8, data:(4):  c4 09 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ---D--, lock: 2, len=9, data:(4):  01 00 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ---D--, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

No change – as we could reasonably expect.

Now touch rows in the table with Y=0, but don’t touch Y value itself:

SQL> update child_t set x = x where y = 0;

2500 rows updated.

No changes in the leaf block:

row#0[8024] flag: ------, lock: 2, len=8, data:(4):  c4 09 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ---D--, lock: 2, len=9, data:(4):  01 00 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ---D--, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

But if we touch Y column in UPDATE statement

SQL> update child_t set y = y where y = 0;

2500 rows updated.

we can see what the row with key value = 0 is marked as deleted – because
now the parent key exists:

row#0[8024] flag: ---D--, lock: 2, len=8, data:(4):  01 00 00 00
col 0; len 1; (1):  80
row#1[8015] flag: ---D--, lock: 2, len=9, data:(4):  01 00 00 00
col 0; len 2; (2):  c1 02
row#2[8006] flag: ---D--, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 03
row#3[7997] flag: ------, lock: 2, len=9, data:(4):  c4 09 00 00
col 0; len 2; (2):  c1 04

About dnikiforov

I'm writing here about everything what is in my interest - Java, Oracle, MySQL and other things. These are just remarks about things I'm working with, and if this helps you, guys, in your work - this makes me happy. ;)
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s