Та же ошибка обнаружена в сохраненной **процедуре**, но не в сохраненной **функции**

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

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

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

Любые идеи?


person Kiril Kirov    schedule 27.07.2011    source источник
comment
почему этот вопрос помечен как C?   -  person Jens Gustedt    schedule 27.07.2011
comment
Потому что речь идет о unixODBC, C API ? Извините, я забыл упомянуть об этом здесь.   -  person Kiril Kirov    schedule 27.07.2011


Ответы (3)


Я не использую 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.

person bohica    schedule 27.07.2011
comment
Вау! Хороший! Есть небольшой прогресс. Я создал ту же функцию и выполнил ее через isql - НЕТ ОШИБКИ.. Или, по крайней мере, - выполнил нормально. НО, теперь я вижу, откуда эта пустая строка - это описание ошибки! Ух ты. Итак, когда я запускаю isq с -v (подробным), возвращаемая строка НЕ ​​пуста, но содержит описание ошибки — в данном случае: [37000][Informix][Informix ODBC Driver][Informix]Character to numeric conversion error. НО, он выполняется нормально, и ошибка НЕ ​​отображается (как при вашем выполнении) - НЕТ ERROR: Could not SQLExecute в моих isql и INFORMIX БД. - person Kiril Kirov; 28.07.2011
comment
Я нашел решение (вы можете проверить мой ответ). Большое спасибо за помощь! - person Kiril Kirov; 01.08.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, то вы знаете, что проблема заключается в том, как клиент обрабатывает ошибку. Если вы не видите двух ошибок, то мне очень любопытно посмотреть, что происходит.

person Jonathan Leffler    schedule 28.07.2011
comment
Хм, мило. Да, ты прав. Это работает (экспортируйте переменную, выполните через isql, а затем sqliprint xyz), и я получаю ту же ошибку (-648). Кроме того, если я выполняю вызов с помощью dbaccess непосредственно с сервера INFORMIX, я снова получаю сообщение об ошибке. Проблема в том, что isql (то же самое с моим простым приложением C) не показывает мне никаких ошибок и вместо этого возвращает пустую строку (func). Это странно. Это заставляет меня думать, что это может быть что-то с конфигурацией или я не знаю. Может какая-то дополнительная опция в odbc.ini, odbcinst.ini, sqlhosts или я не знаю :\ - person Kiril Kirov; 28.07.2011
comment
Ха! Хороший! Я понял, откуда берется эта пустая строка (которая возвращается)... это описание ошибки. Или что-то вроде этого. Я имею в виду, что когда я выполняю вызов с использованием isql, возвращается пустая строка, ошибок не обнаружено. НО, когда я запускаю isql с -v (подробно), ошибка NO обнаруживается снова (выполняется успешно), НО пустая строка больше не является пустой строкой, она устанавливается на Cannot open DEBUG file for SPL routine trace, которая ожидается. Проблема в том, что выполнение все еще в порядке, и ОШИБКА не отображается (только сообщение об ошибке) - person Kiril Kirov; 28.07.2011
comment
Я не знаю, есть ли у unixODBC такая опция (установить подробный), но даже если она есть, если код ошибки не возвращается, я не могу полагаться на сообщения об ошибках :\ Я продолжу свои исследования, у нас есть кое-что прогресс (маленький, к сожалению, но прогресс). Любые идеи приветствуются :) Спасибо! - person Kiril Kirov; 28.07.2011
comment
CSDK, который у меня есть, — clientdk.3.70.UC2DE.LINUX.tar, а версия unixODBC — 2.3.0 — обе последние версии. У вас установлен isql (он идет с CSDK, если я не ошибаюсь)? Если да, не могли бы вы, пожалуйста, запустить вызовы в isql? Кстати, я использовал finderr вместо -648, и это было найдено, описано и т. д. (как на клиентских, так и на серверных машинах). Так что это не какая-то таинственная ошибка. - person Kiril Kirov; 28.07.2011
comment
Я нашел решение (вы можете проверить мой ответ). Большое спасибо за помощь! - person Kiril Kirov; 01.08.2011

Прежде всего - спасибо большое @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 )

в котором говорится, что если есть возвращаемые столбцы и выборка не удалась при ПЕРВОМ вызове, то что-то не так. Тогда у меня есть

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

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

person Kiril Kirov    schedule 01.08.2011
comment
Если то, что вы говорите, правда, то я думаю, что это ошибка в драйвере. SQLExecute должен завершиться ошибкой SQL_SUCCEEDED. DBD::ODBC, вероятно, показывает ошибку, потому что вызывает SQLError после SQLExecute независимо от того, истинно ли значение SQL_SUCCEEDED(SQLExecute()). Комментарий в коде гласит: «Вызывать dbd_error независимо от значения rc», чтобы мы могли получать любые сообщения о состоянии, которые желательны. Я не могу вспомнить, писал ли я этот бит DBD::ODBC или нет. Вы можете найти его по адресу cpansearch.perl.org/src/MJEVANS. /DBD-ODBC-1.31/dbdimp.c - person bohica; 02.08.2011
comment
Да, я думаю, это ошибка драйвера. Или я что-то ужасно неправильно делаю :) Понятно, спасибо за ссылку. Делаю сейчас примерно так, как в dbdimp.c - проверь на всякий случай. Проблема в том, что я не уверен, будет ли это работать всегда, или иногда я могу получить ложную ошибку. Но в любом случае, здесь важно то, что пока это работает. Спасибо, ценю. - person Kiril Kirov; 02.08.2011