Oracle PL/SQL Programming 第2章:Creating and Running PL/SQL Code 读书笔记

暂不考虑系统设计或单元测试之类的任务,所有 PL/SQL 程序员必须熟悉的基本操作任务包括:

  • 浏览数据库
  • 创建和编辑 PL/SQL 源代码
  • 编译 PL/SQL 源代码,并更正编译器注意到的任何代码错误和警告
  • 从某个环境执行编译后的程序
  • 检查程序执行的结果

与 C 等独立语言不同,PL/SQL 托管在 Oracle 执行环境中(它是一种嵌入式语言)。

浏览数据库

每个选择编写 PL/SQL 程序的人都是为了处理 Oracle 数据库的内容。您将需要检查数据库中的数据结构(表、列、序列、用户定义类型等),以及您将调用的任何现有存储程序的签名。 您可能还需要了解表的实际内容(列、约束等)。

您可以采用两种不同的方法进行数据库导航:

  • 使用 IDE(集成开发环境),我建议SQL Developer,他是原厂提供的免费工具。
  • 在 SQL*Plus,SQLcl等命令行环境中运行脚本,该环境会查询 ALL_OBJECTS 或 USER_OBJECTS 等数据字典视图的内容。

我建议以IDE为主 ,因为图形界面比脚本更容易使用和理解,而且效率更高。然后适当的结合命令行。

创建和编辑源代码

这是我建议使用IDE的一个重要原因。IDE可以提供代码格式化,调试,自动完成等便捷功能。

PL/SQL 的独特之处在于,程序的源代码必须先加载到数据库中,然后才能编译和执行。 因此存在许多代码管理问题,包括:

  • 程序员如何以及在哪里找到存储程序的"原始"副本?
  • 它存在于磁盘上还是仅存在于数据库中?
  • 我们如何以及多久执行一次备份?
  • 我们如何管理多开发人员对代码的访问? 也就是说,我们使用软件版本控制系统吗?

作者建议,"原始"源代码存储在文件中 - 不要使用 RDBMS 作为代码存储库

SQL*Plus

Oracle 的 SQL*Plus 作为 Oracle 前端的鼻祖,为 SQL 和 PL/SQL 提供了命令行解释器。 也就是说,它接受来自用户的语句,将它们发送到 Oracle 服务器,并显示结果。

SQL*Plus 是我最喜欢的 Oracle 工具之一(我也是)。 讽刺的是,该产品的前身被大胆命名为 UFI------用户友好界面,但至少它不会经常崩溃。

还有一个Java版的SQLcl,可以很好的补充SQL*Plus。

启动 SQL*Plus

