《Oracle PL/SQL程序设计(第5版)》一一2.4 执行必要的PL/SQL任务

2.4 执行必要的PL/SQL任务

Oracle PL/SQL程序设计(第5版)
让我们把焦点转移到当把SQL*Plus作为前端工具时,该如何创建、运行、删除以及其他的PL/SQL程序管理任务。不要期待这部分能够覆盖所有细节,后面的章节会更加深入细致地介绍这些主题,这里只是快速过一遍。

2.4.1 创建存储过程

要想创建一全新的PL/SQL存储程序,你需要使用SQL中的一个CREATE语句。比如,如果你想创建一个存储函数,这个函数能够对一个字符串中的单词个数计数,你就可以使用CREATE FUNCION语句:

CREATE FUNCTION wordcount (str IN VARCHAR2)
  RETURN PLS_INTEGER
AS
  declare local variables here
BEGIN
  implement algorithm here
END;
/

只是一个简单的BEGIN-END块,要在SQL*Plus中运行这个语句还需要一个结尾的斜杠,这个斜杠自己占一行。

如果DBA已经把Oracle的CREATE PROCEDURE权限赋予给你了(这个权限也允许创建函数),这个语句会让Oracle编译并把这个存储过程保存到你的模式下,一但代码编译完成,你就会看以如下这样一个成功信息:

Function created.

如果在你的模式下已经有另一个数据库对象也叫wordcount,比如一个表或者一个包, CREATE FUNCTION这个命令就会失败,并给出错误消息ORA-0955:name is already used by an existing object。这也是Oracle提供了OR REPLACE选项的原因,而且99%的情况下你都会使用这个选项。

CREATE OR REPLACE FUNCTION wordcount (str IN VARCHAR2)
  RETURN PLS_INTEGER
AS
  same as before

使用OR REPLACE选项,能够避免先删除然后重建程序的方法所带来的副作用;换句话说,它能够保留你已经赋予其他用户或者角色的针对这个对象的权限。幸运的是,这个命令只会替换相同类型的对象,所以如果你想要创建的是一个函数,它不会自动删除一个叫做workcount的数据表。

和之前多次使用的匿名代码块一样,程序员通常会把这些语句保存到一个操作系统文件中。我为这个函数创建一个名叫wordcount.fun的文件,然后使用SQL*Plus的@命令来运行这个文件:

SQL> @wordcount.fun
Function created.

之前已经说过,SQL*Plus默认的时候并不回显脚本的内容。你可以开启SET ECHO ON,然后代码在屏幕上滚动,还带着数据库所分配的行号,这个选项在问题诊断时非常有用。让我们注释掉一个变量声明,这就给程序中引入了一个错误:

SQL> /* File on web: wordcount.fun */
SQL> SET ECHO ON
SQL> @wordcount.fun
SQL> CREATE OR REPLACE FUNCTION wordcount (str IN VARCHAR2)
 2    RETURN PLS_INTEGER
 3 AS
 4 /* words PLS_INTEGER := 0; ***Commented out for intentional error*** */
 5   len PLS_INTEGER := NVL(LENGTH(str),0);
 6   inside_a_word BOOLEAN;
 7 BEGIN
 8     FOR i IN 1..len + 1
 9     LOOP
 10       IF ASCII(SUBSTR(str, i, 1)) < 33 OR i > len
 11       THEN
 12       IF inside_a_word
 13       THEN
 14         words := words + 1;
 15         inside_a_word := FALSE;
 16       END IF;
 17     ELSE
 18       inside_a_word := TRUE;
 19     END IF;
 20    END LOOP;
 21    RETURN words;
 22  END;
 23 /

Warning: Function created with compilation errors.

SQL>

这个消息告诉我们,函数已经创建了,但却带有编译错误,因此这个函数还不能使用。我们已经成功地把函数的源代码保存到数据库中,现在我们需要对数据库给出的错误信息的细节进行梳理。查看错误消息的完整文本的最快捷方式就是用SQL*Plus的SHOW ERRORS命令,简写成SHO ERR:

SQL> SHO ERR Errors for FUNCTION WORDCOUNT:

