在存储的**过程**中检测到相同的错误,但在存储的**函数中没有检测到**

时间:2011-07-27 11:14:45

标签: c stored-procedures error-handling informix unixodbc

这个问题与我之前的问题有关:RaiseError (PERL, DBI) equivalent for unixODBC C API?

当我稍后隔离问题时,我会发布一个更具体,更孤立且没有不必要信息的新问题。


版本: unixODBC 2.3.0
lib: 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;

如您所见,它们完全相同。调试文件的路径是错误的,因此预计会出错。当我从call func()执行Aqua Data Studio时,会检测到错误:

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' 已退回,空返回字符串(''),而不是..

执行call func()会产生与execute function func();

相同的结果

致电SQLMoreResults返回SQL_NO_DATASQLFetch返回SQL_ERROR

有什么想法吗?

3 个答案:

答案 0 :(得分: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调用了。

答案 1 :(得分:1)

这可能与您正在使用的服务器版本(不太可能,但可能)有关,或与您正在使用的API有关。当我使用ESQL / C(CSDK)3.70.FC2使用(my)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错误的数据包,那么您就知道问题在于客户端处理错误的方式。如果你没有看到这两个错误,那么我很想知道发生了什么。

答案 2 :(得分:0)

首先 - 感谢很多给@Jonathan Leffler(提示SQLIDEBUG=2:xyz + sqliprint并在他的机器上测试)和@bohica(提示)与strace)的支持!这真的帮助我找到真正的问题并解决它!我两个都是+1 不幸的是,答案不在他们的帖子中,这就是为什么我会自己回答。


要点:

SQLPrepareSQLExecute 一些错误有时,但不是全部。存储过程时,这些函数会捕获更多错误。不幸的是,存储的功能的情况有所不同。

我现在如何捕捉错误?如果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 )

其中说 - 如果 返回列并且在FIRST调用上获取失败,则出现问题。然后我有

while ( SQL_SUCCESS == SQLError( 0, 0, stmt, szSqlState, &nNativeError, szError, 500, &nErrorMsg ) )
{ /* bla bla */ }

一切都很好。我仍然不明白为什么SQLExecute会返回SQL_SUCCESS(甚至不是SQL_SUCCESS_WITH_INFO ..),但这并不重要。