Vous êtes sur la page 1sur 6

8no"ledge 4pert for PL/SQL 9.:.

: $#ceptions Propagation

A PL/SQL program is an anonymous block, a procedure, or a function. This program, or _highest le!el_ block, can call other procedures or functions, or nest an anonymous block "ithin that block. So at any gi!en point in e#ecution, there might be se!eral layers of PL/SQL blocks nested "ithin other blocks. $ach PL/SQL block can ha!e its o"n e#ception section, or it can be totally !oid of e#ception handlers. To determine the appropriate e#ception handling beha!ior, PL/SQL follo"s rules regarding% Scope The PL/SQL block or blocks in "hich an e#ception can be raised and handled.

Propagation The "ay in "hich an e#ception is passed back through enclosing blocks until it is handled or is resol!ed to be an unhandled e#ception

Scope of an Exception
The scope of an e#ception is that portion of the code "hich is _co!ered_ by that e#ception. An e#ception co!ers a block of code if it can be raised in that block. The follo"ing list sho"s the scope for each of the different kinds of e#ceptions% Exception Type &amed system e#ception &amed programmer defined e#ception *nnamed system e#ception *nnamed programmer defined e#ception Description of Scope These e#ceptions are globally a!ailable because they are not declared in or confined to any particular block of code. 'ou can raise and handle a named system e#ception in any block. These e#ceptions can only be raised and handled in the e#ecution and e#ception sections of the block in "hich they are declared (and all nested blocks). These e#ceptions can be handled in any PL/SQL e#ception section !ia the +,$& -T,$.S section. /f they are assigned a name, then the scope of that name is the same as that of the named programmer defined e#ception. This e#ception is only defined in the call to .A/S$_APPL/0AT/-&_$..-. and then is passed back to the calling program.

Scope of Programmer-Defined Exception 0onsider the follo"ing e#ample of the e#ception o!erdue_balance declared in procedure check_account. The scope of that e#ception is the check_account procedure, and nothing else% P.-0$1*.$ check_account (company_id_in /& &*23$.) /S o!erdue_balance $40$PT/-&5 3$6/& ... e#ecutable statements ... L--P ... /7 ... T,$& .A/S$ o!erdue_balance5 $&1 /75 $&1 L--P5 $40$PT/-& +,$& o!erdue_balance T,$& ... $&15 +e can .A/S$ the o!erdue_balance inside the check_account procedure, but "e cannot raise that e#ception from a

8no"ledge 4pert for PL/SQL 9.:.: $#ceptions Propagation

program that calls check_account. The follo"ing anonymous block "ill generate the associated compile error% 1$0LA.$ company_id &*23$. %; :<<5 3$6/& check_account (:<<)5 $40$PT/-& +,$& o!erdue_balance /= PL/SQL cannot resol!e this reference. =/ T,$& ... $&1 PLS <<><:% identifier ?-@$.1*$_3ALA&0$? must be declared5 The check_account procedure is a _black bo#_ as far as the anonymous block is concerned. Any identifiers_including e#ceptions_"hich are declared inside check_account are in!isible outside of that program. Raising Exceptions in Nested Blocks +hen you declare an e#ception in a block, it is local to that block, but global to all the blocks "hich are enclosed by that block (nested blocks). /n the !ersion of check_account sho"n in the follo"ing e#ample, the procedure contains an anonymous subblock "hich also raises the o!erdue_balance. 3ecause the subblock is enclosed by the procedure block, PL/SQL can resol!e the reference to that e#ception% P.-0$1*.$ check_account (company_id_in /& &*23$.) /S o!erdue_balance $40$PT/-&5 3$6/& ... e#ecutable statements ... Start of sub block inside check_account 3$6/& ... statements "ithin sub block ... .A/S$ o!erdue_balance5 $#ception raised in sub block. $&15 $nd of sub block inside check_account L--P ... /7 ... T,$& .A/S$ o!erdue_balance5 $&1 /75 $&1 L--P5

$#ception raised in main block.

$40$PT/-& +,$& o!erdue_balance T,$& ... $&155

$#ception handled in main block.

+hen the o!erdue_balance e#ception is raised in either the subblock or the main block, control is transferred immediately to the main block_the only e#ception section in the entire procedure. 3ecause o!erdue_balance "as declared for the "hole procedure, the name is kno"n throughout all subblocks. Overlapping Exception Names 'ou ne!er ha!e to declare a named system e#ception because they ha!e all been declared in the STA&1A.1 package, "hich is instantiated as soon as you run any PL/SQL code. -n the other hand, you can declare your o"n e#ceptions "ith the same name as a pre!iously defined system e#ception, as sho"n belo"%

