【问题标题】:Why doesn't OCI-Lob->close work for IN OUT parameters?为什么 OCI-Lob->close 对 IN OUT 参数不起作用?
【发布时间】:2011-12-20 16:26:25
【问题描述】:

从我阅读的有关 LOB 和 OCI8 PHP 扩展的文档中,我似乎应该在下面的代码中调用 $lob->close(),因为我使用了 $lob->writeTemporary()。当我将 LOB 传递给接受 IN 参数的存储过程时,$lob->close() 工作正常,但如果我将 LOB 传递给接受 IN OUT 参数的存储过程,则不起作用。

显然,对于 IN OUT 参数,我可以省略对 $lob->close() 的调用,但我很想知道为什么需要这样做。有人可以解释一下下面的代码中发生了什么导致它产生以下错误吗?非常感谢任何见解。

OCI-Lob::close() [oci-lob.close]: ORA-22289: 无法对未打开的文件或 LOB 执行 %s 操作

$my_clob = 'Lorem ipsum dolor sit amet...';

$connection = oci_connect('user', 'pass', 'connection string');
$statement  = oci_parse($connection, 'begin p_clob_in_out(:p_my_clob); end;');
$lob        = oci_new_descriptor($connection, OCI_D_LOB);

$lob->writeTemporary($my_clob, OCI_TEMP_CLOB);

oci_bind_by_name($statement, ':p_my_clob', $lob, -1, OCI_B_CLOB);

oci_execute($statement, OCI_DEFAULT);

if (is_object($lob))
{
  $data = $lob->load();

  $lob->close();
  $lob->free();
}

echo $data;

p_clob_in_out 过程如下所示:

procedure p_clob_in_out(
    p_my_clob in out clob
)
is
begin
    p_my_clob := 'ABC123... ' || p_my_clob;
end p_clob_in_out;

感谢Vincent Malgrat's 的回答,在进一步阅读后,我认为这就是正在发生的事情......在我的 PHP 代码中,$lob 变量是传入的临时 LOB。该临时 LOB 由过程修改,它会创建它的副本。然后将副本传递出去并替换$lob 变量。在 LOB 的副本上从未调用过 writeTemporary 方法,所以当我调用 $lob->close() 时它会失败。 PHP 脚本无法再访问最初创建的原始 LOB(我可以调用 $lob->close())。

我认为 NOCOPY 提示可能不适用于此处,因为在 this page 的“NOCOPY 限制”下,它指出如果“通过数据库链接或作为外部过程调用子程序”,则 NOCOPY 将被忽略。根据this page,听起来我的PHP脚本中调用存储过程的匿名块将被视为外部过程。

【问题讨论】:

    标签: php oracle clob oci8 lob


    【解决方案1】:

    我遇到了一个与临时 LOB 类似的令人费解的问题(纯 Pl/SQL,因此在 PHP 中可能类似)。一些在持久 LOBS 上运行良好的代码不适用于临时 LOB。经过一番搜索,我在documentation 中找到了这个注释:

    如果用户修改临时 LOB,而另一个定位器也指向它,则会创建临时 LOB 的副本。执行修改的定位器现在指向临时 LOB 的新副本。其他定位器不再看到与进行修改的定位器相同的数据

    如果您在程序中指定NOCOPY,我很想知道您是否遇到同样的问题:procedure p_clob_in_out(p_my_clob in out NOCOPY clob)。您还可以在过程调用后检查您的 lob 是否包含'ABC123... '

    我的推理如下:IN 参数作为引用传递,因此当您将 LOB 作为 IN 参数传递时,无论如何都会修改 LOB。 IN OUT 参数是按值传递的,因此实际上您将过程应用于临时 LOB 的副本(不会深度复制持久 LOB)。

    【讨论】:

    • 这听起来可能与它有关,但是,当我在过程中指定 NOCOPY 时,我仍然遇到同样的问题。无论有没有 NOCOPY,在我尝试关闭它并发生错误之前,LOB 确实包含“ABC123 ...”。
    • 由于您在回答中提供的提示,我想我可能了解现在发生的事情。我用我的发现编辑了我原来的问题,因为它们对于这个评论来说太长了。谢谢!
    • 我同意你的分析。我想知道该副本是否是您的分配行 (p_my_clob := 'ABC123... ' || p_my_clob) 的意外结果。您可以使用 DBMS_LOB.writeappend 函数进行测试吗?即dbms_lob.writeappend(p_my_clob, length('ABC123... '), 'ABC123... ')
    • 这确实有效!如果我使用 NOCOPY 提示和dbms_lob.writeappend,我可以成功调用$lob->close()
    猜你喜欢
    • 1970-01-01
    • 2015-12-14
    • 2020-12-20
    • 2015-07-01
    • 2019-09-14
    • 2012-02-11
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多