sqlplus 不在指定的输出文件中记录编译错误

Posted

技术标签:

【中文标题】sqlplus 不在指定的输出文件中记录编译错误【英文标题】:sqlplus doesn't log compilation errors in designated out file 【发布时间】:2012-10-22 16:38:52 【问题描述】:

这是我调用 sqlplus 的 shell 脚本:

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log

SELECT 'IN sqlplus' FROM dual;

DECLARE tbl_xst integer;

SELECT COUNT(*) INTO tbl_xst FROM SYS.ALL_TABLES
WHERE table_name = 'SOME_TABLE'
AND OWNER = 'SOME_OWNER';

IF tbl_xst = 1 THEN
BEGIN
    DROP TABLE SOME_OWNER.SOME_TABLE;
END
END IF

SELECT 'The end' FROM dual;
!!

当我运行 shell 脚本并查看日志文件 logFile.log 时,会出现以下内容:

SQL*Plus: Release 10.2.0.3.0 - Production on Mon Oct 22 12:33:05 2012

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.


Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

SQL> SQL>
'INSQLPLUS
----------
IN sqlplus

SQL> SQL>   2    3    4    5    6    7    8    9   10   11   12   13   14   15  Disconnected from Oracle Database 11g Enterprise Edition Releas
e 11.2.0.2.0 - 64bit Production
With the Partitioning, Automatic Storage Management, OLAP, Data Mining
and Real Application Testing options

如您所见,第一个记录 SELECT 语句('IN sqlplus')进入,而底部的第二个没有,即执行没有到达它,因为两者之间有错误。为什么sqlplus没有在日志文件中写入这个错误信息?

在一些评论后编辑:我们已经确定这很可能是因为 sqlplus 没有将 STDERR 转储到指定的日志文件中,其中只有 STDOUT 存在。如何格式化 sqlplus 命令以将两个流(STDOUT 和 ERR)组合到指定的日志文件中?我怀疑&lt;&lt;!!&gt; 在这里很关键。

更多实验后编辑:奇怪的是,一些错误消息被转储到 STDOUT 中,我猜想那些试图引用坏 DB 对象的语法正确。如果有 SQL 编译错误,它显然会进入 STDERR。我所做的是在上面的第一个 SELECT 和 DECLARE 之后插入以下行:

DROP TABLE FAKE_NONEXISTING;

该语句是合法的并且可以编译,但 FAKE_NONEXISTING 不存在,我在日志文件中得到以下内容:

SQL> SQL> DROP TABLE FAKE_NONEXISTING
           *
ERROR at line 1:
ORA-00942: table or view does not exist

但是,我在日志文件中没有得到任何似乎是 SQL 编译错误的信息

【问题讨论】:

如何更改调用 sqlplus 以将 STDERR 定向到定义文件的行?更好的是,我如何将 STDOUT 和 ERR 结合到同一个日志文件中? 其实sqlplus的摄入需要不同的格式 我实际上质疑“它没有被打印在 stdout 它被打印在 stderr”的假设,因为当你手动在 sqlplus 中(所以不从脚本调用)时,你会得到错误和常规输出在同一个流中 我认为这与 sqlplus 行中的 语法有关 【参考方案1】:

SQL*Plus 不会将输出分开到stdoutstderr。这实际上与重定向或外壳无关;如果您将该代码粘贴到交互式 SQL*Plus 会话中,您也会遇到同样的问题。您没有看到编译错误,因为您没有告诉它您已经提供了需要编译和执行的完整块。

一旦你开始a PL/SQL block - 在这种情况下是DECLARE - 之后的所有内容都被视为同一块的一部分,直到你提供terminating ./,tells SQL*Plus to execute the current buffer,它这是整个匿名块。您希望打印 The end 的第二个普通 select 被视为不完整块的一部分,因此它也永远不会运行。您的脚本在遇到/ 之前终止(在!!),因为您没有脚本,所以SQL*Plus 不知道要执行什么。如果您确实将其粘贴到 SQL*Plus 中,您将在第 15 行看到相同的输出和等待输入的光标;脚本版本在此时被终止,大致相当于在 shell 脚本等待输入时按 ctrl-C。

但是您还缺少该块的其他几个关键部分。如果您在程序部分和终止的/ 周围添加BEGINEND,您将开始看到错误,其中一些只是缺少分号;这应该让你开始:

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log

SELECT 'IN sqlplus' FROM dual;

DECLARE -- start of PL/SQL block declaration
    tbl_xst integer;
BEGIN -- start of the actual block
    SELECT COUNT(*) INTO tbl_xst FROM SYS.ALL_TABLES
    WHERE table_name = 'SOME_TABLE'
    AND OWNER = 'SOME_OWNER';

    IF tbl_xst = 1 THEN
    BEGIN
        DROP TABLE SOME_OWNER.SOME_TABLE; -- this will error
    END; -- missing semi-colon, but separate BEGIN/END wrapper isn't really needed
    END IF; -- missing semi-colon
END; -- missing end to the block
/ - missing PL/SQL terminator/executor

-- now back in plain SQL mode
SELECT 'The end' FROM dual;
!!

现在应该报告关于DROP 的错误。那是一个 DDL 命令,不能像在 PL/SQL 中那样运行;您必须使用动态 SQL,例如:

    IF tbl_xst = 1 THEN
        EXECUTE IMMEDIATE 'DROP TABLE SOME_OWNER.SOME_TABLE';
    END IF;

(这是 William Stearns 提到的,尽管我强烈建议您不要有一个带有 WHEN OTHERS 和没有 RAISE 的异常块,因为它会吞下发生的任何错误它试图删除表。)

顺便说一句,如果您不想在输出中看到 SQL*Plus 版本、连接和提示/行号信息,可以使用-s[ilent] 选项来抑制它。

【讨论】:

【参考方案2】:

要将错误输出也重定向到您的日志文件,您需要在此处将 2>&1 附加到您的行:

sqlplus $USER/$PASSWD@$DB<<!!>./logFile.log 2>&1

根据我自己的评论更新...我可能会添加>>而不是>来附加现有文件,以便您的日志可以随着时间的推移使用。

#!/usr/bin/ksh

sqlplus $USER/$PASSWD@$DB<<+EOF>>./logFile.log 2>&1

SELECT 'IN sqlplus' FROM dual;

BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE SOME_OWNER.SOME_TABLE';
    EXCEPTION WHEN OTHERS THEN NULL;
END;

SELECT 'The end' FROM dual;
+EOF

【讨论】:

我猜是 不幸的是,这并没有。输出是一样的:第一次打印有效,第二次从未到达,中间没有有用的错误信息。 检查上面最新的帖子修正,从 EDIT AFTER MORE EXPERIMENTATION 开始: 是的,你没有处理异常。让我缩短它以删除特定表(如果存在)。 我会看看***.com/questions/12058020/…

以上是关于sqlplus 不在指定的输出文件中记录编译错误的主要内容,如果未能解决你的问题,请参考以下文章

sqlplus中怎么将你全部的操作和结果记录保存到你指定的文件里

如何在 sqlplus 中执行 .sql 文件时仅记录错误

在登陆sql plus时老是出现错误提示,无法解析指定的连接标识符,是啥原因?

怎么用C语言编一个学生成绩记录簿?

sqlplus 输出标题格式错误和不必要的空行

如何使 SQLPlus 编译警告静音?