$#ceptions Propagation

Page > :

8no"ledge 4pert for PL/SQL 9.:.: $#ceptions Propagation

1$0LA.$ no_data_found $40$PT/-&5 3$6/&5 This locally declared e#ception "ill take precedence o!er the system e#ception. As a result, the follo"ing e#ception handler "ill not trap an error caused by an implicit Auery that returns no ro"s% $40$PT/-& +,$& no_data_found T,$& ... $&155 This is 2' e#ception, not PL/SQLBs.

Q alifying Exception Names /f you "ant to name a local e#ception the same as a predefined e#ception and handle the latter in that same PL/SQL block, you need to use the dot notation on the predefined e#ception. This notation distinguishes bet"een the t"o and allo"s PL/SQL to find the handler for the predefined e#ception. 'ou can then handle the t"o different e#ceptions separately, or you can combine them in a single e#pression% $40$PT/-& +,$& no_data_found T,$& 132S_-*TP*T.P*T_L/&$ (B2y o"n local e#ceptionB)5 +,$& STA&1A.1.&-_1ATA_7-*&1 T,$& 132S_-*TP*T.P*T_L/&$ (BThe predefined e#ceptionB)5 $&155 or% $40$PT/-& +,$& no_data_found -. STA&1A.1.&-_1ATA_7-*&1 T,$& 132S_-*TP*T.P*T_L/&$ (B0ould not find the dataB)5 $&155 The best solution is to ne!er declare e#ceptions "ith the same name as a named system e#ception. Referencing D plicate Exceptions in Nested Blocks 'ou cannot declare the same e#ception more than once in a single block, but you can declare an e#ception in a nested block "ith the same name as that of an enclosing block. +hen you do this, the declaration local to that nested block takes precedence o!er the global e#ception. +hen you raise that e#ception, you are raising the local e#ception, "hich is a completely different e#ception from the outer e#ception, e!en though they share the same name. /n the follo"ing !ersion of check_account, the nested block contains its o"n declaration of the o!erdue_balance e#ception% : P.-0$1*.$ check_account (company_id_in /& &*23$.) > /S C /= 2ain block e#ception declaration =/ D o!erdue_balance $40$PT/-&5 E 3$6/& F ... e#ecutable statements ...
$#ceptions Propagation Page C

8no"ledge 4pert for PL/SQL 9.:.: $#ceptions Propagation

G H /= Start of sub block inside check_account =/ 9 1$0LA.$ :< /= Sub block e#ception declaration =/ :: o!erdue_balance $40$PT/-&5 :> 3$6/& :C ... statements "ithin sub block ... :D :E /= $#ception raised in sub block. =/ :F .A/S$ o!erdue_balance5 :G $&15 :H /= $nd of sub block inside check_account =/ :9 >< L--P >: ... >> /7 ... T,$& >C /= $#ception raised in main block. =/ >D .A/S$ o!erdue_balance5 >E $&1 /75 >F $&1 L--P5 >G >H $40$PT/-& >9 /= $#ception handled in main block. =/ C< +,$& o!erdue_balance C: T,$& C> 132S_-*TP*T.P*T_L/&$ (B3alance is o!erdue. Pay upIB)5 CC $&155 This program "ill compile "ithout error. $!en though the o!erdue_balance e#ception is declared t"ice, each declaration takes place in a different PL/SQL block, hence in a different scope. The procedure le!el o!erdue_balance is declared on line D. The e#ception of the same name for the nested block is declared on line ::. 7ollo"ing these declarations, there are t"o .A/S$ statements_one "ithin the nested block on line :F and one in the main body of the procedure on line >D. 7inally, there is Just a single e#ception section and one handler for o!erdue_balance on line C<. +hile the o!erdue_balance e#ception is declared in e!ery block in "hich it is raised, the e#ception handling beha!ior of check_account may not be as you "ould e#pect. +hat happens, for e#ample, "hen the .A/S$ statement on line :F e#ecutesK 1o you see this% B3alance is o!erdue. Pay upIB5 or this% -.A <FE<:% PL/SQL% unhandled user defined e#ception -.A FE:>% at ?*S$..0,$08_A00-*&T?, line &5 'ou "ill, in fact, ha!e raised an unhandled e#ception "hen you .A/S$ o!erdue_balance in the nested block because the nested block does not ha!e its o"n e#ception section. So, "hen the e#ception is raised on line :F, the nested block cannot handle the e#ception. /nstead, that e#ception (declared only in that nested block) is passed on to the enclosing block and PL/SQL tries to handle it there. As soon as control passes to the enclosing block, ho"e!er, the nested block terminates and all local identifiers are erased. This includes the e#ception "hich "as Just raised. /t is no longer defined and therefore cannot be handled in the outer block, e!en though it seems to ha!e a handler for precisely that e#ception. The enclosing block also doesn_t kno" anything about the local o!erdue_balance, only its o"n. And e!en though they appear to ha!e the same name, these e#ceptions are different e#ceptions as far as the compiler is concerned. As a result, the nested block o!erdue_balance e#ception goes unhandled.
$#ceptions Propagation Page D

