Я пытаюсь получить данные из переменной курсора, открытой в хранимой функции, но я всегда получаю сообщение об ошибке «Извлечь из последовательности».
Вот хранимая функция:
CREATE OR REPLACE FUNCTION test_function RETURN SYS_REFCURSOR AS
p_recordset SYS_REFCURSOR;
BEGIN
OPEN p_recordset FOR SELECT '1' FROM DUAL UNION SELECT '2' FROM DUAL;
RETURN p_recordset;
END TEST_FUNCTION;
И код Pro * C:
int myfunction()
{
...
EXEC SQL BEGIN DECLARE SECTION;
SQL_CURSOR sql_cursor_pl;
VARCHAR string_field[20];
EXEC SQL END DECLARE SECTION;
EXEC SQL ALLOCATE :sql_cursor_pl;
// It is not possible to use embedded PL/SQL block as seen in other
// examples because it requieres a compilation time access to database
// that I don't have, so as far as I know I have to use EXEC SQL CALL
EXEC SQL CALL sch.test_function() INTO :sql_cursor_pl;
EXEC SQL WHENEVER NOT FOUND DO break;
//for ( ; ; )
while (sqlca.sqlcode == '\0')
{
EXEC SQL FETCH :sql_cursor_pl INTO :string_field;
...
}
EXEC SQL CLOSE :sql_cursor_pl;
...
}
Сохраненная функция работает нормально, если я использую ее в другом PL-блоке, подобном приведенному ниже, поэтому я думаю, что проблема должна быть в коде Pro * C.
DECLARE
mycursor sys_refcursor;
string_field VARCHAR(20)
BEGIN
mycursor := sch.test_function();
LOOP
FETCH mycursor INTO string_field;
EXIT WHEN mycursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(string_field);
END LOOP;
CLOSE mycursor;
END;
Я думаю, что нашел проблему и одно решение. При открытии курсора в блоке PL / SQL индекс курсора начинается с 0, а у Pro * C — с 1. Проблема, я думаю, заключается в том, что Pro * C вообще не обновляет индекс курсора, поэтому одним из решений может быть увеличить вручную, как это видно Вот.
...
while (sqlca.sqlcode == '\0')
{
sql_cursor_pl.curocn++;
EXEC SQL FETCH :sql_cursor_pl INTO :string_field;
...
}
...
Проблема заключается в состоянии while, которое проверяется перед выполнением FETCH
команда.
Я обычно разрешаю эти циклы, используя EXEC SQL WHENEVER NOT FOUND
директивы. Вот пример того, как это сделать:
while(1)
{
EXEC SQL WHENEVER NOT FOUND DO break; // Where a no data found occurs execute a C "break" instruction.
EXEC SQL FETCH :sql_cursor_pl INTO :string_field;
EXEC SQL WHENEVER NOT FOUND DO ???; // Restore desired behaviour.
...
}
Первая директива указывает Pro * C / C ++ выполнить break
если ошибка не найдена, это означает выход из цикла while.
Вторая директива необходима для восстановления желаемого поведения (здесь требуется некоторое прерывание, но в остальной части кода это, вероятно, не лучший выбор).