Почему OCI-Lob-> close не работает для параметров IN OUT? - PullRequest
2 голосов
/ 20 декабря 2011

Из документации, которую я прочитал относительно больших объектов и расширения PHP OCI8, кажется, что я должен вызвать $lob->close() в приведенном ниже коде, так как я использовал $lob->writeTemporary().$lob->close() отлично работает, когда я передаю большой объект в хранимую процедуру, которая принимает параметр IN, но не работает, если я передаю большой объект в хранимую процедуру, которая принимает параметр IN OUT.

Очевидно, яМожно просто пропустить вызов $lob->close() для параметров IN OUT, но мне любопытно узнать, зачем мне это нужно.Может ли кто-нибудь объяснить, что происходит в приведенном ниже коде, что приводит к следующей ошибке?Любое понимание приветствуется.

OCI-Lob :: close () [oci-lob.close]: ORA-22289: невозможно выполнить операцию% s над неоткрытым файлом или LOB

$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;

После прочтения благодаря ответу Винсента Малграта , я думаю, что это то, чтопроисходит ... В моем PHP-коде переменная $lob - это временный большой объект, который передается. Этот временный большой объект изменяется процедурой, которая создает его копию.Затем копия передается и заменяет переменную $lob.Метод writeTemporary никогда не вызывался для копии большого объекта, поэтому, когда я вызываю $lob->close(), он не работает.Первоначально созданный большой объект (который я мог бы назвать $lob->close() on) больше не доступен сценарием PHP.

Я думаю, что подсказка NOCOPY здесь может не применяться, поскольку на thisна странице в разделе «Ограничения для NOCOPY» указывается, что NOCOPY будет игнорироваться, если «подпрограмма вызывается через ссылку на базу данных или как внешняя процедура».Согласно этой странице , это звучит как анонимный блок в моем PHP-скрипте, который вызывает хранимую процедуру, будет считаться внешней процедурой.

1 Ответ

0 голосов
/ 20 декабря 2011

Я столкнулся с похожей загадочной проблемой с временными большими объектами (чистый Pl / SQL, поэтому может быть похож на PHP). Некоторый код, который работал нормально с постоянными LOBS, не работал с временным LOB. После некоторых поисков я нашел это примечание в документации :

Копия временного большого объекта создается, если пользователь изменяет временный большой объект, в то время как другой локатор также указывает на него. Локатор, для которого была выполнена модификация, теперь указывает на новую копию временного большого объекта. Другие локаторы больше не видят те же данные, что и локатор , с помощью которого была произведена модификация.

Мне было бы интересно посмотреть, столкнетесь ли вы с той же проблемой, если в своей процедуре вы укажете NOCOPY : procedure p_clob_in_out(p_my_clob in out NOCOPY clob). Также можете ли вы проверить, что ваша доля содержит 'ABC123... ' после вызова процедуры?

Мое объяснение таково: IN параметры передаются в качестве ссылки, поэтому LOB в любом случае изменяется, когда вы передаете его в качестве параметра IN. IN OUT параметры передаются по значению, поэтому вы применяете свою процедуру к копии временного большого объекта (постоянные большие объекты не будут копироваться глубоко).

...