这个问题与我之前的问题有关: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)
也是如此。
但是 (使用SQLExecute
),
execute procedure proc(1);
返回SQL_ERROR
(预期和罚款),而
execute function func();
返回SQL_SUCCESS
.. 但 'result is set here'
不 已退回,空返回字符串(''
),而不是..
执行call func()
会产生与execute function func();
致电SQLMoreResults
返回SQL_NO_DATA
,SQLFetch
返回SQL_ERROR
。
有什么想法吗?
答案 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
不幸的是,答案不在他们的帖子中,这就是为什么我会自己回答。
SQLPrepare
和SQLExecute
一些错误有时,但不是全部。存储过程时,这些函数会捕获更多错误。不幸的是,存储的功能的情况有所不同。
我现在如何捕捉错误?如果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
..),但这并不重要。