8no"ledge 4pert for PL/SQL 9.:.: $#ceptions Propagation

The best "ay to a!oid this problem is to not use duplication of e#ception names. This only makes the code !ery hard to understand and follo". 3ut, if you insist on these o!erlapping names, you can take any of the follo"ing steps% .aise the procedure le!el o!erdue_balance e#ception "ithin the subblock if the enclosing block has a name (if it is a procedure or a function). 'ou can use dot notation to distinguish the local e#ception from its global counterpart as follo"s% .A/S$ check_account.o!erdue_balance55

2ake sure that the locally raised o!erdue_balance is handled by the main check_account e#ception section by including a +,$& -T,$.S clause to trap any e#ceptions not other"ise handled. .emo!e the local declaration of o!erdue_balance so this e#ception is declared only once in the program unit.

Propagation of an Exception
The scope rules for e#ceptions determine the block in "hich an e#ception can be raised. The rules for e#ception propagation address the "ay in "hich an e#ception is handled, once it has been raised. +hen an e#ception is raised, PL/SQL looks for an e#ception handler in the current block (anonymous block, procedure, or function) for this e#ception. /f it does not find a match, then PL/SQL propagates the e#ception to the enclosing block of that current block. PL/SQL then attempts to handle the e#ception by raising that e#ception once more in the enclosing block. /t continues to do this in each successi!e enclosing block until there are no more blocks in "hich to raise the e#ception. The diagram belo" illustrates propagation of e#ceptions through nested blocks%

+hen all blocks are e#hausted, PL/SQL returns an unhandled e#ception to the application en!ironment that e#ecuted the outermost PL/SQL block. An unhandled e#ception halts the e#ecution of the host program. -ne !ery direct conseAuence of this propagation method is that if PL/SQL cannot locate an e#ception handler in the current block for a local, programmer defined e#ception, the e#ception "ill not be handled at all. The e#ception is not recogniLed outside of the current block, so propagating to enclosing blocks "ill ne!er cause the e#ception to be handled (unless you use the blanket +,$& -T,$.S handler). Examples of t!e "ay Exceptions Propagate T!ro g! Enclosing Blocks /n the diagram belo", the e#ception raised in the inner block too_many_faults is handled by the ne#t enclosing block%

$#ceptions Propagation

Page E

8no"ledge 4pert for PL/SQL 9.:.: $#ceptions Propagation

The innermost block has an e#ception section, so PL/SQL first checks to see if the too_many_faults is handled in this section. 3ecause it "as not handled, PL/SQL closes that block and raises the too_many_faults e#ception in the enclosing block, &ested 3lock :. 0ontrol immediately passes to the e#ception section of &ested 3lock :. (The e#ecutable statements after &ested 3lock > are not e#ecuted.) PL/SQL scans the e#ception handlers and finds that too_many_faults is handled in this block, so the code for that handler is e#ecuted, after "hich control passes back to the main list_my_faults procedure. &otice that if the &-_1ATA_7-*&1 e#ception had been raised in the innermost block (&ested 3lock >), then the e#ception section for &ested 3lock > "ould ha!e handled the e#ception. Then control "ould pass back to &ested 3lock : and the e#ecutable statements "hich come after &ested 3lock > "ould be e#ecuted. /n the ne#t diagram, the e#ception raised in the inner block is handled by the outermost block.

The outermost block is the only one "ith an e#ception section, so "hen &ested 3lock > raises the too_many_faults e#ception, PL/SQL terminates e#ecution of that block and raises that e#ception in the enclosing block, &ested 3lock :. Again, this block has no e#ception section so PL/SQL immediately terminates &ested 3lock : and passes control to the outermost block (the list_my_faults procedure). This procedure does ha!e an e#ception section, so PL/SQL scans the e#ception handlers, finds a match for too_many_faults, e#ecutes the code for that handler, and then returns control to "hate!er program called list_my_faults.

$#ceptions Propagation

Page F

Vous aimerez peut-être aussi