PL SQL 用户指南和参考第十章PLSQL对象类型_第1页
PL SQL 用户指南和参考第十章PLSQL对象类型_第2页
PL SQL 用户指南和参考第十章PLSQL对象类型_第3页
PL SQL 用户指南和参考第十章PLSQL对象类型_第4页
PL SQL 用户指南和参考第十章PLSQL对象类型_第5页
已阅读5页,还剩31页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第十章 PL/SQL对象类型一、抽象的角色抽象是对一个真实世界实体的高级描述或建模。它能排除掉无关的细节内容,使我们的日常生活更有条理。例如,驾驶一辆汽车时,我们是不需要知道它的发动机是如何工作的。由变速排档、方向盘、加速器和刹车组成的接口就能让我们有效地使用它。而其中每一项的详细信息对于日常驾驶来说并不重要。 抽象是编程的核心内容。例如,我们在隐藏一个复杂的算法时只要编写一个过程,然后为它传递参数就可以做到过程化抽象。如果需要改变具体的实现,换一个过程体即可。有了抽象后,那些调用过程的程序就不需要再修改了。 我们在指定变量的数据类型时,可以使用数据抽象。数据类型代表了对于想操作的数值的值集合

2、和操作符集合。比方说一个POSITIVE类型的变量,只能存放正整数,也只能用于加减乘等运算。使用这个变量时,我们不必知道PL/SQL是如何存储整数或是实现算术运算的。 对象类型是大多数编程语言内置类型的一个概括。PL/SQL提供了大量的标量类型和复合类型,每种类型都与一组预定义操作符相关联。标量类型(如 CHAR)是没有内部组成成分的。但复合类型(如RECORD)是有内部组成成分的,并且其中每一个局部都可以被独立操作。同RECORD类型一样,对象类型也是复合类型。但是,它的操作是用户自定义的,而不是预定义的。 目前,我们还不能用PL/SQL定义对象类型。它们必须用CREATE语句创立并存放在O

3、racle数据库中,这样才能被许多程序所共享。使用对象类型的程序称为客户端程序,它可以声明并操作对象,但并不要求知道对象类型是如何表现数据或实现操作。这就能够让我们分别编写程序和对象类型,即便是在改变了对象实现时也不会影响到程序。因此,对象类型既支持过程化和又支持数据抽象。 二、什么是对象类型对象类型是一个用户自定义复合类型,它封装了数据结构和操作这个数据结构的函数和过程。数据结构中的变量称为属性,函数和过程称为方法。通常,我们认为对象(如人、车、银行账户)都是有着属性和行为的。例如一个婴儿有性别、年龄和体重这些属性,行为有吃、喝、睡等。对象类型能够让我们把这些内容抽象出来并在应用程序中使用。

4、 使用CREATE TYPE语句创立对象类型的时候,我们实际上是创立了真实世界中某个对象的抽象模板。模板只指定了我们在程序中能用到的属性和行为。比方一个雇员有很多属性,但通常只有他的一局部信息是我们的应用程序所需要的,见以下图: 假设我们现在需要编写一个为雇员分发奖金的程序。因为并不是雇员的所有属性都能用于解决这个问题,所以,我们只需设计一个抽象的雇员,拥有与解决问题相关的属性即可:姓名、ID号、部门、职称、工资和级别。然后,设计一些具体的操作方法,例如更改雇员的级别。 下一步就是定义用于数据表现的变量(属性)和用于执行操作的子程序集(方法)。最后,我们把属性和方法封装到对象类型中去。 对象的

