应用程序必须预测运行时错误并尝试从中恢复。本章提供了有关错误报告和恢复的深入讨论。您将学习如何使用状态变量SQLCODE,SQLSTATE,SQLCA(SQL通信区域)和
WHENEVER
语句来处理警告和错误。您还将学习如何使用状态变量ORACA(Oracle通信区域)诊断问题。讨论了以下主题:
关于MODE = {ANSI | ANSI14}时使用状态变量
每个应用程序的重要部分都必须用于错误处理。错误处理的主要好处是它允许程序在出现错误时继续运行。错误源于设计错误,编码错误,硬件故障,无效的用户输入和许多其他来源
您无法预料到所有可能的错误,但您可以计划处理对您的程序有意义的某些类型的错误。对于Oracle预编译器,错误处理意味着检测并从SQL语句执行错误中恢复。
您还可以准备处理警告,例如“值截断”和状态更改,例如“数据结束”。在每个数据操作语句之后检查错误和警告条件尤为重要,因为在处理表中的所有符合条件的行之前,
INSERT
,
UPDATE
或
DELETE
语句可能会失败。
Oracle预编译器提供了四个状态变量,用作错误处理机制:
SQLCODE(Pro * FORTRAN中的SQLCOD)
SQLSTATE(Pro * FORTRAN中的SQLSTA)
SQLCA(使用WHENEVER声明)
ORACA
MODE选项(描述)控制ANSI / ISO合规性。SQLCODE,SQLSTATE和SQLCA变量的可用性取决于MODE设置。无论MODE设置如何,您都可以声明和使用ORACA变量。有关更多信息,请参阅 关于使用Oracle通信区域 。
当
MODE={ORACLE|ANSI13}
,您必须声明SQLCA状态变量。接受SQLCODE和SQLSTATE声明(不推荐),但不会将其识别为状态变量。有关更多信息,请参阅
关于使用SQL通信区域
。
当
MODE={ANSI|ANSI14}
,您可以使用SQLCODE,SQLSTATE和SQLCA变量中的任何一个,两个或全部三个。要确定哪种变量(或变量组合)最适合您的应用,请参阅
关于在MODE = {ANSI | ANSI14}时使用状态变量
“。
在Oracle预编译器的1.5版中,引入了SQLCODE状态变量作为SQL89标准ANSI / ISO错误报告机制。SQL92标准将SQLCODE列为 不推荐使用的功能并定义了一个新的状态变量SQLSTATE(与Oracle预编译器的1.6版一起引入),作为首选的ANSI / ISO错误报告机制。
SQLCODE存储错误代码和“未找到”条件。它仅保留与SQL89的兼容性,可能会从该标准的未来版本中删除。
与SQLCODE不同,SQLSTATE存储错误和警告代码并使用标准化编码方案。执行SQL语句后,Oracle服务器将状态代码返回到当前范围内的SQLSTATE变量。状态代码指示SQL语句是成功执行还是引发异常(错误或警告条件)。为了提高 互操作性 (系统轻松交换信息的能力),SQL92预定义了所有常见的SQL异常。
SQLCA是一种类似记录的主机语言数据结构。Oracle在每个 可执行的 SQL语句之后更新SQLCA。(在声明性陈述之后,SQLCA值未定义。)通过检查存储在SQLCA中的Oracle返回码,您的程序可以 确定SQL语句的结果。这可以通过两种方式完成:
使用WHENEVER语句进行隐式检查
显式检查SQLCA变量
您可以使用
WHENEVER
语句,对SQLCA变量进行显式检查,或者同时执行这两种操作。通常,使用
WHENEVER
语句是首选,因为它更容易,更便携,并且符合ANSI标准。
当
MODE={ANSI|ANSI14},
您必须至少声明一个 - 您可以声明两个或全部三个 - 以下状态变量:
SQLCA
在Pro * COBOL中,如果声明了SQLCA,则无法声明SQLCODE。同样,如果声明了SQLCODE,则无法声明SQLCA。存储Pro * COBOL错误代码的SQLCA数据结构中的字段也称为SQLCODE,因此如果声明了两个状态变量,则会发生错误。
通过在可执行SQL和PL / SQL语句之后使用您自己的代码显式检查SQLCODE和SQLSTATE,SQLCODE或SQLSTATE,您的程序可以获得最新可执行SQL语句的结果。您的程序也可以隐式检查SQLCA(使用
WHENEVER
SQLERROR和
WHENEVER
SQLWARNING语句),也可以显式检查SQLCA变量。
当
MODE={ORACLE|ANSI13},
您必须声明SQLCA状态变量。有关更多信息,请参阅
关于使用SQL通信区
“。
Oracle预编译器1.5版假定存在一个状态变量SQLCODE,无论它是否在Declare Section中声明;事实上,预编译器从不打扰注意是否有SQLCODE的声明 - 它只是假定声明存在。仅当存在SQLCA的
INCLUDE
,SQLCA才会用作状态变量。
从Oracle预编译器1.6版开始,预编译器不再假定存在SQLCODE状态变量,并且不需要它。预编译器要求声明SQLCA,SQLCODE或SQLSTATE 中的至少 一个。
当且仅当满足以下条件中的至少一个时,SQLCODE才被识别为状态变量:
它在Declare Section中声明,具有 完全 正确的数据类型。
预编译器找不到其他状态变量。
如果预编译器发现一个SQLSTATE声明中声明段(
完全
正确类型的课程),或者找到一个
INCLUDE
SQLCA的,它
不会
擅自SQLCODE声明。
由于Oracle预编译器的1.5版允许在同时声明SQLCA的同时在声明部分之外声明SQLCODE变量,因此预编译器版本1.6及更高版本会出现兼容性问题。添加了一个新选项
ASSUME_SQLCODE={YES|NO}
(默认为NO)以在版本1.6.7中修复此问题,并将其记录为版本1.7中的新功能。
当A
SSUME_SQLCODE=YES,
并且当SQLSTATE或SQLCA(仅限Pro * FORTRAN)被声明为状态变量时,预编译器假定SQLCODE被声明为无论是在声明部分还是在正确类型中声明它都是无效的。这导致版本1.6.7及更高版本在这方面的行为类似于版本1.5。有关预编译器选项ASSUME_SQLCODE的信息,请参阅“ASSUME_SQLCODE”。
SQLCODE(Pro * FORTRAN中的SQLCOD)必须在Declare Section 内部 或 外部 声明为4字节整数变量,如 表8-1 所示。
在每次SQL操作之后,Oracle都会将状态代码返回到当前范围内的SQLCODE变量。状态代码(表示SQL操作的结果)可以是以下任何数字:
Oracle在不检测错误或异常的情况下执行了SQL语句。
Oracle执行了该语句,但检测到异常。当Oracle无法找到满足
WHERE
子句中的条件的行或
SELECT
INTO
或
FETCH
返回任何行时,就会发生这种情况。
当
MODE={ANSI|ANSI14|ANSI13}, +100
在没有行的
INSERT
之后
MODE={ANSI|ANSI14|ANSI13}, +100
返回到SQLCODE。当子查询不返回要处理的行时,可能会发生这种情况。
由于数据库,系统,网络或应用程序错误,Oracle未执行该语句。这些错误是无法恢复的。当它们发生时,在大多数情况下,当前事务应该回滚。负返回码对应于 Oracle数据库错误消息中 列出的错误代码。
您可以通过使用您自己的代码显式检查SQLCODE或使用
WHENEVER
语句隐式检查来了解最新SQL操作的结果。
在特定预编译单元中声明SQLCODE而不是SQLCA时,预编译器会为该单元分配内部SQLCA。您的主程序无法访问内部SQLCA。如果声明SQLCA 和 SQLCODE(仅限Pro * FORTRAN),Oracle会在每次SQL操作后向两者返回相同的状态代码。
当
MODE={ORACLE|ANSI13},
将忽略SQLCODE的声明。
SQLSTATE状态代码由两个字符的 类代码 和三个字符的 子类代码组成 。除了类代码00(成功完成)之外,类代码表示一类异常。除了子类代码000(不适用)之外,子类代码表示该类别中的特定异常。对于 例如,SQLSTATE值“22012”由类代码22(数据异常)和子类代码012(除以零)组成。
SQLSTATE值中的五个字符中的每一个都是一个数字(0..9)或一个大写的拉丁字母(A ..Z)。以0..4范围内的数字或A范围内的字母开头的类代码。H保留用于预定义条件(SQL92中定义的条件)。所有其他类代码都保留用于实现定义的条件。在预定义的类中,子类代码以0..4范围内的数字或范围A中的字母开头。H保留用于预定义的子条件。所有其他子类代码都保留用于实现定义的子条件。编码方案 如图8-1 所示。
图8-1 SQLSTATE编码方案
表8-5 显示了SQL92预定义的类。
表8-5预定义的SQL92类
表8-6 显示了Oracle错误如何映射到SQLSTATE状态代码。在某些情况下,几个Oracle错误会映射到状态代码。在其他情况下,没有Oracle错误映射到状态代码(因此最后一列为空)。60000 ... 99999范围内的状态代码是实现定义的。
表8-6 Oracle错误映射到SQLSTATE状态
Oracle错误SQL通讯区域( SQLCA)是一种类似记录的数据结构。其字段包含Oracle在SQL时更新的错误,警告和状态信息 声明被执行。因此,SQLCA始终反映最近SQL操作的结果。要确定结果,可以在SQLCA中检查变量。
在允许本地和全局声明的主机语言中,您的程序可以有多个SQLCA。例如,它可能有一个全局SQLCA和几个本地SQLCA。访问本地SQLCA受其在程序范围内的限制。Oracle仅将信息返回给“活动”SQLCA。
另请注意,当您的应用程序使用时 SQL * Net同时访问本地和远程数据库的组合,所有数据库都写入一个SQLCA。每个数据库 没有 不同的SQLCA。有关更多信息,请参阅“ 并发登录 ”。
当
MODE={ORACLE|ANSI13}
,需要SQLCA;如果未声明SQLCA,则会发生编译时错误。当
MODE={ANSI|ANSI14}
,SQLCA是可选的,但是如果不声明SQLCA,则不能使用
WHENEVER
SQLWARNING语句。因此,如果要使用
WHENEVER
SQLWARNING语句,则必须声明SQLCA。
如果在特定编译单元中声明SQLCODE而不是SQLCA,则预编译器会为该单元分配内部SQLCA。您的主程序无法访问内部SQLCA。如果声明SQLCA 和 SQLCODE(仅限Pro * FORTRAN),Oracle会在每次SQL操作后向两者返回相同的状态代码。
当
MODE={ANSI|ANSI14}
,必须声明SQLSTATE(请参阅
SQLCODE和SQLSTATE
SQLSTATE状态变量支持SQL92标准指定的SQLSTATE状态变量。您可以在有或没有SQLCODE的情况下使用SQLSTATE状态变量。有关更多信息,请
参见表8-3
和
表8-4
。
要声明SQLCA,只需包含它(使用EXEC SQL
INCLUDE
语句)
)在您的主机语言源文件中,如下所示:
* Include the Oracle Communications Area (ORACA). EXEC SQL INCLUDE ORACA EXEC SQL INCLUDE SQLCA;
当且仅当存在SQLCA的
INCLUDE
时才使用SQLCA。
预编译程序时,
INCLUDE
SQLCA语句将被多个允许Oracle与程序通信的变量声明替换。
在Pro * COBOL中,
INCLUDE
是
在
声明部分的
内部
还是
外部
没有区别。有关在Pro * COBOL中声明SQLCA的详细信息,请参阅
使用SQL通信区域
。
在Pro * FORTRAN中,SQLCA必须在Declare Section
之外
声明,因为它是一个COMMON块。此外,SQLCA必须位于
CONNECT
语句和第一个可执行FORTRAN语句之前。
您必须在包含SQL语句的每个子例程和函数中声明SQLCA。每次执行其中一个子例程或函数中的SQL语句时,Oracle都会更新COMMON块中保存的SQLCA。
通常,只有COMMON列表中变量的顺序和数据类型才有意义,而不是它们的名称。但是,您无法重命名SQLCA变量,因为预编译器会生成引用它们的代码。因此,SQLCA的所有声明必须相同。有关在Pro * FORTRAN中声明SQLCA的详细信息,请参阅 使用SQL通信区域 。
SQLCA包含有关SQL语句结果的以下运行时信息:
Oracle错误代码
行处理计数
图8-2 显示了SQLCA中的所有变量。要查看特定主机语言的SQLCA结构和变量名称,请参阅本指南的补充内容。
图8-2 SQLCA变量
在执行SQL语句之前,Oracle必须对其进行 解析 ,即检查它以确保它遵循语法规则并引用有效的数据库对象。如果Oracle发现错误,则会在SQLCA变量SQLERRD(5)中存储偏移量,您可以显式检查该变量。偏移量指定SQL语句中解析错误开始时的字符位置。第一个角色占据零位。例如,如果偏移量为9,则解析错误从第十个字符开始。
默认情况下,在预编译时检查静态SQL语句的语法错误。因此,SQLERRD(5)对于调试程序在运行时接受或构建的动态SQL语句非常有用。
解析错误是由丢失,错放或错误拼写的关键字,无效选项,不存在的表等引起的。例如,动态SQL语句
UPDATE EMP SET JIB = :job_title WHERE EMPNO = :emp_number
导致解析错误
ORA-00904: invalid column name
因为列名JOB拼写错误。SQLERRD(5)的值为15,因为错误的列名JIB从第16个字符开始。
如果您的SQL语句不会导致解析错误,Oracle会将SQLERRD(5)设置为零。如果解析错误从第一个字符(占据零位置)开始,Oracle也会将SQLERRD(5)设置为零。因此,仅当SQLCODE为负时才检查SQLERRD(5),这意味着发生了错误。
SQLCA变量SQLERRMC中提供了错误代码和Oracle错误消息。最多存储前70个字符的文本。要获取超过70个字符的消息的完整文本,请使用SQLGLM函数。请参阅 “ 获取错误消息的全文 ” 。
Oracle执行了该语句,但检测到异常。当Oracle找不到符合
WHERE
-clause搜索条件的行或
SELECT
INTO
或
FETCH
没有返回任何行时,就会发生这种情况。
当
MODE={ANSI|ANSI14|ANSI13}, +100
之后返回到SQLCODE
INSERT没有行。当子查询不返回要处理的行时,可能会发生这种情况。
由于数据库,系统,网络或应用程序错误,Oracle未执行该语句。这些错误是无法恢复的。当它们发生时,在大多数情况下,当前事务应该回滚。
负返回码对应于 Oracle数据库错误消息中 列出的错误代码。
此整数字段保存存储在SQLERRMC中的消息文本的长度。
此字符串字段包含存储在SQLCODE中的错误代码的消息文本,最多可存储70个字符。对于超过70个字符的消息的全文,请使用SQLGLM函数。
验证SQLCODE是否定的
在 您引用SQLERRMC 之前 。如果在SQLCODE为零时引用SQLERRMC,则会获得与先前SQL语句关联的消息文本。
该字段留作将来使用。
SQLERRD(3)
该字段包含最近执行的SQL语句处理的行数。但是,如果SQL语句失败,则SQLERRD(3)的值未定义,但有一个例外。如果在数组操作期间发生错误,则处理在导致错误的行处停止,因此SQLERRD(3)给出成功处理的行数。
该
行处理计数在
OPEN
语句后归零,在
FETCH
语句后递增。对于
EXECUTE
,
INSERT
,
UPDATE
,
DELETE
和
SELECT
INTO
语句,计数反映了成功处理的行数。伯爵的确如此
不
包括更新或处理的行
删除级联。例如,如果因为符合WHERE子句条件而删除了20行,并且删除了5行,因为它们现在(在主删除之后)违反了列约束,则计数为20而不是25。
该字段留作将来使用。
此字段包含一个偏移量,指定在最近执行的SQL语句中解析错误开始的字符位置。第一个角色占据零位。
SQLERRD(6)
该字段留作将来使用。
这个单个字符数组有八个元素。它们用作警告标志。Oracle通过为其分配“W”(用于警告)字符值来设置标志。旗帜警告特殊情况。
例如,当Oracle将截断的列值分配给输出主机变量时,会设置警告标志。
另请注意,虽然 图8-2将 SQLWARN说明为数组,但它在Pro * COBOL中实现为一个组项,其中包含名为SQLWARN0到SQLWARN7的基本PIC X项。Pro * FORTRAN实现由LOGICAL变量SQLWN0到SQLWN7组成。
中国领域的描述 SQLWARN如下:
SQLWARN(0)
如果设置了另一个警告标志,则设置此标志。
SQLWARN(1)
如果将截断的列值分配给输出主机变量,则会设置此标志。这仅适用于字符数据。Oracle在不设置警告或返回负SQLCODE值的情况下截断某些数字数据。
要查明列值是否被截断以及删除了多少,请检查与输出主机变量关联的指示符变量。指标变量返回的(正)整数是列值的原始长度。您可以相应地增加主机变量的长度。
SQLWARN(2)
如果在评估SQL组函数(如AVG,COUNT或MAX)时忽略了一个或多个空值,则会设置此标志。此行为是预期的,因为除COUNT(*)外,所有组函数都忽略空值。如有必要,可以使用SQL函数NVL临时为空列条目分配值(例如,零)。
SQLWARN(3)
如果查询选择列表中的列数不等于
SELECT
或
FETCH
语句的
INTO
子句中的主机变量数,则设置此标志。返回的项目数量是两者中较小的一个。
SQLWARN(4)
如果表中的每一行都由没有WHERE子句的
UPDATE
或
DELETE
语句处理,则设置此标志。如果没有搜索条件限制处理的行数,则更新或删除称为
无条件
。此类更新和删除是不常见的,因此Oracle会设置此警告标志。这样,您可以在必要时回滚事务
SQLWARN(5)
当EXEC SQL CREATE {PROCEDURE | FUNCTION | PACKAGE | PACKAGE BODY}语句由于PL / SQL编译错误而失败时,将设置此标志。
SQLWARN(6)
此标志已不再使用。
SQLWARN(7)
此标志已不再使用。
当预编译器程序执行嵌入式PL / SQL块时,并非设置SQLCA中的所有字段。例如,如果块提取多行,则行处理的计数SQLERRD(3)将设置为1, 而不是 实际提取的行数。因此,在执行PL / SQL块之后,您应该只依赖SQLCA中的SQLCODE和SQLERRM字段。
SQLCA可以容纳长达70个字符的错误消息。要获取更长(或嵌套)错误消息的全文,您需要 SQLGLM函数。如果连接到Oracle,则可以调用 SQLGLM使用语法
SQLGLM(message_buffer, buffer_size, message_length);
message_buffer是您希望Oracle在其中存储错误消息的文本缓冲区(Oracle空白填充到此缓冲区的末尾)。
缓冲区大小是一个整数变量,指定缓冲区的最大大小(以字节为单位)。
是一个整数变量,Oracle在其中存储错误消息的实际长度。
Oracle错误消息的最大长度为512个字符,包括错误代码,嵌套消息和表和列名称等消息插入。SQLGLM返回的错误消息的最大长度取决于您为buffer_size指定的值。
在以下示例中,您调用SQLGLM以获取最多100个字符的错误消息:
-- declare variables for function call msg_buffer CHARACTER(100); buf_size INTEGER; msg_length INTEGER; set buf_size = 100; EXEC SQL WHENEVER SQLERROR DO sql_error; -- other statements ROUTINE sql_error BEGIN -- get full text of error message SQLGLM(msg_buffer, buf_size, msg_length); display contents of msg_buffer; exit program with an error END sql_error;请注意,只有在发生SQL错误时才会调用SQLGLM。在调用SQLGLM 之前,始终确保SQLCODE为负数。如果在SQLCODE为零时调用SQLGLM,则会获得与先前SQL语句关联的消息文本。
默认情况下,预编译程序会忽略Oracle错误和警告条件,并在可能的情况下继续处理。执行自动条件检查和错误处理,使用
WHENEVER语句。使用
WHENEVER语句,您可以指定Oracle检测到错误,警告条件或“未找到”条件时要采取的操作。这些操作包括继续下一个语句,调用例程,分支到带标签的语句或停止。EXEC SQL WHENEVER <condition> <action>;您可以让Oracle自动检查SQLCA是否满足以下任何条件。
当MODE = {ANSI | ANSI14}时,声明SQLCA是可选的。但是,要使用WHENEVER SQLWARNING, 必须声明SQLCA。
SQLCODE的值为+1403(当
MODE={ANSI|ANSI14| ANSI13}
时为+100),因为Oracle找不到满足
WHERE
子句搜索条件的行,或者
SELECT INTO
或
FETCH
没有返回任何行。当
MODE={ANSI|ANSI14|ANSI13}, +100
在没有行的
INSERT
之后
MODE={ANSI|ANSI14|ANSI13}, +100
返回到SQLCODE。
当Oracle检测到上述 条件之一时 ,您可以让程序执行以下任何操作。
您的程序将控制转移到内部例程。到达例程结束时,控制转移到失败的SQL语句后面的语句。
例程
是可以调用的任何函数程序单元,例如COBOL段或
FORTRAN
子例程。在这种情况下,单独编译的程序(如
COBOL
子例程)
不是
例程。
适用于进入和退出例程的通常规则。然而,将参数传递给该例程 不允许 的。此外,例程 不得 返回值。
EXEC SQL -- COBOL WHENEVER <condition> DO PERFORM <paragraph_name> -- COBOL END-EXEC. -- COBOL
EXEC SQL -- FORTRAN WHENEVER <condition> DO CALL <subroutine_name> -- FORTRAN
只需在第一个可执行SQL语句之前编写以下
WHENEVER
语句:
EXEC SQL WHENEVER NOT FOUND GOTO close_cursor; EXEC SQL WHENEVER SQLWARNING CONTINUE; EXEC SQL WHENEVER SQLERROR GOTO error_handler;
以下Pro * C示例使用
WHENEVER
...
DO
语句处理特定错误:
EXEC SQL WHENEVER SQLERROR DO handle_insert_error; EXEC SQL INSERT INTO EMP (EMPNO, ENAME, DEPTNO) VALUES (:emp_number, :emp_name, :dept_number); EXEC SQL WHENEVER SQLERROR DO handle_delete_error; EXEC SQL DELETE FROM DEPT WHERE DEPTNO = :dept_number; ROUTINE handle_insert_error; BEGIN IF sqlca.sqlcode = -1 THEN -- duplicate key value ELSEIF sqlca.sqlcode = -1401 THEN -- value too large ENDIF; ROUTINE handle_delete_error; BEGIN IF sqlca.sqlerrd(3) = 0 THEN -- no rows deleted ENDIF;
因为
WHENEVER
是一个声明性陈述,它的范围是位置的,而不是逻辑的。它测试源文件中跟随它的所有可执行SQL语句,而不是程序逻辑流程。因此,您应该在要测试的第一个可执行SQL语句之前编写
WHENEVER
语句。
WHENEVER
语句一直有效,直到被另一个检查相同条件的
WHENEVER
语句取代。
在该示例中,第一个
WHENEVER
SQLERROR语句被第二个取代,因此仅适用于
CONNECT
语句。第二
WHENEVER
SQLERROR声明同时适用于UPDATE和DROP语句,尽管控制的
第一步
,从
第三步
到流。
step1:
EXEC SQL WHENEVER SQLERROR STOP;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
GOTO step3;
step2:
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL UPDATE EMP SET SAL = SAL * 1.10;
step3:
EXEC SQL DROP INDEX EMP_INDEX;
发表声明。
通常,在程序中的第一个可执行SQL语句之前编写
WHENEVER
语句。这可以确保所有后续错误都被捕获,因为WHENEVER语句对文件末尾保持有效。
处理数据结束条件。
在使用游标获取行时,您的程序应准备好处理数据结束条件。如果
FETCH
没有返回数据,程序应该分支到发出
CLOSE
命令的标记代码段,如下所示:
SQL WHENEVER NOT FOUND GOTO no_more; no_more: EXEC SQL CLOSE my_cursor;
EXEC SQL WHENEVER SQLERROR GOTO sql_error; sql_error: EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE;
如果没有
WHENEVER
SQLERROR
CONTINUE
语句,
ROLLBACK
错误将再次调用例程,启动无限循环。
不小心使用
WHENEVER
会导致问题。例如,如果
DELETE
语句设置
NOT
FOUND
,则以下代码进入无限循环,因为没有行符合搜索条件:
-- improper use of WHENEVER EXEC SQL WHENEVER NOT FOUND GOTO no_more; EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; ENDLOOP; no_more: EXEC SQL DELETE FROM EMP WHERE EMPNO = :emp_number;
在下一个示例中,您可以通过重置
GOTO
目标来正确处理
NOT FOUND
条件:
-- proper use of WHENEVER EXEC SQL WHENEVER NOT FOUND GOTO no_more; EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; ENDLOOP; no_more: EXEC SQL WHENEVER NOT FOUND GOTO no_match; EXEC SQL DELETE FROM EMP WHERE EMPNO = :emp_number; no_match:
FUNC1 BEGIN EXEC SQL WHENEVER SQLERROR GOTO labelA; EXEC SQL DELETE FROM EMP WHERE DEPTNO = :dept_number; labelA: FUNC2 BEGIN EXEC SQL INSERT INTO EMP (JOB) VALUES (:job_title);
WHENEVER GOTO
语句分支的标签必须与语句位于同一预编译文件中。
错误后返回。
如果程序在处理错误后必须返回,请使用
DO
routine_call
操作。或者,您可以测试SQLCODE的值,如以下示例所示:
EXEC SQL UPDATE EMP SET SAL = SAL * 1.10; IF sqlca.sqlcode < 0 THEN -- handle error EXEC SQL DROP INDEX EMP_INDEX;
在许多预编译器应用程序中,可以方便地知道正在处理的语句的文本,长度以及它包含的SQL命令(例如
INSERT
或
SELECT
)。对于使用动态SQL的应用程序尤其如此。
例程SQLGLS是SQLLIB运行时库的一部分,它返回以下信息:
您可以在发出静态SQL语句后调用SQLGLS。使用动态SQL方法1,可以在执行SQL语句后调用SQLGLS。使用动态SQL方法2,3或4,可以在准备语句后调用SQLGLS。
SQLGLS(SQLSTM, STMLEN, SQLFC)
表8-7 显示了SQLGLS参数列表中可用于参数的主机语言数据类型。
表8-7 SQLGLS参数数据类型
所有参数必须通过引用传递。这通常是默认参数传递约定;你不需要采取特别的行动。
参数SQLSTM是一个空白填充(非空终止)字符缓冲区,用于保存SQL语句的返回文本。您的程序必须静态声明缓冲区或为其动态分配内存。
长度参数 STMLEN是一个四字节整数。在调用SQLGLS之前,请将此参数设置为SQLSTM缓冲区的实际大小(以字节为单位)。当SQLGLS返回时,SQLSTM缓冲区包含填充到缓冲区长度的SQL语句文本空白。STMLEN返回返回语句文本中的实际字节数,不计算空白填充。但是,如果发生错误,STMLEN将返回零。
没有解析SQL语句。
您传递了无效参数(例如,负长度值)。
SQLLIB中发生内部异常。
参数 SQLFC是一个四字节整数,它在语句中返回SQL命令的SQL函数代码。 表8-8 显示了每个SQL命令的功能代码。
CONNECT
ROLLBACK
这些语句没有SQL函数代码。
表8-8 SQL命令功能代码
SQL函数 SQL函数同样,SQLCA处理标准SQL通信; Oracle通讯区( ORACA)处理Oracle通信。如果您需要有关运行时错误和状态更改的更多信息,请使用ORACA。它包含一组扩展的诊断工具。但是,使用ORACA是可选的,因为它增加了运行时开销。
除了帮助您诊断问题外,ORACA还允许您监视程序对Oracle资源(如SQL语句执行程序和游标缓存)的使用情况。
在允许本地和全局声明的主机语言中,您的程序可以有多个ORACA。例如,它可能有一个全局ORACA和几个本地ORACA。访问本地ORACA受到程序范围的限制。Oracle仅将信息返回给“活动”ORACA。只有在提交或回滚后才能使用该信息。
要声明ORACA,只需在主机语言源文件中包含它(使用EXEC SQL
INCLUDE
语句),如下所示:
* Include the Oracle Communications Area (ORACA). EXEC SQL INCLUDE ORACA
预编译程序时,
INCLUDE
ORACA语句将被多个程序变量声明替换。这些声明允许Oracle与您的程序进行通信。
如果设置了主DEBUG标志(ORADBGF),则此标志允许您在每个游标操作之前检查游标缓存的一致性。
Oracle运行时库执行一致性检查,并可能发出错误消息,这些消息列在 Oracle数据库错误消息中 。它们像Oracle错误消息一样返回到SQLCA。
此标志具有以下设置:
0 - 禁用缓存一致性检查(默认值)。
1 - 启用缓存一致性检查。
如果设置了主DEBUG标志(ORADBGF),则此标志告诉Oracle运行时库每次预编译器动态分配或释放内存时都要检查堆的一致性。这对于检测扰乱内存的程序错误很有用。
必须在发出
CONNECT
命令之前设置此标志,并且一旦设置,则无法清除;后续更改请求将被忽略。它具有以下设置:
0 - 禁用堆一致性检查(默认值)。
1 - 启用堆一致性检查。
此子记录标识包含当前SQL语句的文件,因此可帮助您在为一个应用程序预编译多个文件时查找错误。它包含以下两个字段:
此整数字段保存ORASFNMC中存储的文件名的长度。
此字符串字段包含文件名。最多存储前70个字符。
这些变量允许您收集游标缓存统计信息。它们由程序发出的每个
COMMIT
或
ROLLBACK
语句自动设置。在内部,每个
CONNECTed
数据库都有一组这些变量。ORACA中的当前值与执行上次提交或回滚的数据库有关。
以下程序提示输入部门编号,将该部门中每个员工的姓名和工资插入两个表中的一个,然后显示ORACA的诊断信息:
EXEC SQL BEGIN DECLARE SECTION; username CHARACTER(20); password CHARACTER(20); emp_name INTEGER; dept_number INTEGER; salary REAL; EXEC SQL END DECLARE SECTION; EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE ORACA; display 'Username? '; read username; display 'Password? '; read password; EXEC SQL WHENEVER SQLERROR DO sql_error; EXEC SQL CONNECT :username IDENTIFIED BY :password; display 'Connected to Oracle'; EXEC ORACLE OPTION (ORACA=YES); -- set flags in the ORACA set oraca.oradbgf = 1; -- enable debug operations set oraca.oracchf = 1; -- enable cursor cache consistency check set oraca.orastxtf = 3; -- always save the SQL statement display 'Department number? '; read dept_number; EXEC SQL DECLARE emp_cursor CURSOR FOR SELECT ENAME, SAL + NVL(COMM,0) FROM EMP WHERE DEPTNO = :dept_number; EXEC SQL OPEN emp_cursor; EXEC SQL WHENEVER NOT FOUND DO no_more; rLOOP EXEC SQL FETCH emp_cursor INTO :emp_name, :salary; IF salary < 2500 THEN EXEC SQL INSERT INTO PAY1 VALUES (:emp_name, :salary); EXEC SQL INSERT INTO PAY2 VALUES (:emp_name, :salary); ENDIF; ENDLOOP; ROUTINE no_more BEGIN EXEC SQL CLOSE emp_cursor; EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL COMMIT WORK RELEASE; display 'Last SQL statement: ', oraca.orastxt.orastxtc; display '... at or near line number: ', oraca.oraslnr; display display ' Cursor Cache Statistics'; display '-------------------------------------------'; display 'Maximum value of MAXOPENCURSORS ', oraca.orahoc; display 'Maximum open cursors required: ', oraca.oramoc; display 'Current number of open cursors: ', oraca.oracoc; display 'Number of cache reassignments: ', oraca.oranor; display 'Number of SQL statement parses: ', oraca.oranpr; display 'Number of SQL statement executions: ', oraca.oranex; exit program; END no_more; ROUTINE sql_error BEGIN EXEC SQL WHENEVER SQLERROR CONTINUE; EXEC SQL ROLLBACK WORK RELEASE; display 'Last SQL statement: ', oraca.orastxt.orastxtc; display '... at or near line number: ', oraca.oraslnr; display display ' Cursor Cache Statistics'; display '-------------------------------------------'; display 'Maximum value of MAXOPENCURSORS ', oraca.orahoc; display 'Maximum open cursors required: ', oraca.oramoc; display 'Current number of open cursors: ', oraca.oracoc; display 'Number of cache reassignments: ', oraca.oranor; display 'Number of SQL statement parses: ', oraca.oranpr; display 'Number of SQL statement executions: ', oraca.oranex; exit program with an error; END sql_error;