Just to write it down. I was trying to do a simple SELECT on a Caché (http://www.intersystems.com/cache/) table through an Oracle dblink, but always received the error "ORA-01002: fetch out of sequence". The solution was using OCI_NO_AUTO_COMMIT on the oci_execute function.
oci_execute
(PHP 5, PECL OCI8 >= 1.1.0)
oci_execute — 文を実行する
説明
oci_parse() が返した statement を実行します。
実行後、INSERT 文などの場合はデフォルトでデータをデータベースにコミットします。 SELECT 文などの場合は問い合わせを実行します。 問い合わせの結果をその後 PHP で取得するには oci_fetch_array() などの関数を使います。
一度パースした文は何度でも実行することができ、 これを使えば毎回パースするコストを節約することができます。 この方法は、oci_bind_by_name() でデータをバインドした INSERT 文で一般的に使われています。
パラメータ
- statement
-
有効な OCI ステートメント ID。
- mode
-
オプションの二番目のパラメータは、次の定数のいずれかとなります。
実行モード 定数 説明 OCI_COMMIT_ON_SUCCESS ステートメントの実行に成功すると、 この接続においてまだ確定していない変更をすべてコミットします。 これがデフォルトです。 OCI_DEFAULT PHP 5.3.2 (PECL OCI8 1.4) で非推奨となりますが、 過去との互換性のためにまだ使用可能です。新しく書くコードでは、 同じ意味となる OCI_NO_AUTO_COMMIT を使いましょう。 OCI_DESCRIBE_ONLY oci_field_name() 関数などでクエリのメタデータを使えるようにしますが、 結果セットは作りません。続けて oci_fetch_array() などをコールすると失敗します。 OCI_NO_AUTO_COMMIT 変更を自動的にはコミットしません。PHP 5.3.2 (PECL OCI8 1.4) より前のバージョンでは OCI_DEFAULT を使います。これは、今では OCI_NO_AUTO_COMMIT のエイリアスとなっています。 OCI_NO_AUTO_COMMIT モードを使うとトランザクションを開始します。 接続を閉じたりスクリプトが終了したりしたときに、 トランザクションは自動的にロールバックされます。 トランザクションをコミットするには oci_commit() を、破棄するには oci_rollback() をコールします。
データを追加したり更新したりする際には、 リレーショナルデータの一貫性やパフォーマンスなどを考慮して トランザクションを使うことを推奨します。
OCI_NO_AUTO_COMMIT モードを使った文を実行した後に oci_commit() あるいは oci_rollback() をコールしなかった場合、 たとえデータが変更されていなくても スクリプトの終了時に OCI8 がロールバックを実行します。 不要なロールバックを避けるために、多くのスクリプトはクエリや PL/SQL で OCI_NO_AUTO_COMMIT モードを使いません。 同じスクリプトの中で異なるモードで oci_execute() を実行する場合は、 アプリケーション内で適切なトランザクションの一貫性を確保するよう注意しましょう。
返り値
成功した場合に TRUE を、失敗した場合に FALSE を返します。
例
例1 oci_execute() での問い合わせの例
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'SELECT * FROM employees');
oci_execute($stid);
echo "<table border='1'>\n";
while ($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
echo "<tr>\n";
foreach ($row as $item) {
echo " <td>" . ($item !== null ? htmlentities($item, ENT_QUOTES) : " ") . "</td>\n";
}
echo "</tr>\n";
}
echo "</table>\n";
?>
例2 モードを指定せずに oci_execute() を実行する例
<?php
// 実行する前にテーブルを作成します。
// CREATE TABLE MYTABLE (col1 NUMBER);
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'INSERT INTO mytab (col1) VALUES (123)');
oci_execute($stid); // 結果はコミットされ、他のユーザからもすぐに見えるようになります
?>
例3 oci_execute() で OCI_NO_AUTO_COMMIT を使う例
<?php
// 実行する前にテーブルを作成します。
// CREATE TABLE MYTABLE (col1 NUMBER);
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'INSERT INTO mytab (col1) VALUES (:bv)');
oci_bind_by_name($stid, ':bv', $i, 10);
for ($i = 1; $i <= 5; ++$i) {
oci_execute($stid, OCI_NO_AUTO_COMMIT); // PHP <= 5.3.1 の場合は OCI_DEFAULT を使います
}
oci_commit($conn); // 新しい値 1, 2, 3, 4, 5 をすべてコミットします
?>
例4 oci_execute() でさまざまなコミットモードを使う例
<?php
// 実行する前にテーブルを作成します。
// CREATE TABLE MYTABLE (col1 NUMBER);
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'INSERT INTO mytab (col1) VALUES (123)');
oci_execute($stid, OCI_NO_AUTO_COMMIT); // データはコミットされません
$stid = oci_parse($conn, 'INSERT INTO mytab (col1) VALUES (456)');
oci_execute($stid); // 123 と 456 が両方コミットされます
?>
例5 oci_execute() で OCI_DESCRIBE_ONLY を使う例
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
$stid = oci_parse($conn, 'SELECT * FROM locations');
oci_execute($s, OCI_DESCRIBE_ONLY);
for ($i = 1; $i <= oci_num_fields($stid); ++$i) {
echo oci_field_name($stid, $i) . "<br>\n";
}
?>
注意
注意:
トランザクションは接続を閉じたとき、 もしくはスクリプトの終了時のいずれの場合でも すぐに自動的にロールバックされます。 トランザクションをコミットするには oci_commit() をコールする必要があります。
OCI_COMMIT_ON_SUCCESS モードを指定するか、 あるいはデフォルトの状態で oci_execute() をコールすると、 それ以前の未コミットのトランザクションをコミットします。
CREATE や DROP といった Oracle の DDL は、未コミットのトランザクションを自動的にコミットします。
注意:
oci_execute() 関数は 通常はステートメントをデータベースに送信するので、 ステートメントの構文エラーなどを特定することもできます。 軽量なローカル版の oci_parse() ではこれはできません。
注意:
PHP 5.0.0 より前のバージョンでは、かわりに ociexecute() を使用します。現在のバージョンでは、古い関数名もまだ使えます。 しかし、これは廃止予定であり非推奨です。
Notice (PHP 5.2.12-pl0-gentoo):
You can parse empty query, you can execute empty query (returns true), but you cannot fetch data from empty query. So, if you provide query as variable, make sure it isn't empty.
<?php
$q = oci_parse($c, "");
if($q != false){
// parsing empty query != false
if(oci_execute($q){
// executing empty query != false
if(oci_fetch_all($q, $data, 0, -1, OCI_FETCHSTATEMENT_BY_ROW) == false){
// but fetching executed empty query results in error (ORA-24338: statement handle not executed)
$e = oci_error($q);
echo $e['message'];
}
}
else{
$e = oci_error($q);
echo $e['message'];
}
}
else{
$e = oci_error($link);
echo $e['message'];
}
?>