5、属性是公有的(对客户端程序可见)。但是,设计良好的程序是不应该直接操作这些属性的,我们应该为这些操作编写相应的方法。这样,雇员数据就能保存在一个适宜的状态。 在运行时,我们可以建立抽象雇员的实例(通常称为对象),然后为它的属性赋值。我们可以按照我们的需求创立任意多个实例。每个对象都有姓名、编号、职别等,如以下图所示: 三、为什么使用对象类型对象类型能把大的系统划分为多个逻辑实体,简化系统复杂度。这就使我们可以创立模块化、可维护、可重用的组件。也能让不同小组的程序员并行开发软件组件。 对象类型靠封装数据的操作来把数据维护代码从SQL脚本中别离出来,并把PL/SQL块封装到方法里。使用对象方法可以

6、防止很多在数据访问时带来的负面影响,同时,对象类型隐藏实现细节,更新细节内容时不必修改客户端程序。 对象类型可以为现实数据建模。现实世界中的复杂实体和关系都可以直接映射到对象类型中。并且,对象类型还可以直接映射到面向对象语言(如Java和C+)的类中。 四、对象类型的结构与包相同,对象类型也有两局部:说明和体,如以下图所示。说明局部是应用程序接口;它声明了数据结构(属性集合)和所需的操作(方法)。方法体局部是对已声明方法的实现。 客户端程序要使用到的所有方法都在说明中声明。我们可以把对象说明想象成一个可选的接口,把对象体想象成一个黒盒。我们可以在不改变说明局部的前提下调试,增强或替换对象体,并

7、且不会对客户端程序造成影响。 在一个对象说明中,所有的属性都必须声明在方法之前。只有子程序的声明才需要实现。所以,如果一个对象类型的说明只声明了属性,那么对象类型的体就没有必要了。我们不能在对象体中声明属性。对象说明中的声明都是公有的。 为了能更好的了解结构,请看下面的例子。这是一个复数的对象类型,有实数局部和虚数局部,并有几个与复数操作相关的方法。 CREATE TYPE complex AS OBJECT(  rpart   REAL,   - attribut

8、e  ipart   REAL,  MEMBER FUNCTION plus(x complex)    RETURN complex,   - method  MEMBER FUNCTION LESS(x complex)    RETURN complex,  MEMBER 

9、FUNCTION times(x complex)    RETURN complex,  MEMBER FUNCTION divby(x complex)    RETURN complex);CREATE TYPE BODY complex AS  MEMBER FUNCTION plus(x complex)  

10、  RETURN complex IS  BEGIN    RETURN complex(rpart + x.rpart, ipart + x.ipart);  END plus;  MEMBER FUNCTION LESS(x complex)    RETURN complex IS 

11、 BEGIN    RETURN complex(rpart - x.rpart, ipart - x.ipart);  END LESS;  MEMBER FUNCTION times(x complex)    RETURN complex IS  BEGIN    RETURN

12、60;complex(rpart * x.rpart - ipart * x.ipart,                   rpart * x.ipart + ipart * x.rpart);  END times;  MEMBER&

13、#160;FUNCTION divby(x complex)    RETURN complex IS    z   REAL := x.rpart * 2 + x.ipart * 2;  BEGIN    RETURN complex(rpart * x.rpart 

14、+ ipart * x.ipart) / z,                   (ipart * x.rpart - rpart * x.ipart) / z);  END divby;END; 五、对象类型组件对象类型封装了数据和操作。我们可以

15、在对象类型说明中声明属性和方法,但不能声明常量、异常、游标或类型。我们至少要声明一个属性(最多1000个),方法是可选的。 1、属性同变量一样,属性也有名称和数据类型。对象类型中的名称必须是唯一的(但在其他的对象类型中可以重用)。除了下面几种类型之外,其他任何Oralce类型都可以使用: 1. LONG和LONG RAW 2. ROWID和UROWID 3. PL/SQL特定类型BINARY_INTEGER及它的子类型、BOOLEAN、PLS_INTEGER、RECORD、REF CURSOR、%TYPE和%ROWTYPE 4. PL/SQL包内定义的数据类型 我们不能在声明属性的时候用赋值语

