Oracle PL/SQL语言初级教程之异常处理

来源:互联网 发布:青云志坐骑进阶数据 编辑:程序博客网 时间:2024/05/21 07:51

Oracle PL/SQL语言初级教程之异常处理

 

PL/SQL处理异常不同于其他程式语言的错误管理方法,PL/SQL的异常处理机制和ADA很相似,有一个处理错误的全包含方法。当发生错误时,程式无条件转到异常处理部分,这就需要代码要很干净并把错误处理部分和程式的其他部分分开。oracle允许声明其他异常条件类型以扩展错误/异常处理。这种扩展使PL/SQL的异常处理很灵活。

 

  当一个运行时错误发生时,称为一个异常被抛出。PL/SQL程式编译时的错误不是能被处理得异常,只有在运行时的异常能被处理。在PL/SQL程式设计中异常的抛出和处理是很重要的内容。

 

  抛出异常

 

  由三种方式抛出异常

 

   . 通过PL/SQL运行时引擎

 

   . 使用RAISE语句

 

   . 调用RAISE_APPLICATION_ERROR存储过程

 

  当数据库或PL/SQL在运行时发生错误时,一个异常被PL/SQL运行时引擎自动抛出。异常也能够通过RAISE语句抛出

 

  RAISE exception_name;

 

  显式抛出异常是程式员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,他能够抛出任何任何异常。例如,您希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器,您只需简单的在程式中使用下面的语句: 中国网管论坛

 

  RAISE TIMEOUT_ON_RESOUCE;

 

  下面看一个订单输入系统,当库存小于订单时抛出一个inventory_too_low异常。

 

DECLARE

inventory_too_low EXCEPTION;

---其他声明语句

BEGIN

.

.

IF order_rec.qty>inventory_rec.qty THEN

RAISE inventory_too_low;

END IF

.

.

EXCEPTION

WHEN inventory_too_low THEN

order_rec.staus:='backordered';

replenish_inventory(inventory_nbr=>

inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty);

END;

 

 

  这里replenish_inventory是个触发器。

 

  处理异常

 

  PL/SQL程式块的异常部分包含了程式处理错误的代码,当异常被抛出时,一个异常陷阱就自动发生,程式控制离开执行部分转入异常部分,一旦程式进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法:

 

EXCEPTION DL.bitsCN.com网管软件下载

 WHEN exception_name THEN

  Code for handing exception_name

 [WHEN another_exception THEN

  Code for handing another_exception]

 [WHEN others THEN

  code for handing any other exception.]

 

 

  用户必须在单独的WHEN子串中为每个异常设计异常处理代码,WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时,控制转到异常部分,ORACLE查找当前异常相应的WHEN..THEN语句,捕获异常,THEN之后的代码被执行,假如错误陷阱代码只是退出相应的嵌套块,那么程式将继续执行内部块END后面的语句。假如没有找到相应的异常陷阱,那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。

 

EXCEPTION

 

 WHEN inventory_too_low THEN

  order_rec.staus:='backordered';

  replenish_inventory(inventory_nbr=>

  inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty);

 WHEN discontinued_item THEN

  --code for discontinued_item processing

 WHEN zero_divide THEN

  --code for zero_divide

 WHEN OTHERS THEN

  --code for any other exception

END;

 

 

  当异常抛出后,控制无条件转到异常部分,这就意味着控制不能回到异常发生的位置,当异常被处理和解决后,控制返回到上一层执行部分的下一条语句。

 

BEGIN

 DECLARE

  bad_credit;

 BEGIN

  RAISE bad_credit;

   --发生异常,控制转向;

 EXCEPTION

  WHEN bad_credit THEN

   dbms_output.put_line('bad_credit');

  END;

 

  --bad_credit异常处理后,控制转到这里

 EXCEPTION

  WHEN OTHERS THEN

   --控制不会从bad_credit异常转到这里

   --因为bad_credit已被处理

END;

 

 

  当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。 bitsCN.nET中国网管博客

 

