【问题标题】:Using Pro*C, how to fetch from a cursor opened in PL stored function without setting 'sqlcheck=semantics' option?使用 Pro*C,如何在不设置 'sqlcheck=semantics' 选项的情况下从 PL 存储函数中打开的游标中获取?
【发布时间】:2016-05-12 14:57:49
【问题描述】:

我正在尝试从存储函数中打开的游标变量中获取数据,但我总是收到“提取乱序”错误消息。

这里是存储的函数:

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;

【问题讨论】:

    标签: c++ plsql oracle-pro-c


    【解决方案1】:

    我想我已经找到了问题和解决方案。在 PL/SQL 块中打开游标时,游标索引从 0 开始,但 Pro*C 的从 1 开始。我认为问题是 Pro*C 根本不更新游标索引,因此一种解决方案可能是制作像 here 那样手动递增。

    ...
    while (sqlca.sqlcode == '\0')
    {
      sql_cursor_pl.curocn++;
      EXEC SQL FETCH :sql_cursor_pl INTO :string_field;
      ...
    }
    ...
    

    【讨论】:

    • 在 fetch-loop 之前设置一次sql_cursor_pl.curocn = 1 就足够了。尽管如此,这听起来像是 Pro*C 中的一个错误
    【解决方案2】:

    问题出在执行FETCH命令之前测试的while条件。

    我通常使用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,如果出现 no data found 错误,这意味着退出 while 循环。 需要第二个指令来恢复所需的行为(在此期间需要中断,但在其余代码中可能不是最佳选择)。

    【讨论】:

    • 感谢您的回答,但我的代码也应该在循环之前包含该语句,并且我认为从从双重检索常量值的选择中返回游标必须始终返回有效光标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多