从我读过的有关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脚本中的匿名块调用存储过程将被视为外部过程。
答案 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不会被深度复制)。