在存储的**过程**中检测到相同的错误,但在存储的**函数**中未检测到
Posted
技术标签:
【中文标题】在存储的**过程**中检测到相同的错误,但在存储的**函数**中未检测到【英文标题】:The same error is detected in stored **procedure**, but not in stored **function** 【发布时间】:2011-07-27 11:14:45 【问题描述】:这个问题和我上一个问题有关:RaiseError (PERL, DBI) equivalent for unixODBC C API?
当我稍后隔离问题时,我将发布新问题,更具体、更孤立且没有不必要的信息。
版本:unixODBC 2.3.0 库:unixODBC - C API
假设我有一个存储的函数:
CREATE FUNCTION "test".func() RETURNING LVARCHAR(1000);
set debug file to '/home/directory_does_not_exists/unknown.log';
trace off;
trace on;
trace off;
return 'result is set here';
END FUNCTION;
和相同的体,但是在存储的PROCEDURE中:
CREATE PROCEDURE "test".proc(pDummy SMALLINT)
set debug file to '/home/directory_does_not_exists/unknown.log';
trace off;
trace on;
LET pDummy = 2;
trace off;
END PROCEDURE;
如您所见,它们完全一样。调试文件的路径错误,因此预计会出错。当我从Aqua Data Studio
执行call func()
时,检测到错误:
Cannot open DEBUG file for SPL routine trace
call proc(1)
也一样。
但是当我通过 unixODBC(使用SQLExecute
)执行这两个调用时,
execute procedure proc(1);
返回SQL_ERROR
(这是预期的并且很好),而
execute function func();
返回 SQL_SUCCESS
.. 但是 'result is set here'
不返回,空字符串 (@987654334 @) 被返回,而不是..
执行call func()
得到与execute function func();
相同的结果
调用SQLMoreResults
返回SQL_NO_DATA
,SQLFetch
返回SQL_ERROR
。
有什么想法吗?
【问题讨论】:
为什么这个问题被标记为 C? 因为它是关于unixODBC
,C API
?对不起,我忘了在这里提。
【参考方案1】:
我不使用 Informix,但我使用 Perl DBD::ODBC 以及 isql(用 C 编写)尝试的简单示例都返回错误:
use strict;
use warnings;
use DBI;
my $h = DBI->connect();
eval
$h->do(q/drop function fmje/);
;
$h->do(<<'EOS');
create function fmje (@p1 as int)
returns int
as
begin
declare @a int;
set @a = 'fred';
return @p1;
end;
EOS
my $s = $h->prepare(q/? = call fmje(?)/);
$s->bind_param_inout(1, \my $x, 10);
$s->bind_param(2, 1);
$s->execute;
print "return is ", ($x ? $x : "undef"), "\n";
isql -v baugi sa easysoft
+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL> call fmje(1)
[22005][unixODBC][Easysoft][SQL Server Driver 11.0][SQL Server]Conversion failed when converting the varchar value 'fred' to data type int.
[ISQL]ERROR: Could not SQLExecute
SQL>
Informix 对于函数的工作方式必须不同,或者您可能没有通过 Aqua Data Studio 使用通用 ODBC。
如果您看到 Perl 的错误,正如您在另一篇文章中所说的,那么按照我在那里的建议进行操作并添加:
[ODBC]
Trace=yes
TraceFile=/tmp/unixodbc.log
到您的 odbcinst.ini 文件的顶部并运行 Perl。然后向我们展示错误日志中的行。然后用 isql 重复,以便我们可以比较 ODBC 调用。
【讨论】:
哇!好的!有一点小进步。我创建了相同的函数并通过isql
执行它 - 未检测到错误.. 或者至少 - 执行得很好。但是,现在我看到了这个空字符串的来源——这是错误描述!哇。因此,当我运行 isq
和 -v
(详细)时,返回的字符串不是空的,但它包含错误描述 - 在本例中为:[37000][Informix][Informix ODBC Driver][Informix]Character to numeric conversion error
。但是,它执行得很好,并且没有显示错误(与您的执行一样)-在我的 isql
和 INFORMIX
DB 中没有 ERROR: Could not SQLExecute
。
我找到了解决方案(您可以查看我的答案)。非常感谢您的帮助!【参考方案2】:
这可能与您正在使用的服务器版本有关(不太可能,但可能),或者与您正在使用的 API 有关。当我使用使用 ESQL/C (CSDK) 3.70.FC2 构建的(我的)sqlcmd 程序在 MacOS X 10.7 上测试 IDS 11.70.FC2 时,我得到:
$ sqlcmd -c -d stores -e begin -xf x1.sql -e 'execute procedure proc(2)' \
-e 'execute function func()'
+ CREATE FUNCTION "test".func() RETURNING LVARCHAR(1000);
set debug file to '/home/directory_does_not_exists/unknown.log';
trace off;
trace on;
trace off;
return 'result is set here';
END FUNCTION;
+ CREATE PROCEDURE "test".proc(pDummy SMALLINT)
set debug file to '/home/directory_does_not_exists/unknown.log';
trace off;
trace on;
LET pDummy = 2;
trace off;
END PROCEDURE;
+ execute procedure proc(2)
SQL -648: Cannot open DEBUG file for SPL routine trace.
SQLSTATE: IX000 at /dev/stdin:0
+ execute function func()
SQL -648: Cannot open DEBUG file for SPL routine trace.
at /dev/stdin:0
$
如您所见,func()
和proc()
在 ESQL/C 中都正确报告了错误。所以,问题几乎肯定出在客户端代码中——在 ODBC 驱动程序及其处理错误的方式中,或者在调用 ODBC 驱动程序的代码中。
如何进一步隔离问题?
在环境中使用SQLIDEBUG=2:xyz
运行您的测试。然后,找到名称以xyz_
开头的文件(例如,我得到了xyz_35424_0_819800
)并在其上运行sqliprint
。这将显示服务器是否两次生成错误消息。
我在一个跟踪中得到了两个类似的数据包:
S->C (12) Time: 2011-07-28 00:28:02.41736
SQ_ERR
SQL error..........: -648
ISAM/RSAM error....: 0
Offset in statement: 0
Error message......: "" [0]
SQ_EOT
如果您看到两个带有 -648 错误的数据包,那么您就知道问题出在客户端处理错误的方式上。如果您没有看到这两个错误,那么我很想知道发生了什么。
【讨论】:
嗯,不错。你是对的。这有效(导出变量,通过isql
执行然后sqliprint xyz
),我收到相同的错误(-648)。此外,如果我直接从 INFORMIX 服务器使用dbaccess
执行调用,我会再次收到错误消息。问题是,isql
(与我的简单C
应用程序相同)没有显示任何错误,而是返回空字符串(func
)。那很奇怪。这让我觉得,这可能与配置有关,或者我不知道。也许odbc.ini
、odbcinst.ini
、sqlhosts
中有一些额外的选项,或者我不知道:\
哈!好的!我知道这个空字符串(返回的)来自哪里......这是错误描述。或者类似的东西。我的意思是,当我使用isql
执行调用时,返回空字符串,没有检测到错误。但是当我用-v
(详细)开始isql
时,再次检测到NO错误(成功执行),BUT空字符串不再是空字符串,它是设置为Cannot open DEBUG file for SPL routine trace
,这是预期的。问题是,执行仍然很好并且没有显示错误(只是错误消息)
我不知道unixODBC
是否有这样的选项(设置详细),但即使有,如果没有返回错误代码,我不能依赖错误消息:\ I '将继续我的研究,我们有一些进展(小,不幸的是,但进展)。欢迎任何想法:) 谢谢!
我拥有的 CSDK 是 clientsdk.3.70.UC2DE.LINUX.tar,unixODBC 版本是 2.3.0 - 都是最新版本。您是否安装了isql
(如果我没记错的话,它是 CSDK 自带的)?如果是这样,请您在 isql 中运行调用吗?顺便说一句,我将finderr
用于-648
,它被发现、描述等(在客户端和服务器机器上)所以,这不是什么神秘的错误..
我找到了解决方案(您可以查看我的答案)。非常感谢您的帮助!【参考方案3】:
首先 - 感谢非常感谢@Jonathan Leffler(提示SQLIDEBUG=2:xyz
+ sqliprint
并在他的机器上进行测试)和@bohica(提示strace
) 支持!这真的帮助我找到了真正的问题并解决了它!两者都由我 +1。
不幸的是,答案不在他们的帖子中,这就是为什么我会自己回答。
总结:
SQLPrepare
和 SQLExecute
在 some 错误中有时失败,但不是全部。当使用存储 procedure 时,这些函数会捕获更多错误。不幸的是,存储函数的情况有所不同。
我现在如何捕捉错误?如果SQLExecute
成功,我会打电话给SQLNumResultCols
- 这很正常。之后,我打电话给SQLFetch
,这也是意料之中的。但是,由于SQLFetch
可能由于多种原因而失败(例如,它总是在存储过程上失败),所以它的错误被忽略了。还有一个while
像
if ( SQLNumResultCols( stmt, &nAllCols ) != SQL_SUCCESS )
// ...
int nSucceededFetches = 0; // added now, see below why
while ( SQL_SUCCEEDED( SQLFetch( stmt ) ) )
++nSucceededFetches; // added now, see below why
/* bla bla */
这是关键 - 添加额外检查:
if( 0 == nSucceededFetches && nColumns > 0 )
它说 - 如果有 有 返回列 并且在第一次调用时 fetch 失败,那么就有问题了。然后我有
while ( SQL_SUCCESS == SQLError( 0, 0, stmt, szSqlState, &nNativeError, szError, 500, &nErrorMsg ) )
/* bla bla */
一切都很好。我仍然不明白为什么SQLExecute
返回SQL_SUCCESS
(甚至不是SQL_SUCCESS_WITH_INFO
..),但这没关系。
【讨论】:
如果你说的是真的,那么我认为这是驱动程序中的一个错误。 SQLExecute 应该失败 SQL_SUCCEEDED。 DBD::ODBC 可能会显示错误,因为无论 SQL_SUCCEEDED(SQLExecute()) 是否为真,它都会在 SQLExecute 之后调用 SQLError。代码中的注释说“无论 rc 的值如何,都调用 dbd_error,这样我们就可以获得所需的任何状态消息。”。我不记得我是否写了那段 DBD::ODBC。你可以在cpansearch.perl.org/src/MJEVANS/DBD-ODBC-1.31/dbdimp.c找到它 是的,我猜这是驱动程序错误。或者我做错了什么:) 我明白了,谢谢你的参考。我现在做这样的事情,如dbdimp.c
- “检查以防万一”。问题是,我不确定这是否总是有效,或者有时我会收到一些“误报”错误。但无论如何,重要的是,它现在有效。谢谢,不胜感激。以上是关于在存储的**过程**中检测到相同的错误,但在存储的**函数**中未检测到的主要内容,如果未能解决你的问题,请参考以下文章
存储过程如何在从 BIDS 调用时不返回行,但在使用相同参数时从 SSMS 调用时返回行?