LINE/COL ERROR
-------- ----------------------------------------------
14/13 PLS-00201: identifier 'WORDS' must be declared
14/13 PL/SQL: Statement ignored
21/4 PL/SQL: Statement ignored
21/11 PLS-00201: identifier 'WORDS' must be declared

编译器已经发现了变量的存在,并准确的报告出行号和列号。要想获得一个错误更详细的内容,你可以根据错误的标识符去文档Oracle’s Database Error Messages中查找——这里是PLS-00201。

其实在后台,SHOW ERRORS命令也仅仅是查询Oracle数据字典的USER_ERRORS视图。你当然可以自己查询这个视图,不过通常没必要这么做。

显示其他错误

很多Oracle程序员只知道这个SQLPlus命令的一种形式:*

SQL>SHOW ERRORS

他们错误地认为必须直接查看USER_ERRORS视图去看最近的编译错误。其实,可以在SHOW ERRORS后面加上一个对象类别和对象名称,这样就可以只显示和该对象相关的错误:

SQL>SHOW ERRORS category [schema.]object

比如,要查看workcount函数最近的编译错误,使用:

SQL>SHOW ERRORS FUNCTION wordcount

在解释输出时要小心:

No errors.

这个输出可能意味着下列三种情况之一:(1)对象编程成功;(2)提供的是错误的类别(比如给的是过程而不是函数);(3)没有指定名字的对象。

这个命令能够支持的类别的完整列表随着Oracle版本变化而变化,不过下面这些是都包括的:

DIMENSION
FUNCTION
JAVA SOURCE
JAVA CLASS
PACKAGE
PACKAGE BODY
PROCEDURE
TRIGGER
TYPE
TYPE BODY
VIEW

习惯上,在每一个创建PL/SQL存储过程的CREATE语句后面都要加上一个SHOW ERRORS命令。因此一个用于SQL*Plus环境的,创建存储过程的“最佳实践”模板应该是这样的:

CREATE OR REPLACE program-type
AS
  your cod
END;
/
SHOW ERRORS

(我不常在脚本中使用SET ECHO ON,只是在需要时才会在命令行中使用。)

如果你的程序包含的是编译器能够检测到的错误,CREATE命令仍然会让Oracle把程序保存到数据库中,只不过程序的状态是无效的。但如果拼错了CREATE语法,数据库就无法分辨你想做什么,因此也不会在数据库中保存代码。

2.4.2 执行存储过程

我们已经看到两种调用存储过程的方法了:封装在一个PL/SQL代码块中,或者使用SQL*Plus的EXECUTE命令。你也可以在存储过程中使用其他存储过程。比如,你可以在任何一处能够使用整数表达式的地方使用wordcount函数。下面代码简单演示了,我是如何使用一个较怪的输入(CHR(9)是一个,ASCII的“tab”字符)来测试wordcount函数的。

BEGIN
  DBMS_OUTPUT.PUT_LINE('There are ' || wordcount(CHR(9)) || ' words in a tab');
END;
/

这个wordcount是表达式的一部分,而表达式整体又作为DBMS_OUTPUT.PUT_LINE的参数,wordcount表达式的返回值是一个整数。PL/SQL会自动把整数转换成字符串,然后和其他两个字符串拼接起来,最终结果是:

There are 0 words in a tab

在一个SQL语句里可以调用多个PL/SQL函数,下面是使用wordcount函数的一些例子:

在select子句中使用这个函数,以计算某一表列的词的数量;
SELECT isbn, wordcount(description) FROM books;
使用ANSI兼容的CALL语句,把函数的返回值绑定到一个SQL*Plus变量;然后显示结果:

VARIABLE words NUMBER
CALL wordcount('some text') INTO :words;
PRINT :words

和上一个例子相同,但是执行的是一个远程数据库的函数,指向这个远程数据库的数据库链接叫做test.newyork.ora.com:

CALL wordcount@test.newyork.ora.com('some text') INTO :words;

函数是属于bob用户,但是以其他有相应授权的用户登录后执行函数:

SELECT bob.wordcount(description) FROM books WHERE id = 10007;

2.4.3 显示存储过程

总有一个时刻,你会想得到你拥有的存储过程列表,或者想要查看保存在数据字典中的程序代码的最新版本。如果借助于一些基于GUI的导航助手,这是一个相当简单的任务,不过就算没有这种工具,通过写一些SQL语句从数据字典中取出这些信息也不是很难的工作。

