Грабли DBIные, заботливо присыпанные листвой
Ну конечно, я на них наступил.
Типичная последовательность действий при работе с базой данных: prepare(), execute(), если надо прочитать результат – fetch(), ну и в конце finish(). И до сих пор всё работало.
И тут ВНЕЗАПНО оказалось, что если выполняется не обычный SQLный оператор, а хранимая процедура (посредством EXECUTE PROCEDURE), то возникшая при выполнении ошибка после execute() никак не проявляется. Типа, всё нормально выполнилось. А вот когда потом делаешь fetch(), тут-то ошибка и вылезает. Более того, если процедура ничего не возвращает, то ошибка не проявляется вовсе. И процедура, кажется, вообще не выполняется, пока не сделаешь fetch(). Да-да, fetch(), который заведомо ничего вернуть не может.
В документации, естественно, эта замечательная особенность не описана. И я, как обычно, на эти грабли наступил и потратил полдня, чтоб понять, какого хрена оно молча не работает.
Оригинал этой записи. Комментировать можно тут или там.
это баг DBI ?
Re: это баг DBI ?
Ошибка, скорее, в конкретном DBD. В DBI написано, что "Calling stored procedures is currently not defined by the DBI. Some drivers, such as DBD::Oracle, support it in non-portable ways. See driver documentation for more details." А в driver documentation про это ничего нет.
Re: это баг DBI ?
sql.execute while not sql.eof begin A = sql.field0 sql.fetch endпоэтому никто твоих граблей не видит.
Re: это баг DBI ?
Re: это баг DBI ?
Re: это баг DBI ?
В общем-то им даже проще, предполагается что есть два типа sql, возвращающие курсор и не возвращающие, поэтому первые вызываются sql.open а вторые sql.exec. Первые всегда фетчатся вторые никогда, правда они проверяют все равно вернулся курсор или нет.
Re: это баг DBI ?
Re: это баг DBI ?
Re: это баг DBI ?
В моём случае возвращать ей нечего, она добавляет запись в таблицу, предварительно проводя некоторые логические проверки, не реализованные на уровне constraint'ов. Если какие-то проверки не прошли, генерирует ошибку.
попробовал на esql.c написать
EXEC SQL execute procedure tmp_proc(0); chk("exec proc"); printf("\n"); EXEC SQL declare c1 cursor for execute procedure tmp_proc(0); chk("DECLARE"); EXEC SQL open c1; chk("OPEN"); EXEC SQL fetch c1 into $pa; chk("FETCH"); if (sqlca.sqlcode == 0) printf("Value selected from 'c' = %d.\n", pa); printf("\n");и на самом деле ошибка идет только при фетче
EXEC SQL execute procedure tmp_func(0); chk("exec"); printf("\n"); EXEC SQL declare c cursor for execute procedure tmp_func(0); chk("DECLARE"); EXEC SQL open c; chk("OPEN"); EXEC SQL fetch c into $pa; chk("FETCH"); if (sqlca.sqlcode == 0) printf("Value selected from 'c' = %d.\n", pa); printf("\n"); exec: SQLCODE = -684: Function (informix.tmp_func) returns too many values. DECLARE was successful OPEN was successful FETCH: SQLCODE = -746: tmp_func-raised exceptionRe: и на самом деле ошибка идет только при фетче