zoukankan      html  css  js  c++  java
  • Oracle Package

    (转自:http://blog.csdn.net/bbliutao/article/details/9016947)

    一、概述
    包可将一些有联系的对象放在其内部。
    任何能在块定义部分出现的对象都可以在包中出现。这些对象包括存储过程、函数、游标、自定义的类型和变量。
    我们可以在其它的PLSQL块中引用包中的这些对象,也就是说,包为PLSQL提供了全局变量。
    包可以实现信息屏蔽和子程序重载。


    二、包的定义
    一个包由两个独立部分组成——包头和包体,各部分被单独存放在数据字典中,定义一个包,要分别定义包头和包体。

    1、定义包头
    (1)、语法:
    create or replace package [schema.] package_name {is|as}
    pl/sql_package;

    其中package_name是包的名称,pl/sql_package可以是存储过程、函数、变量、类型、异常及游标的定义。

    存储过程和函数必须在包头中预定义。也就是说,在包头中仅定义存储过程名或函数名以及它们的参数,
    存储过程或函数的执行代码将在包体中定义,这不同于无名块中定义存储过程和函数。

    例一:
    create or replace package aupack as
    procedure qusalary(p_code auths.code%type,p_salary out auths.salary%type);
    procedure inauthor(p_code auths.code%type,p_salary out auths.salary%type);
    end aupack;

    2、定义包体
    包体是有个数据字典对象。只有在包头成功编译后,包体才能被编译。包体只包含包头中已预定义的子程序代码。
    在包头中定义(不是预定义)的对象可以直接在包体中使用,不必再在包体中定义。

    (1)、语法:
    create or replace package body [schema.] package_name {is/as}
    pl/sql_body;

    其中package_name为包名,该包名必须与定义包头时的名称一样,pl/sql_body为过程与函数的定义

    如果包头不包含存储过程和函数,则不必定义包体。如果包头中有预定义的子程序(存储过程和函数),
    则在包体中必须编写其子程序代码,而且包头和包体两部分指定的子程序必须一致。
    这包括相同的子程序名、参数名、和参数类型。

    例一:
    create or replace package body aupack is
    procedure qusalary(p_code auths.code%type,p_salary out auths.salary%type) as
    begin
    ...
    end aupack;
    procedure inauthor(p_code auths.code%type,p_salary out auths.salary%type) as
    begin
    ...
    end inauthor;


    三、包的初始化

    1、概述
    包的初始化,也称包的构造过程。类似于C++的构造函数和JAVA的构造方法。
    当在会话内第一次被调用时会自动执行,并且在同一会话内只会执行一次。
    包的构造过程没有名称,在包体实现了包头定义的子程序后的最后部分被定义,以begin开始、end结束。

    2、语法
    create or replace package body package_name {is|as}
    ... --实现包体中过程与函数的定义部分
    begin
    ... --初始化代码
    end;

    例子
    create or replace package apack as
    v_sex varchar2(2);
    procedure a_sex(p_code auths.code%type,p_sex out varchar2);
    end apack;

    create or replace body apack as
    procedure a_sex(p_code auths.code%type,p_sex out varchar2) as
    v_sex number;
    begin
    select sex into v_sex from auths where code=p_code;
    if v_sex=0 then
    p_sex:='女';
    else
    p_sex:='男';
    end if;
    end apack;
    begin
    a_sex('A0001',v_sex); --初始化部分
    end apack;


    四、包中子程序的重载
    1、定义
    在包的内部,存储过程和函数都可被重载,这意味着有多个存储过程或函数可以使用同一名称,但是参数不能相同。
    这样就允许不同的参数调用同一名字的过程或函数。但需要注意同名的函数返回值得数据类型必须完全相同。

    例一
    create or replace package pac_temp is
    procedure ad(p_in number);
    procedure ad(p_in varchar2);
    end pac_temp;

    create or replace package body pac_temp is
    procedure ad(p_in number) as
    begin
    dbms_output.put_line(p_in);
    dbms_output.put_line('我是number');
    end ad;

    procedure ad(p_in varchar2) as
    begin
    dbms_output.put_line(p_in);
    dbms_output.put_line('我是varchar2');
    end ad;
    end pac_temp;

    begin
    dbms_output.put_line('a');
    pac_temp.ad('5');
    pac_temp.ad(5);
    end;

    2、重载的局限性
    (1)、当仅仅参数名不同或者是模式(in,out,in out)不同时,不能重载。
    (2)、不能对仅有返回类型不同的函数进行重载。
    (3)、重载函数的参数必须是数据类型不同间不可自动转换的。此类错误在编译时不会报错,但调用若自动转换发生错误会报错。


    五、包的删除
    drop package body pac_name; --只删除包体
    drop package pac_name; --删除包


    六、包函数的使用纯度级别

    1、概述
    首先,应该明确这里说的是包里面的函数。要在sql语句中引用包的函数,那么该函数不能含有DML语句,也不能读写远程包的变量。
    为了对包的函数加以限制,在定义包头时使用可以使用纯度级别限制函数。

    2、语法
    pragma restrict_references(function_name,wnds[,wnps,rnds,rnps]); --能在sql语句中调用的函数都有wnds基本约束

    四种约束的含义:
    WNDS:函数内不能修改数据库数据(即禁止DML操作)。
    WNPS:函数内不能修改包变量(即不能给包变量赋值)。
    RNDS:函数内不能读取数据数据(即禁止执行select操作)。
    RNPS:函数内不能读取包变量(即不能将包变量赋值给其他变量)。

    根据对函数的四种基本约束,满足下面约束的函数可以被sql语句调用:
    (1)、当函数满足WNDS时,能被SQL语句调用。
    (2)、当函数满足RNPS和WNPS约束时,这个函数(通过数据库连接)能被远程或并行调用。
    (3)、在select、valules或set子句中调用的函数可以没有wnps约束,但在其它的子句中就必须满足wnps约束。
    (4)、一个函数所调用的子程序与该函数的约束级别相同。
    (5)、在含有create table或alter table 命令的check子句中,不能调用直接创建的函数,因为这些语句中的定义不能变化。


    3、restrict_references编译指令的应用

    当将单独存储在数据库中的函数用在sql语句时,plsql引擎自动确定该函数有哪些约束,这些约束能否保证函数在sql语句中的调用。
    对于包函数,则先在包内部使用restrict_references编译指令来指定包函数的约束。
    在sql语句中调用这个包函数时,plsql根据编译指令指定的约束来来判断包函数能否在sql语句中调用。


    例一:
    create or replace package authorpack as
    function fun(p_authorcode auths.author_code%type) return varchar2;
    pragma restrict_references(fun,WNDS,WNPS,RNPS); --指定3种约束
    function authorcount return number;
    pragma restrict_references(authorcount,WNDS,WNPS,RNPS)
    end authorpack;

    create or replace body authorpack as
    v_num number; --包变量
    function fun(p_authorcode auths.author_code%type) return varchar2 as
    v_return varchar2(16);
    begin
    select author||name into v_return from auths where author_code=p_authorcode;
    return v_return;
    end fun;

    function authorcount return number as
    v_return number;
    begin
    if v_num is null then --包变量被读,不满足RNPS
    select count(*) into v_return from auths where author_code like 'A%';
    v_num:=v_return; --包变量被修改,不满足WNPS
    else
    v_return:=v_num;
    end if;
    return v_return;
    end authorcount;
    end authorpack;

    例二
    create or replace package purity is
    minsal number(6,2);
    maxsal number(6,2);
    function max_sal return number;
    function min_sal return number;
    pragma restrict_references(max_sal,WNPS);
    pragma restrict_references(min_sal,WNPS);
    end;

    create or replace package body purity is
    function max_sal return number is
    begin
    select max(sql) into maxsal from emp; --违反WNPS
    return maxsal;
    end;
    function min_sal return number is
    begin
    select max(sql) into maxsal from emp; --违反WNPS
    return maxsal;
    end;
    end;

    在包头的fun函数中使用了restrict_references编译指令指定约束,包体中的fun函数代码显然符合编译指令指定的约束——没有修改数据库表、没有读包中变量、没有修改包中变量。
    在包头的authorcount函数中使用了restrict_references编译指令,但在包体中的authorcount函数代码
    并不符合指定的约束,包体中定义的变量v_num不仅仅被该函数读出(不满足rnps约束),而且被修改(不满足wnps约束),
    所以plsql引擎编译到函数authorcount是,会报“pls-00452”的错误。


    注意事项:
    (1)、plsql编译程序根据编译指令来确认包函数的基本约束,从而确认这个包函数是否能在sql语句中使用。
    只要随后修改了包体(或第一次创建),就要按照编译指令校检函数代码。
    (2)、包初始化部分的代码同样也可以有基础约束。包的基本约束也用restrict_references来指定,
    但应以包名为参数而不是以函数名为参数。
    (3)、restrict_references可在包中函数定义后的任何位置出现,但它只能约束一个函数的定义。
    因此,对于函数的重载,pragma只约束最近定义的函数。
    (4)、如果函数中用到了系统包,则该函数不能用在sql语句中。常见系统包dbms_output,dbms_pipe,dbms_alter,dbms_sql,utl_file等。
    (5)、当过程性语句中调用一个函数时,可以使用参数缺省值,而通过sql语句调用一个函数时,所有的参数都必须指定。
    另外必须使用位置表示法,而不能使用名称表示法。

  • 相关阅读:
    剑指Offer(Java版)第五十题:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志, 写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看, 但却读不懂它的意思。例如,“student. a am I”
    剑指Offer(Java版)第四十九题:汇编语言中有一种移位指令叫做循环左移(ROL), 现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。 例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果, 即“XYZdefabc”。是不是很简单?OK,搞定它!
    【转载】Java 内存分配全面浅析
    【记】Linux下安装JDK1.7
    【ZooKeeper】典型应用场景概览
    正则表达式工具RegexBuddy
    【基础】RandomAccess
    【JNDI】Java Naming and Directory Interface
    【AOP】Cglib动态代理实现方式
    【事务】分布式事物原理
  • 原文地址:https://www.cnblogs.com/FindSelf/p/3656508.html
Copyright © 2011-2022 走看看