比如,要想得到你的程序(或者表、索引等)的完整列表,你可以查询USER_OBJECTS这个视图,像这样:

SELECT * FROM USER_OBJECTS;

这个视图会显示出名称、类型、创建时间、最后一次编译时间、状态(有效或者无效),以及其他有用的信息。

如果你只是想知道一个PL/SQL程序的调用接口的概要信息,最简单的方法就是在SQL*Plus中使用DESCRIBE命令。

SQL> DESCRIBE wordcount
FUNCTION wordcount RETURNS BINARY_INTEGER
Argument Name   Type      In/Out Default?
----------------- ------------- ------ --------
STR         VARCHAR2    IN

DESCRIBE命令同样适用于表、视图、对象类型、过程和包。要想看到存储过程的完整代码,可以查看USER_SOURCE或者TRIGGER_SOURCE视图(如何查看这些数据字典视图会在第20章中有更详细的说明)。

2.4.4 存储程序的授权和别名

对于刚刚创建出来的PL/SQL存储过程,正常情况下只有创建者或DBA能够执行它。要想授权给其他人执行存储过程,使用GRANT语句:

GRANT EXECUTE ON wordcount TO scott;

要想去掉这个权限,使用REVOKE命令:

REVOKE EXECUTE ON wordcount FROM scott;

你也可以把EXECUTE权限授予一个角色:

GRANT EXECUTE ON wordcount TO all_mis;

或者,如果需要,你也可以允许任何使用数据库的用户来运行程序:

GRANT EXECUTE ON wordcount TO PUBLIC;

假设你把权限授予了某个人比如Scott,然后又授予给Scott所拥有的某个角色,接着又授权给了PUBLIC,数据库会一直牢记这三次授权,直到这些授权被收回。但这三个中的任何一个都足够让Scott运行这个程序。如果您不想让Scott运行这个程序,你必须从Scott收回权限,再从PUBLIC收回权限,最后再从all_mis角色收回权限(或者从Scott收回这个角色)才真正可以。

要想查看你已经授予其他用户或者角色的权限列表,你可以查看USER_TAB_PRIVS_MDDE数据字典视图。不过PL/SQL的程序名字是保存在TABLE_NAME列中的,这点不是那么很直观:

SQL> SELECT table_name, grantee, privilege
 2 FROM USER_TAB_PRIVS_MADE
 3 WHERE table_name = 'WORDCOUNT';

TABLE_NAME GRANTEE PRIVILEGE
-------------------------------------------------------- -----------
WORDCOUNT PUBLIC  EXECUTE
WORDCOUNT SCOTT  EXECUTE
WORDCOUNT MIS_ALL EXECUTE

假设Scott已经有了wordcount的EXECUTE权限,他可能想为这个函数创建一个别名,这样一来他就不必在每次使用这个函数时还要加上模式名做前缀了:

SQL> CONNECT scott/tiger
Connected.
SQL> CREATE OR REPLACE SYNONYM wordcount FOR bob.wordcount;

现在Scott可以通过别名的方式来执行程序了:

IF wordcount(localvariable) > 100 THEN...

这是一个不错的方法,因为如果函数的属主发生了变化,需要修改的只有这个别名(而不需要对任何存储过程做改动)。

对过程、函数、包或者用户自定义类型都可以创建别名。为过程、函数或包创建的别名不仅可以隐藏模式信息,而且还可以隐藏数据库信息,你可以很容易地为远程程序创建别名,就像对本地程序那么做。不过,别名也只能隐藏起模式和数据库信息,你不能为包中的子程序创建别名。

删除一个别名也是很容易的:

DROP SYNONYM wordcount;

2.4.5 删除存储程序

如果你真的不再需要某个存储程序了,你可以通过SQL的DROP语句来删除它:

DROP FUNCTION wordcount;

包是有两个元素组成的(声明部分和包体),你可以一次性完整地删除整个包:

DROP PACKAGE pkgname;

或者你也可以只删除包体部分,而不会影响对应的声明部分:

DROP PACKAGE BODY pkgname;

如果你删除了一个存储过程,而其他程序又调用了该存储过程,那么这些调用程序就会被标识成无效。

