为什么OCI-Lob->关闭IN OUT参数?

时间:2011-12-20 16:26:25

标签: php oracle clob oci8 lob

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

显然,我可以省略对{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提示可能不适用于此,因为在{NORDOPY限制下的this page下,如果“通过数据库链接或作为外部程序调用子程序”,NOCOPY将被忽略。根据{{​​3}},听起来我的PHP脚本中的匿名块调用存储过程将被视为外部过程。

1 个答案:

答案 0 :(得分:0)

我遇到了一个与临时LOB类似的令人费解的问题(纯Pl / SQL因此在PHP中可能类似)。一些使用持久性LOBS正常工作的代码不适用于临时LOB。经过一番搜索后,我在documentation

中找到了这个注释
  

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

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

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