16、句或DEFAULT子句为它初始化。同样,也不能对属性应用NOT NULL约束。但是,对象是可以存放到添加了约束的数据表中。 数据结构中的属性集合依赖于真实世界中的对象。例如,为了表现一个分数,我们只需要两个INTEGER类型的变量。另一方面,要是表现一个学生,我们需要几个VARCHAR2来存放姓名、住址、 号码和状态等,再添加一个VARRAY类型变量用来存储课程和分数。 数据结构可能是复杂的。例如,一个属性的数据类型可能是另外一个对象类型(称为嵌套对象类型)。有些对象类型,像队列、链表和树,都是动态的,它们是随着使用的需要而动态改变存储长度的。递归对象类型能够直接或间接的包含自身类型,这样就能

17、创立出更诡异的数据类型。 2、方法一般的,方法就是用关键字MEMBER或STATIC声明在对象说明局部的子程序。方法名不能和对象类型名、属性名重复。MEMBER方法只能通过对象实例调用,如: instance_expression.method() 但是,STATIC方法直接通过对象类型调用,而不是实例,如:object_type_name.method() 方法的定义规那么与打包子程序的相同,也分为说明和体两个局部。说明局部由一个方法名和一个可选的参数列表组成,如果是函数,还需要包含一个返回类型。包体就是一段能执行一个特殊任务的代码。对于对象类型说明中的每个方法说明,在对象类型体中都必须有与

18、之对应的方法体实现,除非这个方法是用关键字NOT INSTANTIABLE加以限定,它的意思就是方法体的实现只在子类中出现。为了使方法说明和方法体相匹配,PL/SQL编译器采用token-by- token的方式把它们的头部进行比较。头部必须精确匹配。与属性相同,一个形式参数的声明也是由名称和数据类型组成。但是,参数的类型不能受到大小约束。数据的类型可以是任何Oracle类型,除了那些不适用于属性的类型。这些约束也适用于返回值的类型。· 方法实现所允许使用的语言 Oracle允许我们在PL/SQL、Java或C语言中实现对象方法。我们可以在Java或C语言中实现类型方法,只需提供一个