2.4.6 隐藏存储过程的源代码

当你用上面展示的方法创建PL/SQL程序时,从数据字典中可以得到明文形式的源代码。任何DBA都可以查看甚至修改这些代码。要想保护商业秘密或者防止代码被篡改,你需要某种手段能够在代码发布前“弄乱”它。

Oracle提供了一个叫做wrap的命令行工具,这个工具可以把许多CREATE语句转换成由明文和十六进制符号组成的混合体。这个工具并不是加密,但确实向隐藏代码前进了一大步,下面是一个被封转后的文件的节选:

FUNCTION wordcount wrapped
0
abcd
abcd
...snip...
1WORDS:
10:
1LEN:
1NVL:
1LENGTH:
1INSIDE_A_WORD:
1BOOLEAN:
...snip...
a5 b 81 b0 a3 a0 1c 81
b0 91 51 a0 7e 51 a0 b4
2e 63 37 :4 a0 51 a5 b a5
b 7e 51 b4 2e :2 a0 7e b4
2e 52 10 :3 a0 7e 51 b4 2e
d :2 a0 d b7 19 3c b7 :2 a0
d b7 :2 19 3c b7 a0 47 :2 a0

如果你需要真正的加密功能——比如,你要发布的是类似于密码这样真正需要保护的信息——你就不能使用这个工具了1。‡

要了解wrap工具的更多内容,可以参见第20章。

时间: 2024-10-28 03:40:33

《Oracle PL/SQL程序设计(第5版)》一一2.4 执行必要的PL/SQL任务的相关文章

《Oracle PL/SQL程序设计(第5版)》一一1.4 关于PL/SQL的版本