BEGIN

 DECLARE ---内部块开始

  bad_credit;

 BEGIN

  RAISE bad_credit;

   --发生异常,控制转向;

  EXCEPTION

  WHEN ZERO_DIVIDE THEN --不能处理bad_credite异常

   dbms_output.put_line('divide by zero error');

  END --结束内部块

 

   --控制不能到达这里,因为异常没有解决;

   --异常部分

 

  EXCEPTION

  WHEN OTHERS THEN

   --由于bad_credit没有解决,控制将转到这里

END;

 

  异常传播

 

  没有处理的异常将沿检测异常调用程式传播到外面,当异常被处理并解决或到达程式最外层传播停止。

在声明部分抛出的异常将控制转到上一层的异常部分。

 

BEGIN

executable statements

BEGIN

today DATE:='SYADATE'; --ERRROR

BEGIN --内部块开始

dbms_output.put_line('this line will not execute');

www_bitscn_com

 

EXCEPTION

WHEN OTHERS THEN

--异常不会在这里处理

END;--内部块结束

 

EXCEPTION

WHEN OTHERS THEN

处理异常

END

 

  执行部分抛出的异常将首先传递到同一块的异常部分,假如在同一块的异常部分没有处理这个异常的处理器,那么异常将会传播到上一层的异常部分中,一直到最外层。

 

  在异常部分抛出的异常将控制转到上一层的异常部分。

 

  处理异常将停止异常的传播和解决。有时用户希望在错误发生时,程式仍然能执行一些动作,要达到这个目的,能够把希望执行的动作放在异常处理器中,然后执行不带参数的RAISE语句,RAISE语句将重新抛出出现的异常,允许他继续传播。

 

DECLARE

order_too_old EXCEPTION;

BEGIN

RAISE order_too_old;

EXCEPTION

WHEN order_too_old THEN

DECLARE

file_handle UTL_FILE.FILE_TYPE;

BEGIN

--open file

file_handle:=UTL_FILE.FOPEN

(location=>'/ora01/app/oracle/admin/test/utlsir'

,filename=>'error.log'

.open_mode=>'W');

--write error stack

UTL_FILE.PUT_LINE(filehandle,

DBMS_UTILITY.FORMAT_ERROR_STACK);

--write the call stack

UTL_FILE.PUT_LINE(filehandle,

DBMS_UTILITY.FORMAT_CALL_STACK);

--close error log

UTL_FILE.FCLOSE(file_handle);

RAISE; --re-raise the exception

END

END

 

  假如从FORMAT_XXX_STACK输出一个很大的值,那么使用DBMS_OUTPUTUTL_FILE显示错误或调用堆的异常部分自身也会抛出异常,这两个堆常规下最多能返回2000字节,但utl_file.put_line被限制在1000字节以内,而dbms_output.put_line限制在512字节内。假如使用前面的代码并且不允许这种可能性,那么在异常处理器中将抛出一个未处理的异常。

 

  GOTO语句不能用于将控制从执行部分传递到异常部分或反之。

 

  已命名异常

 

PL/SQL块的异常部分只有已命名的异常才能被WHEN子串处理,ORACLE包含了一系列已命名的异常,这些异常都声明在STANDARD包中,这些内建异常在这里就不一一讲述,有兴趣的读者能够查阅有关资料。

 

oracle 系统预定义异常表

 

Exception Oracle Error SQLCODE Value

ACCESS_INTO_NULL                 ORA-06530                               -6530

 

CASE_NOT_FOUND                   ORA-06592                              -6592

 

COLLECTION_IS_NULL                ORA-06531                             -6531

 

CURSOR_ALREADY_OPEN         ORA-06511                              -6511

 

DUP_VAL_ON_INDEX                  ORA-00001                             -1

 

INVALID_CURSOR                      ORA-01001                            -1001

 

INVALID_NUMBER                  ORA-01722                                -1722

 

LOGIN_DENIED                    ORA-01017                                -1017

 

NO_DATA_FOUND               ORA-01403                                   +100

 

NOT_LOGGED_ON              ORA-01012                                    -1012

 

PROGRAM_ERROR              ORA-06501                                   -6501

 

ROWTYPE_MISMATCH          ORA-06504                                    -6504

 

SELF_IS_NULL                  ORA-30625                                  -30625

 

