Та же ошибка обнаружена в хранимой ** процедуре **, но не в хранимой ** функции ** - PullRequest
1 голос
/ 27 июля 2011

Этот вопрос связан с моим предыдущим: Эквивалент RaiseError (PERL, DBI) для 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;

И того же тела, но в сохранена ПРОЦЕДУРА :

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).

НО когда я выполняю эти 2 вызова через unixODBC (используя SQLExecute),

execute procedure proc(1);

возвращает SQL_ERROR (что ожидается и нормально), тогда как

execute function func();

возвращает SQL_SUCCESS .. НО 'result is set here' is not возвращено, вместо нее возвращается пустая строка ('') ..

Выполнение call func() дает те же результаты, что и execute function func();

Вызов SQLMoreResults возвращает SQL_NO_DATA, SQLFetch возвращает SQL_ERROR.

Есть идеи?

Ответы [ 3 ]

1 голос
/ 28 июля 2011

Это может быть связано с используемой версией сервера (маловероятно, но возможно) или с API, который вы используете. Когда я тестирую с IDS 11.70.FC2 на MacOS X 10.7 с использованием (моей) сборки программы sqlcmd с ESQL / C (CSDK) 3.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, значит, проблема в том, как клиент обрабатывает ошибку. Если вы не видите две ошибки, мне очень интересно посмотреть, что происходит.

1 голос
/ 27 июля 2011

Я не использую 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 должен работать по-другому для функций, или, возможно, вы не используете общий ODBC через Aqua Data Studio.

Если вы видите ошибку Perl, как вы говорите в другом посте, сделайте, как я рекомендовал, и добавьте:

[ODBC]
Trace=yes
TraceFile=/tmp/unixodbc.log

в начало файла odbcinst.ini и запустите Perl. Затем покажите нам строки из журнала от ошибки. Затем повторите с isql, чтобы мы могли сравнить вызовы ODBC.

0 голосов
/ 01 августа 2011

Прежде всего - спасибо большое @ Джонатану Леффлеру (за подсказку с 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 )

, которая говорит - если есть возвращает столбцы и при первом вызове происходит сбой выборки, тогда что-то не так.Тогда у меня

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

И все хорошо.Я до сих пор не понимаю, почему SQLExecute возвращает SQL_SUCCESS (НЕ даже SQL_SUCCESS_WITH_INFO ..), но это не имеет значения.

...