1.4 关于PL/SQL的版本 Oracle PL/SQL程序设计(第5版) 每个版本的Oracle数据库都有其对应的PL/SQL版本.只要我们使用的是最新版的PL/SQL,就会有更多的功能供我们使用.作为PL/SQL程序员的最大挑战就是"紧跟".我们不需要不断地自学每个版本中的新特性─学会使用它们,尤其在我们自己的应用程序中该如何使用,确定有些新技术尤其有用,我们应该利用这些新技术修改已有的应用程序. 表1-1总结了数据库中每一版(过去的和当前的)PL/SQL的主要成员(注意在早期的

《Oracle PL/SQL程序设计(第5版)》一一2.6 在其他语言中调用PL/SQL

2.6 在其他语言中调用PL/SQL Oracle PL/SQL程序设计(第5版) 总有一天,你会在从C.Java.Perl.PHP或其他语言中调用PL/SQL.虽然这是一个很合理的需求,如果你曾经做过跨语言的开发工作,你一定熟知要把各种语言专有的数据类型糅合在一起─尤其是那些复合数据类型,比如数组.记录或者对象类型─的复杂性,更不用说不同的参数语法或者厂商对所谓"标准"应用编程接口(API)的扩展,比如微软的ODBC(Open Database Connectivity). 我会用几

《Oracle PL/SQL程序设计(第5版)》一一1.5 PL/SQL开发人员的资源

1.5 PL/SQL开发人员的资源 Oracle PL/SQL程序设计(第5版) O'Reilly在1995年出版了本书的第一版.当时,Oracle PL/SQL编程这本书确实造成一个小轰动.它是第一本关于PL/SQL的独立著作(也就是,不是来自于Oracle公司的).从那时开始,PL/SQL程序员的资源─图书.开发环境.工具以及网站─开始蓬勃发展.(当然,迄今为止这本书仍然是这些资源中最重要和最有价值的!) 下面这一节简要地介绍了这许多资源.要充分利用这些资源,许多资源都可以免费获得或者非常低

《Oracle PL/SQL程序设计(第5版)》一一1.6 一些建议

1.6 一些建议 Oracle PL/SQL程序设计(第5版) 自从本书1995年第一版出版以来,我有机会培训.帮助.与上千名PL/SQL开发人员合作过.在这个过程中,我从学生和读者中学到的许多,也深刻的理解了在PL/SQL世界中我们是如何工作的.我要给你一些如何让这个强大的编程语言更有效的工作的建议,你可不要不耐烦. 1.6.1 不要太着急 我们的工作时间总是很紧迫,记者解决一个个的问题.我们不能浪费时间,有太多的代码要写.因此马上开始吧--对吗? 错误.如果太快地深入到代码构建中,盲目地把用

《Oracle PL/SQL程序设计(第5版)》一一2.2 创建和编辑源代码

2.2 创建和编辑源代码 Oracle PL/SQL程序设计(第5版) 当今的程序员有太多的代码编辑器可以选择,从最简单的纯文本编辑器到最花哨的开发环境让人眼花缭乱.不同的程序员会有不同的选择,本书的一名作者Steven Feuerstein,非常痴迷于Toad IDE.他也是一个非常典型的IDE用户--最多熟悉界面上10%的功能和按钮,并严重依赖于这些功能.相反Bill Pribyl说他自己是一个"非常古怪的人,因为我只喜欢使用一个非常朴素的文本编辑器来写PL/SQL程序.我的一个要求就是,它

《Oracle PL/SQL程序设计(第5版)》一一1.1 什么是PL/SQL?

1.1 什么是PL/SQL? Oracle PL/SQL程序设计(第5版) Oraclel 的PL/SQL语言有这样一些典型的特点: ** 它是一种高度结构化.易读.易理解的语言** 如果你是一个开发新手,那么PL/SQL是一个非常好的起点.你会发现PL/SQL是一门非常容易掌握的语言,它有丰富的关键字.语法结构,可以让编写出能够清晰的表达你的意图的代码.如果你在其他开发语言已经是一个资深开发者,你也会发现PL/SQL这门新语言非常容易适应的. ** 它是一种标准的.可移植的Oracle开发语言

《Oracle PL/SQL程序设计(第5版)》一一第1章 PL/SQL概述

第1章 PL/SQL概述 Oracle PL/SQL程序设计(第5版) 所谓PL/SQL,即"Procedural Language extensions to the Structured Query Language"的首字母缩写.在关系数据库的世界中,SQL语言是无处不在,从数据查询到数据更新.Oracle 公司发明PL/SQL为了克服SQL语言自身的一些局限,并为那些要在Oracle数据库中运行的核心业务,提供一种更完整的变成解决方案.这一章将介绍PL/SQL,包括它的起源.它

《Oracle PL/SQL程序设计(第5版)》一一2.5 编辑PL/SQL的环境

2.5 编辑PL/SQL的环境 Oracle PL/SQL程序设计(第5版)如前所述,你可以选择像SQL*Plus这样最朴素的编辑和执行环境,你也可以使用一个集成开发环境,后者提供丰富的图形界面能够提高生产力.这一部分会罗列一些最流行的IDE工具.我不会推荐任何一款工具,你应该仔细定义你的需求列表并排出优先顺序,然后再看哪一款最能满足你的需求.还有许多其他的PL/SQL IDE工具,但上面罗列的这些足够了.

《Oracle PL/SQL程序设计(第5版)》一一第2章 创建并运行PL/SQL代码

第2章 创建并运行PL/SQL代码 Oracle PL/SQL程序设计(第5版)即便一个PL/SQL程序员从来不重视系统设计或者单元测试这样的任务,他也必须熟悉下面这些最基本的操作: 在数据库中导航:创建和编辑PL/SQL源代码:编译PL/SQL源代码,修正编译器发现的代码错误(或者,可选的,处理警告信息):在某些环境下运行编译后的程序:检查程序执行结果(可能是从屏幕上的输出,或者是根据表中的数据变化,等等).PL/SQL是寄生在Oracle执行环境中的(因此说它是"嵌入式语言"),这

《Oracle PL/SQL程序设计(第5版)》一一1.2 PL/SQL的起源

1.2 PL/SQL的起源 Oracle PL/SQL程序设计(第5版)Oracle公司一度领导软件工业为设计数据库和应用程序提供一种声明式的.非过程化的方法.Oracle数据库服务器是世界上最先进的.最强大的.最稳定的关系数据库.它的应用程序开发工具,比如Oracle Forms,通过提供大量的默认功能,提高了生产力水平,开发人员只要依靠"在屏幕上涂涂画画"的方法,就能避免自行开发的劳苦. 1.2.1 早期的PL/SQL 在早期的Oracle中,SQL的声明式方法,以及开天辟地的关系