sql 复制代码
[oracle@xy ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Jan 24 06:12:20 2024
Version 19.21.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.


Connected to:
Oracle Database 19c EE Extreme Perf Release 19.0.0.0.0 - Production
Version 19.21.0.0.0

SQL>

你可以在操作系统命令行中指定用户名口令,也可以在SQL>提示符下的connect命令中指定用户名和口令。

sql 复制代码
-- 操作系统下
OS> sqlplus username/password@service
-- SQL提示符下
OS> sqlplus /nolog
SQL> connect username/password@service

运行 SQL 语句

SQL*Plus 中 SQL 语句的默认终止符是分号,或者也可以用/来执行。

sql 复制代码
SQL>select sysdate from dual;

SYSDATE
---------
24-JAN-24

SQL> select sysdate from dual
  2  /

SYSDATE
---------
24-JAN-24

运行 PL/SQL 程序

SQL*Plus 默认抑制输出。 要使其显示,必须打开 SERVEROUTPUT:

sql 复制代码
SET SERVEROUTPUT ON
BEGIN
   DBMS_OUTPUT.PUT_LINE('Hello, World');
END;
/

可以将 SERVEROUTPUT 命令放在启动文件中(SQL*Plus 在每次 CONNECT 后自动重新运行启动文件),使其处于启用状态,直到发生以下情况之一:

  • 您断开连接、注销或以其他方式结束会话。
  • 您明确将 SERVEROUTPUT 设置为 OFF。
  • Oracle 数据库根据您的请求或由于编译错误而丢弃会话状态。

当您在SQL*Plus 中输入 SQL 或 PL/SQL 语句时,程序会为第一行之后的每一行分配一个编号。 行号有两个好处:

  1. 可以帮助您指定要使用内置行编辑器编辑哪一行
  2. 便于报告错误并附有行号

要告诉 SQL*Plus 您已完成输入 PL/SQL 语句,可以输入斜杠(/)。其有几个重要特征:

  • 斜杠的含义是"执行最近输入的语句",无论该语句是 SQL 还是 PL/SQL。
  • 斜杠是SQL*Plus特有的命令; 它不是 PL/SQL 语言的一部分,也不是 SQL 的一部分。
  • 它必须单独出现在一行上; 该行中不能包含其他命令。不够前后有空格也没关系

作为一项便利功能,SQL*Plus 为 PL/SQL 用户提供了 EXECUTE 命令,该命令可以节省键入 BEGIN、END 和尾部斜杠的时间。 因此,下面2段代码是等价的:

sql 复制代码
-- 方式1
SET SERVEROUTPUT ON
BEGIN
   DBMS_OUTPUT.PUT_LINE('Hello, World');
END;
/

-- 方式2
EXECUTE DBMS_OUTPUT.PUT_LINE('Hello, World');

尾随分号是可选的。 与大多数 SQL*Plus 命令一样,EXECUTE 可以缩写并且不区分大小写。

运行脚本

几乎任何在 SQLPlus 中交互工作的语句都可以存储在文件中以便重复执行。 运行此类脚本的最简单方法是使用 SQLPlus 的@ 命令。

sql 复制代码
SQL> @abc.sql

-- 等价形式
SQL> START abc.sql

-- 等价形式,默认的后缀是.sql
SQL> START abc

默认行为是仅在屏幕上显示各个语句的输出; 如果您想查看文件的原始来源,请使用 SQL*Plus 命令 SET ECHO ON。

特定于SQL *Plus的错误信息都是以SP2开头的,例如:

sql 复制代码
SQL> @aaa
SP2-0310: unable to open file "aaa.sql"

这里可以查询到所有SP2的错误信息。

什么是"当前目录"?

每当您从操作系统命令提示符启动 SQLPlus 时,SQLPlus 都会将操作系统的当前目录视为其自己的当前目录。

下面的例子也说明,在SQL *Plus里是不能切换目录的,要切换的话要退出重新进。

sql 复制代码
$ pwd
/home/oracle

$ sqlplus / as sysdba
SQL> !pwd
/home/oracle

SQL> ! cd /home

SQL> !pwd
/home/oracle

如果你的脚本不在当前目录,也可以指定绝对或相对路径:

sql 复制代码
SQL> @./test/1.sql
SQL> @/home/oracle/test/1.sql

在其他目录中运行脚本的想法提出了一个有趣的问题。 如果这个位于另一个目录中的脚本调用了其他脚本会怎样?

例如,在/tmp目录下有3个脚本文件:

sql 复制代码
$ ls /tmp/*sql
/tmp/1.sql  /tmp/2.sql  /tmp/all.sql

$ cat /tmp/all.sql
@1.sql
@2.sql

$ cat /tmp/1.sql
select '1.sql' from dual;

$ cat /tmp/2.sql
select '2.sql' from dual;

若我当前所在目录为/home/oracle,则执行报错,因为只会在当前目录下寻找其调用的脚本:

sql 复制代码
SQL> !pwd
/home/oracle

SQL> @/tmp/all.sql
SP2-0310: unable to open file "1.sql"
SP2-0310: unable to open file "2.sql"

解决办法有2种,其一是将/tmp加入SQLPATH中:

sql 复制代码
SQL> !echo $SQLPATH
/tmp

SQL> @/tmp/all.sql

'1.SQ
-----
1.sql


'2.SQ
-----
2.sql

其二是调用脚本时使用@@而非@,此时会在正在执行脚本的当前目录寻找脚本:

sql 复制代码
SQL> !echo $SQLPATH


SQL> !pwd
/home/oracle

-- 注意,此时使用了@@,而非@
SQL> !cat /tmp/all.sql
@@1.sql
@@2.sql

SQL> @/tmp/all.sql

'1.SQ
-----
1.sql


'2.SQ
-----
2.sql

其他 SQL*Plus 任务

设置您的偏好

使用SET设置偏好,使用SHOW查看偏好设置。

sql 复制代码
SQL> SHOW ALL
appinfo is OFF and set to "SQL*Plus"
arraysize 15
autocommit OFF
...

SQL> SHOW arraysize
arraysize 15
SQL> set arraysize
SP2-0267: arraysize option 0 out of range (1 through 5000)
SQL> SET arraysize 100
SQL> SHOW arraysize
arraysize 100

SQL*Plus中可以定义自己的变量,可以有3类:

  1. 系统变量。也就是设置偏好时使用SET设置的变量
  2. 替换变量或DEFINE变量
  3. 绑定变量

替换变量用DEFINE定义,然后用&或&&引用,SQL *Plus只是简单的替换其值。替换变量是当做字符串看待的。

sql 复制代码
SQL> define a='hello'
SQL> define a
DEFINE A               = "hello" (CHAR)

SQL> select '&a' from dual;
old   1: select '&a' from dual
new   1: select 'hello' from dual

'HELL
-----
hello

下例说明了&和&&的区别,&&会记录下你输入的值:

sql 复制代码
SQL> undefine a
SQL> select '&a' from dual;
Enter value for a: hello
old   1: select '&a' from dual
new   1: select 'hello' from dual

'HELL
-----
hello

SQL> define a
SP2-0135: symbol a is UNDEFINED
SQL> select '&&a' from dual;
Enter value for a: hello
old   1: select '&&a' from dual
new   1: select 'hello' from dual

'HELL
-----
hello

SQL> define a
DEFINE A               = "hello" (CHAR)

SQL *Plus也有内置的DEFINE变量:

sql 复制代码
SQL> define
DEFINE _DATE           = "24-JAN-24" (CHAR)
DEFINE _CONNECT_IDENTIFIER = "" (CHAR)
DEFINE _USER           = "" (CHAR)
DEFINE _PRIVILEGE      = "" (CHAR)
DEFINE _SQLPLUS_RELEASE = "1903000000" (CHAR)
DEFINE _EDITOR         = "vi" (CHAR)
DEFINE _O_VERSION      = "Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0" (CHAR)
DEFINE _O_RELEASE      = "1903000000" (CHAR)
DEFINE _RC             = "0" (CHAR)

绑定变量用VARIABLE定义:

sql 复制代码
SQL>
VARIABLE x VARCHAR2(10)
BEGIN
   :x := 'hello';
END;
/

SQL> PRINT :x

X
--------------------------------
hello

这3种变量的用法非常丰富,详见这篇非常好的文章SQL*Plus Substitution Variables - DEFINE variables and parameters in SQL Queries

将输出保存到文件

使用SPOOL进行假脱机操作。

下例会将脚本test.sql的输出存放在文件report.lst中。

sql 复制代码
-- 默认的文件后缀为lst,也可以指定后缀
SPOOL report
@test.sql
SPOOL OFF
退出 SQL*Plus
sql 复制代码
SQL> EXIT

如果退出时恰好正在进行假脱机操作,SQL*Plus 将停止假脱机操作并关闭假脱机文件。

如果执行EXIT时,有未提交的事务,默认情况下,SQL*Plus会强制执行commit。此行为是由以下变量控制的:

sql 复制代码
SQL> show exitcommit
exitcommit ON

和EXIT不同,DISCONNECT命令会与数据库断开,但不会退出 SQL*Plus:

sql 复制代码
SQL> DISCONNECT
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

虽然CONNECT命令会隐式的断开之前的连接,但显式(主动)的DISCONNECT是一个好习惯,如可避免安全隐患。

编辑语句

SQL*Plus 将最近发出的语句(准确的说,是SQL语句)保留在缓冲区中,您可以使用内置行编辑器或您选择的外部编辑器来编辑此语句。

sql 复制代码
SQL> EDIT

查看默认的编辑器:

sql 复制代码
SQL> define _editor
DEFINE _EDITOR         = "vi" (CHAR)
启动时自动加载您自己的自定义环境

可以将一些设置存入文件glogin.sql和login.sql。SQL*Plus在启动时会调用这些文件。

如果两个文件都存在,则执行 glogin.sql,然后执行 login.sql; 如果发生冲突,则以最后一个设置为准。

以下为一个login.sql示例:

sql 复制代码
define _editor=vi
set serveroutput on size 1000000
set trimspool on
set long 5000
set linesize 100
set pagesize 9999
set sqlprompt '&_user.@&_connect_identifier.> '

注意,处于安全考虑,SQL*Plus只在$ORACLE_PATH下寻找启动脚本。

SQL*Plus 中的错误处理

对于大多数特定于 SQL*Plus 的命令,没有错误消息即可表示成功。 另一方面,成功的 SQL 和 PL/SQL 命令通常会产生某种积极的文本反馈。

如果 SQLPlus 在 SQL 或 PL/SQL 语句中遇到错误,默认情况下它将报告错误并继续处理。 这在交互式执行时是可取的。 但在执行脚本时,很多情况下您会希望出错时退出SQLPlus。 使用以下命令来实现这一点:

sql 复制代码
SQL> WHENEVER SQLERROR EXIT SQL.SQLCODE

例如:

sql 复制代码
SQL> WHENEVER SQLERROR EXIT SQL.SQLCODE
SQL> select 1 from aaa;
select 1 from aaa
              *
ERROR at line 1:
ORA-00942: table or view does not exist

Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[oracle@oracle-19c-vagrant ~]$ echo $?
174

如上例,SQLCODE可以被调用其的shell环境接收到。按shell的约定,成功时的返回值为0,失败时为非0。

下面的命令,除了错误时退出外,还会回退未提交的事务:

sql 复制代码
SQL> WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK

为什么你会又爱又恨 SQL*Plus

爱的一面:

  • 使用 SQL*Plus,您可以运行"批处理"程序,在 sqlplus 命令行上提供特定于应用程序的参数,并使用 &1(第一个参数)、&2(第二个参数)等在脚本中引用它们。
  • SQL*Plus 为所有SQL 和PL/SQL 语句提供完整且最新的支持。 当您使用 Oracle 独有的功能时,这一点非常重要。 第三方环境可能无法提供100%的覆盖。
  • Oracle数据库自带SQLPlus,Oracle数据库支持的所有平台,SQLPlus都可以运行。

恨的一面:

  • 在SQL*Plus 的控制台版本中,语句缓冲区仅限于最近使用的语句。 SQLcl可以解决这个问题。
  • 对于 SQL*Plus,不存在现代命令解释器功能,例如自动完成关键字或在您键入语句时提示哪些数据库对象可用。SQLcl和SQL Developer可以
  • 联机帮助包含SQL*Plus 命令集的最少文档。 (使用 HELP 命令获取特定命令的帮助。) Oracle文档可以很方便的在线查或离线下载
  • 一旦启动SQL*Plus,就无法更改当前目录。SQLcl同样也不行

不过,最重要的是,SQL*Plus 是一个"真正的程序员"工具,它无处不在,不会崩溃,而且只要有Oracle公司存在,它就可能得到支持。

执行基本 PL/SQL 任务

让我们重点讨论使用 SQL*Plus 作为前端来创建、运行、删除和以其他方式管理 PL/SQL 程序。 这里只简略介绍一下,后面的章节中会更详细地介绍。

创建存储程序

这里所说的存储程序(Stored Program)是指(存储)过程或函数,因为他们会存储在你的schema中。

要构建新的存储 PL/SQL 程序,您可以使用 SQL 的 CREATE 语句。 如CREATE FUNCTION 和CREATE PROCEDURE,例如:

sql 复制代码
CREATE FUNCTION wordcount (str IN VARCHAR2)
   RETURN PLS_INTEGER
AS
   在此处声明本地变量
BEGIN
   在此处实现算法
END;
/

与前面显示的简单 BEGIN-END 块一样,尾部的斜杠表示执行。

假设 DBA 已授予您 Oracle 的 CREATE PROCEDURE 权限(这也授予您创建函数的权限),该语句会导致 Oracle 编译此存储函数并将其存储在您的模式中。

如果 Oracle 模式中已存在同名的另一个数据库对象(例如表或包),则 创建将失败,并显示错误消息 ORA-00955: name is already used by an existing object。 这就是 Oracle 提供 OR REPLACE 选项的原因之一,您可能在绝大多数情况下都应该使用该选项:

sql 复制代码
CREATE OR REPLACE FUNCTION ...

OR REPLACE 选项避免了删除并重新创建程序的副作用; 换句话说,它保留您授予其他用户或角色的任何对象权限。 幸运的是,它仅替换相同类型的对象,并且不会仅仅因为您决定使用该名称创建一个函数而自动删除同名的表。

与多次使用的匿名块一样,程序员通常将这些创建语句存储在操作系统的文件中。 然后可以使用 SQL*Plus 的@ 命令来运行它。

默认情况下,SQL*Plus 不会回显脚本的内容。 如需要,您可以SET ECHO ON 以查看屏幕上滚动过去的源代码,包括数据库分配的行号; 当您排除故障时,此设置会很有帮助。 不过,通常不会在脚本中包含 SET ECHO ON,而是在需要时在命令行中键入它。

下面是一个函数的例子,输入一个数字,返回3个字符的月份字符串:

sql 复制代码
create or replace function to_month(m in integer)
    return varchar2
as
    invalid_month EXCEPTION;
    TYPE m_array_type IS TABLE OF varchar2(16) INDEX BY pls_integer;
    ma m_array_type;
begin
    ma(1) := 'Jan';
    ma(2) := 'Feb';
    ma(3) := 'Mar';
    ma(4) := 'Apr';
    ma(5) := 'May';
    ma(6) := 'Jun';
    ma(7) := 'Jul';
    ma(8) := 'Aug';
    ma(9) := 'Sep';
    ma(10) := 'Oct';
    ma(11) := 'Nov';
    ma(12) := 'Dec';
    
    if m between 1 and 12 then
        return ma(m);
    else
        RAISE invalid_month;
    end if;
end;
/

如果创建失败,查看错误消息全文的最快方法是使用 SQL*Plus的 SHOW ERRORS 命令,缩写为 SHO ERR:

sql 复制代码
SQL> SHO ERR

例如,在上面的函数定义中,如果将INDEX BY pls_integer改为INDEX BY pls_integer,则会报错如下:

sql 复制代码
SQL> show error
Errors for FUNCTION SYS.TO_MONTH:

LINE/COL ERROR
-------- -----------------------------------------------------------------
5/5      PL/SQL: Item ignored
5/26     PLS-00315: Implementation restriction: unsupported table index type
8/5      PL/SQL: Statement ignored
8/14     PLS-00382: expression is of wrong type
9/5      PL/SQL: Statement ignored
9/14     PLS-00382: expression is of wrong type
10/5     PL/SQL: Statement ignored
10/14    PLS-00382: expression is of wrong type
11/5     PL/SQL: Statement ignored
11/14    PLS-00382: expression is of wrong type
12/5     PL/SQL: Statement ignored
12/14    PLS-00382: expression is of wrong type
13/5     PL/SQL: Statement ignored
13/14    PLS-00382: expression is of wrong type
14/5     PL/SQL: Statement ignored
14/14    PLS-00382: expression is of wrong type
15/5     PL/SQL: Statement ignored
15/14    PLS-00382: expression is of wrong type
16/5     PL/SQL: Statement ignored
16/14    PLS-00382: expression is of wrong type

SHOW ERRORS 实际上只是查询数据字典中 Oracle 的 USER_ERRORS 视图。 您可以自己查询该视图,但通常不需要(请参阅下面的边栏)。

您可以在 SHOW ERRORS 中附加对象类别和名称,它将显示任何对象的最新错误:

sql 复制代码
SQL> SHOW ERRORS category [schema.]object

例如,要查看funca函数的最新错误:

sql 复制代码
SHOW ERRORS FUNCTION to_month

如果显示如下信息:

sql 复制代码
No errors.

则有以下三种可能性:(1)对象编译成功; (2) 你给出了错误的类别(例如,函数而不是过程); 或 (3) 不存在具有该名称的对象。

以下是category的完整列表,可能因版本而异:

sql 复制代码
DIMENSION
FUNCTION
JAVA SOURCE
JAVA CLASS
PACKAGE
PACKAGE BODY
PROCEDURE
TRIGGER
TYPE
TYPE BODY
VIEW

通常的做法是在构建存储的 PL/SQL 程序的每个脚本化 CREATE 语句之后附加 SHOW ERRORS 命令。 因此,在 SQL*Plus 中构建存储程序的"最佳实践"模板可能会以这种形式开始:

sql 复制代码
CREATE OR REPLACE program-type
AS
   你的代码
END;
/

SHOW ERRORS

当你的程序包含编译器可以检测到的错误时,CREATE仍然 会导致Oracle数据库将该程序存储在数据库中,但处于无效状态。 但是,如果您输错了部分 CREATE 语法,数据库将无法确定您要执行的操作,并且不会将代码存储在数据库中。

执行存储的程序

我们已经研究了调用存储程序的两种不同方法:将其包装在简单的 PL/SQL 块中或使用 SQL*Plus EXECUTE 命令。 您还可以在其他存储的程序中使用存储的程序。

例如,在下例中,funca作为一个表达式,并作为DBMS_OUTPUT.PUT_LINE的参数:

sql 复制代码
BEGIN
   DBMS_OUTPUT.PUT_LINE('Month 1 is: ' || to_month(1));
END;
/

您还可以在 SQL 语句中调用许多 PL/SQL 函数。 以下是几个示例:

  • 在SELECT列表中调用函数:
sql 复制代码
select to_month(4) from dual;

使用符合 ANSI 的 CALL 语句,将函数输出绑定到 SQL*Plus 变量,并显示结果:

sql 复制代码
VARIABLE mon varchar2
CALL to_month(1) INTO :mon;
PRINT :mon

与上面相同,但从数据库链接foo.bar.com中定义的远程数据库执行该函数。

sql 复制代码
CALL to_month@foo.bar.com(1) INTO :mon;

登录到任何具有适当授权的模式时,执行模式 bob 拥有的函数:

sql 复制代码
SELECT bob.to_month(1) FROM ...;

显示存储的程序

迟早您会想要获得您拥有的存储程序的列表,并且您可能还需要查看 Oracle 在其数据字典中保存的程序源的最新版本。

例如,要查看程序的完整列表(以及表、索引等),请查询 USER_OBJECTS 视图。该视图显示名称、类型、创建时间、最新编译时间、状态(有效或无效)和其他有用信息。

sql 复制代码
SELECT * FROM USER_OBJECTS;

如果您需要的只是 SQL*Plus 中 PL/SQL 程序的可调用接口的摘要,那么最简单的命令是 DESCRIBE:

sql 复制代码
SQL> DESCRIBE to_month
FUNCTION to_month RETURNS VARCHAR2
Argument Name Type       In/Out Default? 
------------- ---------- ------ -------- 
M             NUMBER(38) IN  

DESCRIBE 还适用于表、视图、对象类型、过程和包。 要查看存储程序的完整源代码,请查询 USER_SOURCE 或 TRIGGER_SOURCE。 (第 20 章将进一步详细讨论从这些数据字典视图进行查询。)

管理存储程序的授权和同义词

当您第一次创建 PL/SQL 程序时,通常除了您或 DBA 之外没有人可以执行它。 要授予其他用户执行您的程序的权限,请发出 GRANT 语句:

sql 复制代码
GRANT EXECUTE ON to_month TO ssb;

要删除权限,请使用 REVOKE:

sql 复制代码
REVOKE EXECUTE ON to_month FROM ssb;

您还可以向角色授予 EXECUTE 权限:

sql 复制代码
create role my_role;
GRANT EXECUTE ON to_month TO my_role;

或者,您可以允许当前数据库上的任何用户运行该程序:

sql 复制代码
GRANT EXECUTE ON to_month TO PUBLIC;

如果您向像 Scott 这样的个人以及该用户所属的角色(例如 my_role)授予特权,并将其授予 PUBLIC,则数据库会记住所有三个授予,直到它们被撤销。 任何一项授权都足以允许个人运行该程序,因此,如果您决定不希望 Scott 运行该程序,您必须撤销 Scott 的特权,并从 PUBLIC 撤销它,最后从角色撤销他。

要查看您授予其他用户和角色的权限列表,您可以查询 USER_TAB_PRIVS_MADE 数据字典视图。 有点违反直觉的是,PL/SQL 程序名称出现在 table_name 列中:

sql 复制代码
SELECT table_name, grantee, privilege
FROM USER_TAB_PRIVS_MADE
WHERE table_name = 'TO_MONTH';

TABLE_NAME    GRANTEE    PRIVILEGE    
TO_MONTH      PUBLIC     EXECUTE      
TO_MONTH      SSB        EXECUTE      
TO_MONTH      MY_ROLE    EXECUTE

当 ssb确实拥有 to_month的 EXECUTE 权限时,他可能会想要为该程序创建一个同义词,以避免在其前面加上拥有该程序的模式名称的前缀:

现在他可以通过仅引用同义词来执行其他schema中的程序:

sql 复制代码
connect foo
CREATE OR REPLACE SYNONYM to_month FOR bar.to_month ;
-- 以前需要写bar.tomonth,现在可以写成to_month

这是一件好事,因为如果函数的所有者发生变化,则只有同义词(而不是任何存储的程序)需要修改。

可以为过程、函数、包或用户定义类型创建同义词。 过程、函数或包的同义词不仅可以隐藏模式,还可以隐藏实际的数据库; 您可以像本地程序一样轻松地为远程程序创建同义词。 然而,同义词只能隐藏模式和数据库标识符; 您不能使用同义词代替打包的子程序。

删除同义词很容易:

sql 复制代码
DROP SYNONYM ...

删除存储的程序

如果你真的不再需要某个特定的存储程序,你可以使用 SQL 的 DROP 语句删除它:

sql 复制代码
DROP FUNCTION to_month;

您可以删除一个包,该包最多可以完整地由两个元素(规范和主体)组成:

sql 复制代码
DROP PACKAGE pkgname;

或者你可以只删除主体而不使相应的规范无效:

sql 复制代码
DROP PACKAGE BODY pkgname;

每当您删除其他程序调用的程序时,调用者都会被标记为无效。

隐藏存储程序的源代码

当您按前面所述创建 PL/SQL 程序时,源代码将以明文形式存在于数据字典中,任何 DBA 都可以查看甚至更改它。 为了保护商业秘密或防止代码被篡改,您可能需要在交付 PL/SQL 源代码之前通过某种方式对其进行混淆。

Oracle 提供了一个名为wrap 的命令行实用程序,它将许多CREATE 语句转换为纯文本和十六进制的组合。 这不是真正的加密,但它确实对隐藏代码大有帮助。

如果您需要真正的加密(例如,传递确实需要安全的密码等信息),则不应依赖此设施。

要了解有关 wrap 实用程序的更多信息,请参阅第 20 章。

PL/SQL 编辑环境

Quest软件公司提供了Toad和SQL Navigator;Allround Automations提供了PL/SQL Developer。我还是建议用Oracle提供的SQL Developer,免费还强大。

从其他语言调用 PL/SQL

C:使用Oracle的预编译器(Pro*C)

Oracle 至少为 Oracle 提供了两种不同的 C 语言接口:一种称为 OCI(Oracle Call Interface),这主要是火箭科学家的领域,另一种称为 ProC。 OCI 提供了数百个函数,您必须从中编写低级操作,例如打开、解析、绑定、定义、执行、获取...而这仅适用于单个查询。 因为执行任何有趣操作的最简单的 OCI 程序大约有 200 行长,所以我想我应该展示一个 ProC 示例。 Pro*C 是一种预编译器技术,允许您构建包含 C、SQL 和 PL/SQL 混合的源文件。 Oracle 的 proc 程序最终还是会生成 C 代码。

Pro*C虽然不如C那么纯粹, 相信我,您不想弄乱生成的 C 代码。 但对某些用户而言,可能会觉得比C简单。

Oracle 自己的文档提供了有关 Pro*C 的最佳信息来源。

Java:使用 JDBC

与 C 一样,Oracle 提供了许多不同的方法来连接数据库。 嵌入式 SQL 方法(称为 SQLJ)与 Oracle 的其他预编译器技术类似,不过调试器更友好一些。 一种更流行且以 Java 为中心的方法称为 JDBC(它并不真正代表任何东西),尽管通常的解释是"Java 数据库连接":

sql 复制代码
...
DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:o92",
                             "scott", "tiger");
...

这个特定的示例使用瘦驱动程序,它提供了良好的兼容性和易于安装(所有网络协议智能都存在于 Java 库中),但会牺牲一些通信性能。 另一种方法是使用所谓的 OCI 驱动程序。

关于thin driver和OCI driver,详见1.1 Overview of Oracle JDBC Drivers

Perl:使用 Perl DBI 和 DBD::Oracle

Perl 深受系统管理社区的喜爱,可以说是所有开源语言之母。 现在在 5.10 版本中,它几乎可以完成所有操作,并且似乎可以在任何地方运行。 借助 CPAN(综合 Perl 存档网络)等漂亮的自动配置工具,安装社区提供的模块(例如数据库接口 (DBI) 和相应的 Oracle 驱动程序 DBD::Oracle)变得轻而易举。

Perl 是一种很容易编写出无法阅读的代码的语言。 它也不是一种特别快或特别小的语言,但有一些编译版本至少可以解决速度问题。

有关 Perl 和 Oracle 的更多信息,请参阅 Alligator Descartes 和 Tim Bunce 编写的《Programming the Perl DBI》。 还有许多关于 Perl 语言的优秀书籍,更不用说 perl.com(O'Reilly 的一个站点)、perl.orgcpan.org 上的在线信息。

Python

虽然作者没有提到,但是我觉得他在目前应该占一席之地。

PHP:使用 Oracle 扩展

如果您是那种可能会使用免费且广受欢迎的 Web 服务器(Apache)的人,那么您可能也会喜欢使用免费且广受欢迎的编程语言(PHP)。 PHP 通常用于构建动态网页,也可用于构建 GUI 应用程序或运行命令行程序。 正如您所料,Oracle 是与 PHP 配合使用的众多数据库环境之一。

PL/SQL 服务器页面

尽管 PL/SQL Server Pages (PSP) 环境是 Oracle 专有的,但我想我会提到它,因为它是启动和运行网页的快速方法。 PSP是另一种预编译技术; 它允许您将 PL/SQL 嵌入到 HTML 页面中。 这里的 <%= %> 结构意味着"将其作为 PL/SQL 处理并将结果返回到页面:"

我非常喜欢 PL/SQL Server Pages,它是一种快速组合数据驱动网站的好方法。

有关 PL/SQL Server Pages 的更多信息,请参阅书籍:Learning Oracle PL/SQL。

还有其他地方吗?

您已经了解了如何在 SQL*Plus 以及许多其他常见环境和编程语言中使用 PL/SQL。 还有更多地方和方式可以使用 PL/SQL:

  • 嵌入COBOL或FORTRAN并使用Oracle的预编译器进行处理
  • 使用某种 ODBC 风格从 Visual Basic 调用
  • 通过名为 SQL*Module 的技术从 Ada 编程语言调用
  • 自动执行,作为 Oracle 数据库中事件(例如表更新)的触发器
  • 通过 DBMS_SCHEDULER 提供的包安排在 Oracle 数据库内定期执行
  • TimesTen数据库是Oracle公司收购的内存数据库,可以像关系数据库一样用PL/SQL代码操作其内容

单词

  • nuances 细微差别
  • consternation 惊愕
  • drumroll 击鼓
  • calibrate 校准
相关推荐
chenyang_884 小时前
MySQL——statement对象详解
数据库·mysql·oracle
六月的雨__5 小时前
房屋租赁管理小程序的设计
java·sql·学习·小程序
不爱洗脚的小滕7 小时前
【MySQL】SQL注入的介绍
数据库·sql·mysql
java6666688888 小时前
SQL游标的原理与在数据库操作中的应用
数据库·sql·oracle
baozongwi10 小时前
ctfshow sqli-libs web561--web568
数据库·经验分享·python·sql·mysql·web安全
六月的雨__10 小时前
跑腿平台小程序的设计
java·sql·学习·小程序
ItKevin爱java12 小时前
JDBC中如何处理数据库连接超时和SQL超时?
数据库·sql
2401_8576226612 小时前
【SQL Server高可用性全解】构建永不宕机的数据库解决方案
数据库·oracle
youhebuke22512 小时前
SQLAlchemy pool_pre_ping
数据库·oracle·sqlalchemy
白菜!!!12 小时前
SQL INSERT批量插入方式
数据库·sql·mysql·mybatis