当前位置: 首页 > news >正文

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

总的目录和进度,请参见开始读 Oracle PL/SQL Programming 第6版

暂不考虑系统设计或单元测试之类的任务,所有 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

[oracle@xy ~]$ sqlplus / as sysdbaSQL*Plus: Release 19.0.0.0.0 - Production on Wed Jan 24 06:12:20 2024
Version 19.21.0.0.0Copyright (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.0SQL>

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

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

运行 SQL 语句

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

SQL>select sysdate from dual;SYSDATE
---------
24-JAN-24SQL> select sysdate from dual2  /SYSDATE
---------
24-JAN-24

运行 PL/SQL 程序

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

SET SERVEROUTPUT ON
BEGINDBMS_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段代码是等价的:

-- 方式1
SET SERVEROUTPUT ON
BEGINDBMS_OUTPUT.PUT_LINE('Hello, World');
END;
/-- 方式2
EXECUTE DBMS_OUTPUT.PUT_LINE('Hello, World');

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

运行脚本

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

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

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

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

SQL> @aaa
SP2-0310: unable to open file "aaa.sql"

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

什么是“当前目录”?

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

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

$ pwd
/home/oracle$ sqlplus / as sysdba
SQL> !pwd
/home/oracleSQL> ! cd /homeSQL> !pwd
/home/oracle

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

SQL> @./test/1.sql
SQL> @/home/oracle/test/1.sql

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

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

$ 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> !pwd
/home/oracleSQL> @/tmp/all.sql
SP2-0310: unable to open file "1.sql"
SP2-0310: unable to open file "2.sql"

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

SQL> !echo $SQLPATH
/tmpSQL> @/tmp/all.sql'1.SQ
-----
1.sql'2.SQ
-----
2.sql

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

SQL> !echo $SQLPATHSQL> !pwd
/home/oracle-- 注意,此时使用了@@,而非@
SQL> !cat /tmp/all.sql
@@1.sql
@@2.sqlSQL> @/tmp/all.sql'1.SQ
-----
1.sql'2.SQ
-----
2.sql

其他 SQL*Plus 任务

设置您的偏好

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

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> 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> 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
-----
helloSQL> 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
-----
helloSQL> define a
DEFINE A               = "hello" (CHAR)

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

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>
VARIABLE x VARCHAR2(10)
BEGIN:x := 'hello';
END;
/SQL> PRINT :xX
--------------------------------
hello

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

将输出保存到文件

使用SPOOL进行假脱机操作。

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

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

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

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

SQL> show exitcommit
exitcommit ON

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

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> EDIT

查看默认的编辑器:

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

可以将一些设置存入文件glogin.sql和login.sql。SQL*Plus在启动时会调用这些文件。
如果两个文件都存在,则执行 glogin.sql,然后执行 login.sql; 如果发生冲突,则以最后一个设置为准。

以下为一个login.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> WHENEVER SQLERROR EXIT SQL.SQLCODE

例如:

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 existDisconnected 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> 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,例如:

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 选项的原因之一,您可能在绝大多数情况下都应该使用该选项:

CREATE OR REPLACE FUNCTION ...

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

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

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

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

create or replace function to_month(m in integer)return varchar2
asinvalid_month EXCEPTION;TYPE m_array_type IS TABLE OF varchar2(16) INDEX BY pls_integer;ma m_array_type;
beginma(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 thenreturn ma(m);elseRAISE invalid_month;end if;
end;
/

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

SQL> SHO ERR

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

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> SHOW ERRORS category [schema.]object

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

SHOW ERRORS FUNCTION to_month

如果显示如下信息:

No errors.

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

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

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你的代码
END;
/SHOW ERRORS

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

执行存储的程序

我们已经研究了调用存储程序的两种不同方法:将其包装在简单的 PL/SQL 块中或使用 SQL*Plus EXECUTE 命令。 您还可以在其他存储的程序中使用存储的程序。
例如,在下例中,funca作为一个表达式,并作为DBMS_OUTPUT.PUT_LINE的参数:

BEGINDBMS_OUTPUT.PUT_LINE('Month 1 is: ' || to_month(1));
END;
/

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

  • 在SELECT列表中调用函数:
select to_month(4) from dual;

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

VARIABLE mon varchar2
CALL to_month(1) INTO :mon;
PRINT :mon

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

CALL to_month@foo.bar.com(1) INTO :mon;

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

SELECT bob.to_month(1) FROM ...;

显示存储的程序

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

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

SELECT * FROM USER_OBJECTS;

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

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 语句:

GRANT EXECUTE ON to_month TO ssb;

要删除权限,请使用 REVOKE:

REVOKE EXECUTE ON to_month FROM ssb;

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

create role my_role;
GRANT EXECUTE ON to_month TO my_role;

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

GRANT EXECUTE ON to_month TO PUBLIC;

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

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

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中的程序:

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

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

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

删除同义词很容易:

DROP SYNONYM ...

删除存储的程序

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

DROP FUNCTION to_month;

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

DROP PACKAGE pkgname;

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

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 数据库连接”:

...
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.org 和 cpan.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 校准

相关文章:

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

总的目录和进度&#xff0c;请参见开始读 Oracle PL/SQL Programming 第6版 暂不考虑系统设计或单元测试之类的任务&#xff0c;所有 PL/SQL 程序员必须熟悉的基本操作任务包括&#xff1a; 浏览数据库创建和编辑 PL/SQL 源代码编译 PL/SQL 源代码&#xff0c;并更正编译器注…...

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Swiper容器组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Swiper容器组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Swiper容器组件 滑块视图容器&#xff0c;提供子组件滑动轮播显示的能力。…...

『建议收藏』OpenAI官方出的Prompt提示词教程中文版来了!

一些结论 六大策略: 写清晰的指令 提供参考文本 将复杂任务分解为更简单的子任务 给模型时间“思考” 使用外部工具 系统性测试变化 提高结果质量的六大策略 写清晰的指令 这些模型无法读懂你的想法。如果输出过长&#xff0c;要求简短回复&#xff1b;如果输出过于简单…...

牛刀小试 - C++ 推箱子小游戏

参考文档 C笔记&#xff1a;推箱子小游戏 copy函数 memcpy()函数用法&#xff08;可复制数组&#xff09; 使用memcpy踩出来的坑&#xff0c;值得注意 完整代码 /********************************************************************* 程序名:推箱子小游戏 说明&#x…...

手机视频压缩怎么压缩?一键瘦身~

现在手机已经成为我们日常生活中必不可少的工具&#xff0c;而在手机的应用领域中&#xff0c;文件的传输和存储是一个非常重要的问题。很多用户都会遇到这样一个问题&#xff0c;那就是在手机上存储的文件太多太大&#xff0c;导致手机存储空间不足&#xff0c;那么怎么在手机…...

目标主力能源:华为智能光伏的时代指南针

让新能源成为人类主要的能源来源&#xff0c;是实现“双碳目标”的核心方案。而光伏能源则是目前新能源体系中的主要选择之一。以光伏为核心构建新型电力系统&#xff0c;让光伏能源成为主力能源值得关注和期待。 过去几年&#xff0c;光伏能源极速发展。但如何百尺竿头更进一步…...

每日一题 力扣2846 边权重均等查询

2846. 边权重均等查询 题目描述&#xff1a; 现有一棵由 n 个节点组成的无向树&#xff0c;节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges &#xff0c;其中 edges[i] [ui, vi, wi] 表示树中存在一条位于节点 ui 和节点 vi 之间、权重…...

【Docker】Docker学习⑨ - 单机编排之Docker Compose

【Docker】Docker学习⑨ - 单机编排之Docker Compose 一、Docker简介二、Docker安装及基础命令介绍三、Docker镜像管理四、Docker镜像与制作五、Docker数据管理六、网络部分七、Docker仓库之单机Dokcer Registry八、Docker仓库之分布式Harbor九、单机编排之Docker Compose1 基础…...

ES6笔记-symbol

ES6 symbol 是什么 ES5的对象属性名是字符串&#xff0c;这容易造成属性名的冲突。symbol是一种机制&#xff0c;保证每个属性的名字都是独一无二的。这样就从根本上防止属性名冲突。 它是一种原始数据类型Symbol,表示独一无二的值。它属于javaScript语言的原生数据类型之一。…...

C++设计模式介绍:优雅编程的艺术

物以类聚 人以群分 文章目录 简介为什么有设计模式&#xff1f; 设计模式七大原则单一职责原则&#xff08;Single Responsibility Principle - SRP&#xff09;开放封闭原则&#xff08;Open/Closed Principle - OCP&#xff09;里氏替换原则&#xff08;Liskov Substitution …...

GitLab升级版本(任意用户密码重置漏洞CVE-2023-7028)

目录 前言漏洞分析影响范围查看自己的GitLab版本升级路程 升级过程13.1.1113.8.8 - 14.0.1214.3.614.9.5 - 16.1.6 前言 最近GitLab发了个紧急漏洞需要修复&#xff0c;ok接到命令立刻着手开始修复&#xff0c;在修复之前先大概了解一下这个漏洞是什么东西 漏洞分析 1、组件…...

Unity——八叉树的原理与实现

八叉树原理 八叉树&#xff08;Octree&#xff09;是一种用于在三维空间中进行空间分割的数据结构。它将三维空间递归地划分为八个子空间&#xff0c;每个子空间对应于一个八叉树节点。这种分割方式可以有效地组织和管理场景中的对象&#xff0c;提高检索效率&#xff0c;特别…...

android 自定义软键盘的显示和隐藏

记一下,以后不用找在InputMethodService中有这两个方法可以看到软键盘显示状态 //软键盘隐藏 override fun onWindowHidden() {super.onWindowHidden() } //软键盘显示 override fun onWindowShown() {super.onWindowShown() } 在activity中可以通过这种方法看到软键盘显示状…...

基于openssl v3搭建ssl安全加固的c++ tcpserver

1 概述 tcp server和tcp client同时使用openssl库&#xff0c;可对通信双方流通的字节序列进行加解密&#xff0c;保障通信的安全。本文以c编写的tcp server和tcp client为例子&#xff0c;openssl的版本为v3。 2 安装openssl v3 2.1 安装 perl-IPC-Cmd openssl项目中的co…...

11.2 Web开发_CSS入门(❤❤)

11.2 Web开发_CSS入门❤❤ 1. CSS简介1.1 基础案例2. CSS书写的位置2.1 行内式2.2 内嵌式2.3 外链式3. CSS基础选择器3.1 标签选择器3.2 id选择器3.3 类选择器3.4 选择器优先级3.5 通配符选择器4. 多类名5. 样式的两种特性5.1 层叠性...

[docker] Docker的数据卷、数据卷容器,容器互联

一、数据卷&#xff08;容器与宿主机之间数据共享&#xff09; 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立刻可见&#xff0c;并且更新数据不会影响镜像&#xff0c;从而实现数据在宿主机与容…...

ATF(TF-A)安全通告TF-V11——恶意的SDEI SMC可能导致越界内存读取(CVE-2023-49100)

目录 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) 二、透过事务看本质SDEI是干啥的呢&#xff1f; 三、CVE-2023-49100 1、GICv2 systems 2、GICv3 systems 四、漏洞修复 一、ATF(TF-A)安全通告TFV-11 (CVE-2023-49100) Title 恶意的SDEI SMC可能导致越界内存读取&am…...

如何查找SpringBoot应用中的请求路径(不使用idea)

背景 昨天有个同事向我咨询某个接口的物理表是哪个&#xff0c;由于公司业务较多、这块业务的确不是我负责的&#xff0c;也没有使用idea不能全局搜索(eclipse搜不到jar内的字符串)&#xff0c;也就回复了不清楚。 除了自己写代码输出servlet的路径和类外&#xff0c;发现了一…...

56. 合并区间 - 力扣(LeetCode)

题目描述 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 题目示例 输入&#xff1a;intervals [[1,3…...

数据结构篇-03:堆实现优先级队列

本文着重在于讲解用 “堆实现优先级队列” 以及优先级队列的应用&#xff0c;在本文所举的例子中&#xff0c;可能使用优先级队列来解并不是最优解法&#xff0c;但是正如我所说的&#xff1a;本文着重在于讲解“堆实现优先级队列” 堆实现优先级队列 堆的主要应用有两个&…...

linux clickhouse 安装

1、官网下载clickhouse安装包 下载地址&#xff0c; clickhouse分lts和stable版本&#xff0c;lts是长期版本&#xff0c;一般选择安装lts版本。 其中clickhouse-server是clickhouse服务&#xff0c;就是用来访问数据存储数据&#xff0c;clickhouse-client是用来通过命令访问数…...

【游戏客户端开发的进阶路线】

*** 游戏客户端开发的进阶路线 春招的脚步越来越近&#xff0c;我们注意到越来越多的同学们都在积极学习游戏开发&#xff0c;希望能在这个充满活力的行业中大展拳脚。 当我们思考如何成为游戏开发领域的佼佼者时&#xff0c;关键在于如何有效规划学习路径。 &#x1f914; 我…...

vue3+naiveUI二次封装的v-model 联动输入框

根据官网说明使用 源码 <template><div class"clw-input pt-3"><n-inputref"input":value"modelValue":type"type":title"title"clearable:disabled"disabled":size"size"placeholder&…...

百度Apollo | 实车自动驾驶:感知、决策、执行的无缝融合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…...

DAY31:贪心算法入门455、53、376

理论基础 贪心算法的基本思路是通过局部最优从而达到全局最优&#xff0c;但是有时候局部最优并不一定导致全局最优&#xff0c;这样就需要动态规划的方法。但一部分题目是能通过贪心得到的。贪心的证明一般用到数学归纳法和反证法。在实际的问题中&#xff0c;没有统一的代码…...

LeetCode:376.摆动序列

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 题目链接&#xff1a;376. 摆动序列 - 力扣&#xff08;LeetCode&#xff09; 一、题目 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称…...

Stable Diffusion插件Recolor实现黑白照片上色

今天跟大家分享一个使用Recolor插件通过SD实现老旧照片轻松变彩色&#xff0c;Recolor翻译过来的含义就是重上色&#xff0c;该模型可以保持图片的构图&#xff0c;它只会负责上色&#xff0c;图片不会发生任何变化。 一&#xff1a;插件下载地址 https://github.com/pkuliyi…...

Android 音频焦点管理

前言 前面写过一篇类似的文章&#xff0c;没写完&#xff0c;今天再详细描述一下。 Android音频焦点申请处理 音频焦点管理的意义 两个或两个以上的 Android 应用可同时向同一输出流播放音频。系统会将所有音频流混合在一起。虽然这是一项出色的技术&#xff0c;但却会给用…...

大模型+自动驾驶

论文&#xff1a;https://arxiv.org/pdf/2401.08045.pdf 大型基础模型的兴起&#xff0c;它们基于广泛的数据集进行训练&#xff0c;正在彻底改变人工智能领域的面貌。例如SAM、DALL-E2和GPT-4这样的模型通过提取复杂的模式&#xff0c;并在不同任务中有效地执行&#xff0c;从…...

openssl3.2 - 测试程序的学习 - test\aesgcmtest.c

文章目录 openssl3.2 - 测试程序的学习 - test\aesgcmtest.c概述笔记能学到的流程性内容END openssl3.2 - 测试程序的学习 - test\aesgcmtest.c 概述 openssl3.2 - 测试程序的学习 aesgcmtest.c 工程搭建时, 发现没有提供 test_get_options(), cleanup_tests(), 需要自己补上…...