STORAGE_ERROR               ORA-06500                                    -6500

 

SUBSCRIPT_BEYOND_COUNT      ORA-06533                                  -6533

 

SUBSCRIPT_OUTSIDE_LIMIT       ORA-06532                                  -6532

 

SYS_INVALID_ROWID            ORA-01410                                   -1410

 

TIMEOUT_ON_RESOURCE       ORA-00051                                     -51

 

TOO_MANY_ROWS              ORA-01422                                   -1422

 

VALUE_ERROR                   ORA-06502                                  -6502

 

ZERO_DIVIDE                   ORA-01476                                   -1476

Brief descriptions of the predefined exceptions follow:

 

Exception Raised when ...

ACCESS_INTO_NULL

Your program attempts to assign values to the attributes of an uninitialized (atomically null) object.

 

CASE_NOT_FOUND

None of the choices in the WHEN clauses of a CASE statement is selected, and there is no ELSE clause.

 

COLLECTION_IS_NULL

Your program attempts to apply collection methods other than EXISTS to an uninitialized (atomically null) nested table or varray, or the program attempts to assign values to the elements of an uninitialized nested table or varray.

 

CURSOR_ALREADY_OPEN

Your program attempts to open an alrea*** open cursor. A cursor must be closed before it can be reopened. A cursor FOR loop automatically opens the cursor to which it refers. So, your program cannot open that cursor inside the loop.

 

DUP_VAL_ON_INDEX

Your program attempts to store duplicate values in a database column that is constrained by a unique index.

 

INVALID_CURSOR

Your program attempts an illegal cursor operation such as closing an unopened cursor.

 

INVALID_NUMBER

In a SQL statement, the conversion of a character st*** into a number fails because the st*** does not represent a valid number. (In procedural statements, VALUE_ERROR is raised.) This exception is also raised when the LIMIT-clause expression in a bulk FETCH statement does not evaluate to a positive number.

 

LOGIN_DENIED

Your program attempts to log on to Oracle with an invalid username and/or password.

 

NO_DATA_FOUND

A SELECT INTO statement returns no rows, or your program references a deleted element in a nested table or an uninitialized element in an index-by table. SQL aggregate functions such as AVG and SUM always return a value or a null. So, a SELECT INTO statement that calls an aggregate function never raises NO_DATA_FOUND. The FETCH statement is expected to return no rows eventually, so when that happens, no exception is raised.

 

NOT_LOGGED_ON

Your program issues a database call without being connected to Oracle.

 

PROGRAM_ERROR

PL/SQL has an internal problem.

 

ROWTYPE_MISMATCH

The host cursor variable and PL/SQL cursor variable involved in an assignment have incompatible return types. For example, when an open host cursor variable is passed to a stored subprogram, the return types of the actual and formal parameters must be compatible.

 

SELF_IS_NULL

Your program attempts to call a MEMBER method on a null instance. That is, the built-in parameter SELF (which is always the first parameter passed to a MEMBER method) is null.

 

STORAGE_ERROR

PL/SQL runs out of memory or memory has been corrupted.

 

SUBSCRIPT_BEYOND_COUNT

Your program references a nested table or varray element using an index number larger than the number of elements in the collection.

 

SUBSCRIPT_OUTSIDE_LIMIT

Your program references a nested table or varray element using an index number (-1 for example) that is outside the legal range.

 

SYS_INVALID_ROWID

The conversion of a character st*** into a universal rowid fails because the character st*** does not represent a valid rowid.

 

TIMEOUT_ON_RESOURCE

A time-out occurs while Oracle is waiting for a resource.

 

TOO_MANY_ROWS

A SELECT INTO statement returns more than one row.

 

VALUE_ERROR

An arithmetic, conversion, truncation, or size-constraint error occurs. For example, when your program selects a column value into a character variable, if the value is longer than the declared length of the variable, PL/SQL aborts the assignment and raises VALUE_ERROR. In procedural statements, VALUE_ERROR is raised if the conversion of a character st*** into a number fails. (In SQL statements, INVALID_NUMBER is raised.)

 

ZERO_DIVIDE

Your program attempts to divide a number by zero.

 
原创粉丝点击