19、调用说明即可。调用说明在Oracle的数据词典中公布了Java方法或外部C函数。它把程序的名称、参数类型和返回值信息映射到对应的SQL中去。 · SELF参数 MEMBER方法接受一个内置的SELF参数,它代表了对象类型的实例。不管显式或隐式声明,它总是第一个传入MEMBER方法的参数。但是,STATIC方法就不能接受或引用SELF。 在方法体中,SELF指定了被调用方法所属的对象实例。例如,方法transform把SELF声明为IN OUT参数: CREATE TYPE Complex AS OBJECT (  

20、MEMBER FUNCTION transform (SELF IN OUT Complex) . 我们不能把SELF指定成其他数据类型。在MEMBER函数中,如果SELF没有声明的话,它的参数默认为IN。但是,在MEMBER过程中,如果SELF没有什么,那么它的参数模式默认为IN OUT。并且,我们不能把SELF的模式指定为OUT。 如下例所示,方法可以直接引用SELF的属性,并不需要限定修饰词: CREATE FUNCTION gcd(x INTEGER, y INTEG

21、ER)  RETURN INTEGER AS  - find greatest common divisor of x and y  ans   INTEGER;BEGIN  IF (y <= x) AND(x MOD y = 0) THEN    an

22、s    := y;  ELSIF x < y THEN    ans    := gcd(y, x);  ELSE    ans    := gcd(y, x MOD y);  END IF; 

23、0;RETURN ans;END;CREATE TYPE rational AS OBJECT(  num   INTEGER,  den   INTEGER,  MEMBER PROCEDURE normalize,  .);CREATE TYPE BODY rational AS  MEMBER PROCEDURE

24、 normalize IS    g   INTEGER;  BEGIN    g      := gcd(SELF.num, SELF.den);    g      := gcd(num, den);   -

25、0;equivalent to previous statement    num    := num / g;    den    := den / g;  END normalize;  .END; 如果我们从SQL语句中调用了一个空实例(即SELF为空)的MEMBER方法,方法不会被调用,并且

26、会返回一个空值。如果从过程语句调用的话,PL/SQL就会抛出预定义异常SELEF_IS_NULL。 · 重载 与打包子程序一样,同种类型的方法(函数或过程)都能被重载。也就是说,我们可以为不同的方法起相同的名字,只要它们的形式参数在数量、顺序或数据类型上有所不同。当我们调用其中一个方法的时候,PL/SQL会把实参列表和形参列表作比较,然后找出适宜的方法。子类型也可以重载它的基类方法。这种情况下,方法必须有完全相同的形式参数。如果两个方法只是在参数模式上不同的话,我们是不能进行重载操作的。并且,我们不能因两个函数的返回值类型不同而对它们进行重载。· MAP和ORDER方法 一

27、个标量类型,如CHAR或REAL的值都有一个预定义的顺序,这样它们之间就能进行比较。但是对象类型的实例没有预定义的顺序。要想对它们进行比较或排序就要调用我们自己实现的MAP函数。在下面的例子中,关键字MAP指明了方法convert()通过把Relational对象影射到REAL型上,来对它们进行排序操作:CREATE TYPE rational AS OBJECT(  num   INTEGER,  den   INTEGER,  MA

28、P MEMBER FUNCTION CONVERT    RETURN REAL,  .);CREATE TYPE BODY rational AS  MAP MEMBER FUNCTION CONVERT    RETURN REAL IS  BEGIN    RETURN n

29、um / den;  END CONVERT;  .END; PL/SQL使用顺序来计算布尔表达式的值,如x < y,并且可以在DISTINCT,GROUP BY和ORDER BY子句中作比较。MAP方法convert()可以返回一个对象在所有Relation对象中的相对位置。一个对象类型只能包含一个MAP方法,它接受一个内置参数SELF并返回一个标量类型:DATE、NUMBER、VARCHAR2,或是一个ANSI SQL类型,如CHARACTER或REAL。另外,我们还可以用ORDER方法。一个对象类型只能有一个OR

30、DER方法,它必须是一个能返回数字结果的函数。在下面的例子中,关键字ORDER说明了方法match()可以对两个对象进行比较操作:CREATE TYPE customer AS OBJECT(  ID     NUMBER,  NAME   VARCHAR2(20),  addr   VARCHAR2(30),  ORDER MEMBER FUNC

31、TION match(c customer)    RETURN INTEGER);CREATE TYPE BODY customer AS  ORDER MEMBER FUNCTION match(c customer)    RETURN INTEGER IS  BEGIN    IF ID&#

32、160;< c.ID THEN      RETURN -1;   - any negative number will do    ELSIF ID > c.ID THEN      RETURN 1;   - any

33、0;positive number will do    ELSE      RETURN 0;    END IF;  END;END; 每个ORDER方法都只能接受两个参数:内置参数SELF和另外一个同类型的对象。如果c1和c2是Customer对象,一个c1 > c2这样的比较就会自动调用方法match。该方法能够返回负数、零或正数,分别代表SELF比另外一个对象小、等或大。

34、如果传到ORDER方法的参数任意一个为空,方法就会返回空值。知道方针:一个MAP方法就好比一个哈希函数,能把对象值影射到标量值,然后用操作符,如<、=等来进行比较。一个ORDER方法只是简单地将两个对象进行比较。我们可以声明一个MAP方法或是一个ORDER方法,但不同时声明这两个方法。如果我们声明了其中一个,我们就可以在SQL或过程语句中进行对象比较。但是,如果我们没有声明方法,我们就只能在SQL语句中进行等或不等的比较。(两个同类型的对象只有它们对应的属性值相同的时候才相等。)在对大量的对象进行排序或合并的时候,可以使用一个MAP方法。一次调用会把所有的对象影射到标量中,然后对标量值进

35、行排序。ORDER方法的效率相比照拟低,因为它必须反复地调用(它一次只能比较两个对象)。· 构造方法 每个对象类型都有一个构造方法,它是一个名称与对象类型名称相同的函数,用于初始化,并能返回一个对象类型的新的实例。Oracle会为每个对象类型生成一个构造函数,其中形参与对象类型的属性相匹配。也就是说,参数和属性是一一对应的关系,并且顺序、名称和数据类型都完全相同。我们也可以定义自己的构造方法,要么覆盖掉系统定义的构造函数,要么定义一个有着不同方法签名的新构造函数。PL/SQL从来不会隐式地调用构造函数,所以我们必须显式地调用它。3、更改已存在对象类型的属性和方法我们可以使用ALTER

36、 TYPE语句来添加、修改或删除属性,并可以为已存在的对象类型添加或删除方法: CREATE TYPE person_typ AS OBJECT(  NAME      CHAR(20),  ssn       CHAR(12),  address   VARCHAR2(100);CREATE TYPE person_

37、nt IS TABLE OF person_typ;CREATE TYPE dept_typ AS OBJECT(  mgr    person_typ,  emps   person_nt);CREATE  TABLE dept OF dept_typ;- Add new attributes to Per

38、son_typ and propagate the change- to Person_nt and dept_typALTER  TYPE person_typ ADD ATTRIBUTE (picture BLOB, dob DATE)  CASCADE NOT INCLUDING TABLE DATA;CREATE TYPE mytype&#

39、160;AS OBJECT(  attr1   NUMBER,  attr2   NUMBER);ALTER  TYPE mytype ADD ATTRIBUTE (attr3 NUMBER),  DROP ATTRIBUTE attr2,  ADD ATTRIBUTE attr4 NUMBER CASCADE; 在过

40、程编译时,它总是使用当前引用的对象类型版本。在对象类型发生改变时,效劳器端引用那个对象类型的过程就变得无效了,在下次过程被调用时它会被自动重新编译。而对于客户端引用被更改正的类型的过程,我们就必须手动编译。 如果从基类删除一个方法,那么也必须修改覆盖被删除方法的子类。我们可以用ALTER TYPE的CASADE选择来判断是否有子类被影响到;如果有子类覆盖了方法,那么语句就会被回滚。为了能成功地从基类删除一个方法,我们可以: 1. 先从子类删除方法 2. 从基类删除方法,然后用不带OVERRIDING关键字的ALTER TYPE把它重新添加进去 六、定义对象类型对象类型可以表现现实世界中的任何实

41、体。例如,一个对象类型能表现学生,银行账户,计算机显示器,有理数或者是像队列,栈,链表这样的数据结构。这一节给出了几个完整的例子,让我们了解如何设计对象类型并编写我们自己的对象类型。目前我们还不能在PL/SQL块、子程序或包中定义对象类型。但是,我们可以在SQL*Plus中用下面的语法来定义它: CREATE OR REPLACE TYPE type_name  AUTHID CURRENT_USER | DEFINER   IS | AS OB

42、JECT | UNDER supertype_name (  attribute_name datatype, attribute_name datatype.  MAP | ORDER MEMBER function_spec,  FINAL| NOT FINAL MEMBER function_spec,  INSTANTIABLE| NOT 

43、INSTANTIABLE MEMBER function_spec,  MEMBER | STATIC subprogram_spec | call_spec  , MEMBER | STATIC subprogram_spec | call_spec.) FINAL| NOT FINAL  INSTANTIABLE| NOT INSTANTIABLE;CR

44、EATE OR REPLACE TYPE BODY type_name IS | AS   MAP | ORDER MEMBER function_body;  | MEMBER | STATIC subprogram_body | call_spec;  MEMBER | STATIC subprogram_body

45、 | call_spec;.END; 1、PL/SQL类型继承一览PL/SQL支持单继承模式。我们可以定义对象类型的子类型。这些子类型包括父类型(或超类)所有的属性和方法。子类型还可以包括额外的属性和方法,并可以覆盖超类的方法。 我们还可以定义子类是否能继承于某个特定的类型。我们也可以定义不能直接初始化的类型和方法,只有声明它们的子类才可以进行初始化操作。 有些类型属性可以用ALTER TYPE语句动态的改变。当基类发生变化时,无论是用ALTER TYPE语句还是重新定义基类,子类会自动的应用这些改变的内容。我们可以用TREAT操作符只返回某一个指定的子类的对象。 从REF

46、和DEREF函数中产生的值可以代表声明过的表或视图类型,或是一个或多个它的子类型。 · PL/SQL类继承举例 - Create a supertype from which several subtypes will be derived.CREATE TYPE person_typ AS OBJECT(  ssn       NUMBER, &

47、#160;NAME      VARCHAR2(30),  address   VARCHAR2(100)NOT FINAL;- Derive a subtype that has all the attributes of the supertype,- plus some additional attributes.CREA

48、TE TYPE student_typ UNDER person_typ(  deptid   NUMBER,  major    VARCHAR2(30)NOT FINAL;- Because Student_typ is declared NOT FINAL, you can derive- further subtypes

49、 from it.CREATE TYPE parttimestudent_typ UNDER student_typ(  numhours   NUMBER);- Derive another subtype. Because it has the default attribute- FINAL, you cannot use Employee_

50、typ as a supertype and derive- subtypes from it.CREATE TYPE employee_typ UNDER person_typ(  empid   NUMBER,  mgr     VARCHAR2(30);- Define an object type t

51、hat can be a supertype. Because the- member function is FINAL, it cannot be overridden in any- subtypes.CREATE TYPE T AS OBJECT (., MEMBER PROCEDURE Print(), FINAL M

52、EMBERFUNCTION foo(x NUMBER).) NOT FINAL;- We never want to create an object of this supertype. By using- NOT INSTANTIABLE, we force all objects to use one of the

53、0;subtypes- instead, with specific implementations for the member functions.CREATE TYPE Address_typ AS OBJECT(.) NOT INSTANTIABLE NOT FINAL;- These subtypes can provide their own implem

54、entations of- member functions, such as for validating phone numbers and- postal codes. Because there is no "generic" way of doing these- things, only objects of

55、0;these subtypes can be instantiated.CREATE TYPE USAddress_typ UNDER Address_typ(.);CREATE TYPE IntlAddress_typ UNDER Address_typ(.);- Return REFs for those Person_typ objects that are instances&

56、#160;of- the Student_typ subtype, and NULL REFs otherwise.SELECT TREAT(REF(p) AS REF student_typ)  FROM person_v p;- Example of using TREAT for assignment.- Return REFs for th

57、ose Person_type objects that are instances of- Employee_type or Student_typ, or any of their subtypes.SELECT REF(p)  FROM person_v p WHERE VALUE(p) IS OF(employee_typ, student_typ)

58、;- Similar to above, but do not allow any subtypes of Student_typ.SELECT REF(p)  FROM person_v p WHERE VALUE(p) IS OF(ONLY student_typ);- The results of REF and DERE

59、F can include objects of Person_typ- and its subtypes such as Employee_typ and Student_typ.SELECT REF(p)  FROM person_v p;SELECT DEREF(REF(p)  FROM person_v p; 2、对象类型实例:栈栈是一个有序集合。栈有一个栈顶

60、和一个栈底。栈中的每一项都只能在栈顶添加或删除。所以,最后一个被参加栈的项会被最先删除。(可以把栈想象成自助餐厅中的盘子。)压栈和退栈操作能够对栈进行后进先出(LIFO)更新。 栈能应用在很多地方。例如,它们可以用在系统编程中控制中断优先级并对递归进行管理。最简单的栈实现就是使用整数数组,数组的一端代表了栈顶。 PL/SQL提供了VARRAY数据类型,它能让我们声明变长数组。要声明变长数组属性,必须先定义变长数组类型。但是,我们不能再对象说明中定义类型,所以,我们只能单独的定义变长数组类型,并指定它的最大长度,具体实现如下: CREATE TYPE IntArray

61、0;AS VARRAY(25) OF INTEGER; 现在我们可以编写对象类型说明了:CREATE TYPE stack AS OBJECT(  max_size   INTEGER,  top        INTEGER,  POSITION   intarray,  MEMBER PROCE

62、DURE initialize,  MEMBER FUNCTION FULL    RETURN BOOLEAN,  MEMBER FUNCTION empty    RETURN BOOLEAN,  MEMBER PROCEDURE push(n IN INTEGER),  MEMBER PROCEDURE 

63、;pop(n OUT INTEGER); 最后,我们可以编写对象类型体:CREATE TYPE BODY stack AS  MEMBER PROCEDURE initialize IS  BEGIN    top         := 0;    /* Call co

64、nstructor for varray and set element 1 to NULL. */    POSITION    := intarray(NULL);    max_size    := POSITION.LIMIT;   - get varray s

65、ize constraint    POSITION.EXTEND(max_size - 1, 1);   - copy element 1 into 2.25  END initialize;  MEMBER FUNCTION FULL    RETURN BOOLEAN IS  BEG

66、IN    RETURN(top = max_size);   - return TRUE if stack is full  END FULL;  MEMBER FUNCTION empty    RETURN BOOLEAN IS  BEGIN    RE

67、TURN(top = 0);   - return TRUE if stack is empty  END empty;  MEMBER PROCEDURE push(n IN INTEGER) IS  BEGIN    IF NOT FULL THEN    

68、;  top              := top + 1;   - push integer onto stack      POSITION(top)    := n;    ELSE

69、   - stack is full      raise_application_error(-20211, 'stack overflow');    END IF;  END push;  MEMBER PROCEDURE pop(n OUT INTEGER) IS  

70、;BEGIN    IF NOT empty THEN      n      := POSITION(top);      top    := top - 1;   - pop integer off

71、0;stack    ELSE      - stack is empty      raise_application_error(-20212, 'stack underflow');    END IF;  END pop;END; 在成员过程push和pop中,我们使用内置过程rais

72、e_application_error来关联用户定义的错误消息。这样,我们就能把错误报告给客户端程序而防止把未控制异常传给主环境。客户端程序捕获PL/SQL异常后,可以在OTHERS异常控制句柄中用SQLCODE和SQLERRM 来确定具体的错误信息。下例中,当异常被抛出时,我们就把对应的错误消息输出: DECLARE  .BEGIN  .EXCEPTION  WHEN OTHERS THEN    dbms_output.put_line(SQLERRM);END; 另外,

73、程序还可以使用编译指示EXCEPTION_INIT把raise_application_error返回的错误编号影射到命名异常中,如下例所示:DECLARE  stack_overflow    EXCEPTION;  stack_underflow   EXCEPTION;  PRAGMA EXCEPTION_INIT(stack_overflow, -20211);  PRAGMA EXCEPTION_INIT(

74、stack_underflow, -20212);BEGIN  .EXCEPTION  WHEN stack_overflow THEN  .END; 3、对象类型实例:售票处假设有一个连锁电影院,每个影院有三个银幕。每个影院有一个售票处,销售三种不同电影的影票。所有影票的价格都为三美元。定期检查影票的销售情况,然后及时补充影票。 在定义代表销售处的对象类型之前,我们必须考虑到必要的数据和操作。对于一个简单的售票处来说,对象类型需要票价、当前影票存量和已售影票的收据这些属性。它还需要一些方法:购票、盘存、

75、补充存量和收集收据。 对于收据,我们可以使用含有三个元素的数组。元素1、2和3各自记录电影1、2和3。要声明一个变长数组属性,我们就必须先像下面这样定义它的类型: CREATE TYPE RealArray AS VARRAY(3) OF REAL; 现在,我们可以编写对象类型说明: CREATE TYPE ticket_booth AS OBJECT(  price         R

76、EAL,  qty_on_hand   INTEGER,  receipts      realarray,  MEMBER PROCEDURE initialize,  MEMBER PROCEDURE purchase(movie INTEGER, amount REAL, CHANGE OUT REAL), &#

77、160;MEMBER FUNCTION inventory    RETURN INTEGER,  MEMBER PROCEDURE replenish(quantity INTEGER),  MEMBER PROCEDURE COLLECT(movie INTEGER, amount OUT REAL); 最后,我们可以编写对象类型体: CREATE TYPE BODY

78、60;ticket_booth AS  MEMBER PROCEDURE initialize IS  BEGIN    price          := 3.00;    qty_on_hand    := 5000;   - prov

79、ide initial stock of tickets    - call constructor for varray and set elements 1.3 to zero    receipts       := realarray(0, 0, 0); 

80、60;END initialize;  MEMBER PROCEDURE purchase(movie INTEGER, amount REAL, CHANGE OUT REAL) IS  BEGIN    IF qty_on_hand = 0 THEN      raise_application_error(-20

81、213, 'out of stock');    END IF;    IF amount >= price THEN      qty_on_hand        := qty_on_hand - 1;   

82、60;  receipts(movie)    := receipts(movie) + price;      CHANGE             := amount - price;    ELSE   -

83、0;amount is not enough      CHANGE    := amount;   - so return full amount    END IF;  END purchase;  MEMBER FUNCTION inventory &#

84、160;  RETURN INTEGER IS  BEGIN    RETURN qty_on_hand;  END inventory;  MEMBER PROCEDURE replenish(quantity INTEGER) IS  BEGIN    qty_on_hand    :=

85、0;qty_on_hand + quantity;  END replenish;  MEMBER PROCEDURE COLLECT(movie INTEGER, amount OUT REAL) IS  BEGIN    amount             :=&

86、#160;receipts(movie);   - get receipts for a given movie    receipts(movie)    := 0;   - reset receipts to zero  END COLLECT;END; 4、对象类型实例:银行账户在定义银行账户对象类型之前,我们必

87、须考虑一下要使用的数据和操作。对于一个简单的银行账户来说,对象类型需要一个账号、余额和状态这三个属性。所需的操作有:翻开帐户,验证账号,关闭账户,存款,取款和余额结算。首先,我们要像下面这样编写对象类型说明: CREATE TYPE bank_account AS OBJECT(  acct_number   INTEGER(5),  balance       REAL,  status

88、0;       VARCHAR2(10),  MEMBER PROCEDURE OPEN(amount IN REAL),  MEMBER PROCEDURE verify_acct(num IN INTEGER),  MEMBER PROCEDURE CLOSE(num IN INTEGER, amount OUT 

89、;REAL),  MEMBER PROCEDURE deposit(num IN INTEGER, amount IN REAL),  MEMBER PROCEDURE withdraw(num IN INTEGER, amount IN REAL),  MEMBER FUNCTION curr_bal(num IN INTEGER)  

90、  RETURN REAL); 然后编写对象体: CREATE TYPE BODY bank_account AS  MEMBER PROCEDURE OPEN(amount IN REAL) IS  - open account with initial deposit  BEGIN    IF NOT a

91、mount > 0 THEN      raise_application_error(-20214, 'bad amount');    END IF;    SELECT acct_sequence.NEXTVAL      INTO acct_number   

92、   FROM DUAL;    status     := 'open'    balance    := amount;  END OPEN;  MEMBER PROCEDURE verify_acct(num IN INTEGER) IS 

93、; - check for wrong account number or closed account  BEGIN    IF (num <> acct_number) THEN      raise_application_error(-20215, 'wrong number');    ELSIF(status = 'closed') THEN      ra

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论