PHP Unconference Europe 2015

oci_bind_by_name

(PHP 5, PECL OCI8 >= 1.1.0)

oci_bind_by_nameOracle プレースホルダに PHP 変数をバインドする

説明

bool oci_bind_by_name ( resource $statement , string $bv_name , mixed &$variable [, int $maxlength = -1 [, int $type = SQLT_CHR ]] )

PHP の変数 variable を Oracle プレースホルダ bv_name にバインドします。 バインドは Oracle データベースのパフォーマンスに影響を及ぼす重要な仕組みで、 SQL インジェクション攻撃を防ぐための方法にもなります。

バインドを使うとデータベースでステートメントのコンテキストを (たとえ別のユーザーやプロセスが実行したものであっても) 再利用することができるようになります。 バインドによって SQL インジェクションの心配を軽減できる理由は、 バインド変数で代入したデータが決して SQL 文の一部と見なされることがないからです。 クォートやエスケープは不要です。

バインドする PHP 変数の中身を変更してステートメントを再実行するときにも、 ステートメントをパースしなおしたり変数をバインドしなおしたりする必要はありません。

Oracle のバインド変数は、データベースに渡す値に使う IN 変数と PHP に返される値に使う OUT 変数のふたつに大別できます。 バインド変数は IN あるいは OUT のどちらかの形式になります。バインド変数を入力用に使うか出力用に使うかは、 実行時に決まります。

OUT 変数を使う場合は maxlength を指定しなければなりません。 これを用いて、返される値を格納するのに必要なメモリを PHP が確保します。

IN 変数の場合も、もし PHP の変数にさまざまな値を格納してステートメントを何度も実行するのであれば maxlength を設定しておくことを推奨します。 そうしないと、最初に渡した PHP の変数の値にあわせて Oracle がデータの長さを切り詰めてしまう可能性があります。 最大長がどの程度になるかわからない場合は現在のデータサイズで oci_bind_by_name() を再コールしてから oci_execute() を実行するようにしましょう。 不必要に大きなサイズでバインドすると、 データベースのプロセスのメモリ使用量に影響を及ぼします。

バインドは、Oracle にデータをどのメモリアドレスから読み込むのかを指示します。 IN 変数の場合、oci_execute() がコールされたときにそのメモリアドレスに正しいデータがなければなりません。 つまり、バインドされる変数は実行時までスコープ内に残っていなければならないということです。 もしそうでなければ、 "ORA-01460: unimplemented or unreasonable conversion requested" のような予期せぬエラーが発生します。 OUT 変数の場合は、PHP の変数に何も値が格納されないといったことになるでしょう。

繰り返し実行されるステートメントで決して値が変わることのないバインド変数を使っていると、 Oracle のオプティマイザが最適な実行プランを選びにくくなる可能性があります。 実行に長い時間がかかり、再実行されることもめったにないようなステートメントは、 バインドの恩恵を受けられないでしょう。 しかし、どちらの場合であっても、文字列を連結して SQL 文を作るよりはバインドを使ったほうが安全です。 ユーザーの入力をフィルタリングせずに埋め込んでしまうというリスクをなくせるからです。

パラメータ

statement

有効な OCI8 ステートメント識別子。

bv_name

コロンを先頭につけたバインド変数プレースホルダをステートメント内で使います。 コロンは bv_name では必須ではありません。 Oracle はクエスチョンマークをプレースホルダとして使いません。

variable

bv_name に関連づける PHP の変数。

maxlength

バインド時の最大長。-1 に設定した場合、 variable の現在の長さを最大長として設定します。 この場合は、oci_bind_by_name() がコールされたときに variable が存在してデータが格納されている必要があります。

type

Oracle がデータを扱うときのデータ型。デフォルトの typeSQLT_CHR です。 Oracle は、可能な場合はこの型とデータベースのカラム (あるいは PL/SQL の変数) の型の間で変換を行います。

抽象データ型 (LOB/ROWID/BFILE) をバインドする必要がある場合、まず oci_new_descriptor() 関数を使用してこれを確保する必要があります。 length は抽象データ型用には 使用されず、-1 を設定する必要があります。

type に設定できる値は以下のとおりです。

  • SQLT_BFILEE or OCI_B_BFILE - BFILE 用

  • SQLT_CFILEE or OCI_B_CFILEE - CFILE 用

  • SQLT_CLOB or OCI_B_CLOB - CLOB 用

  • SQLT_BLOB or OCI_B_BLOB - BLOB 用

  • SQLT_RDD or OCI_B_ROWID - ROWID 用

  • SQLT_NTY or OCI_B_NTY - 名前付けされたデータ型用

  • SQLT_INT or OCI_B_INT - integer 用

  • SQLT_CHR - VARCHAR 用

  • SQLT_BIN or OCI_B_BIN - RAW カラム用

  • SQLT_LNG - LONG カラム用

  • SQLT_LBI - LONG RAW カラム用

  • SQLT_RSET - カーソル用。 oci_new_cursor() により、前もって生成されたもの。

  • SQLT_BOL あるいは OCI_B_BOL PL/SQL の BOOLEAN 用 (OCI8 2.0.7 以降と Oracle Database 12c 以降が必要)

返り値

成功した場合に TRUE を、失敗した場合に FALSE を返します。

例1 oci_bind_by_name() によるデータの挿入

<?php

// このようなテーブルを作ります
//   CREATE TABLE mytab (id NUMBER, text VARCHAR2(40));

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$stid oci_parse($conn,"INSERT INTO mytab (id, text) VALUES(:id_bv, :text_bv)");

$id 1;
$text "Data to insert     ";
oci_bind_by_name($stid":id_bv"$id);
oci_bind_by_name($stid":text_bv"$text);
oci_execute($stid);

// テーブルに入る内容: 1, 'Data to insert     '

?>

例2 一度組み立てたものを複数回実行

<?php

// このようなテーブルを作ります
//   CREATE TABLE mytab (id NUMBER);

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$a = array(1,3,5,7,11);  // 挿入するデータ

$stid oci_parse($conn'INSERT INTO mytab (id) VALUES (:bv)');
oci_bind_by_name($stid':bv'$v20);
foreach (
$a as $v) {
    
$r oci_execute($stidOCI_DEFAULT);  // 自動コミットはしません
}
oci_commit($conn); // すべてをここでコミットします

// テーブルには次の 5 行が含まれます: 1, 3, 5, 7, 11

oci_free_statement($stid);
oci_close($conn);

?>

例3 foreach() ループでのバインド

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql 'SELECT * FROM departments WHERE department_name = :dname AND location_id = :loc';
$stid oci_parse($conn$sql);

$ba = array(':dname' => 'IT Support'':loc' => 1700);

foreach (
$ba as $key => $val) {

    
// oci_bind_by_name($stid, $key, $val) ではうまくいきません。
    // これは、すべてのプレースホルダを同じ内容にバインドしてしまうからです。
    // $val ではなく、データの実際の位置を表す $ba[$key] を使いましょう。
    
oci_bind_by_name($stid$key$ba[$key]);
}

oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS);
foreach (
$row as $item) {
    print 
$item."<br>\n";
}

oci_free_statement($stid);
oci_close($conn);

?>

例4 WHERE 句でのバインド

<?php

$conn 
oci_connect("hr""hrpwd""localhost/XE");
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql 'SELECT last_name FROM employees WHERE department_id = :didbv ORDER BY last_name';
$stid oci_parse($conn$sql);
$didbv 60;
oci_bind_by_name($stid':didbv'$didbv);
oci_execute($stid);
while ((
$row oci_fetch_array($stidOCI_ASSOC)) != false) {
    echo 
$row['LAST_NAME'] ."<br>\n";
}

// 出力は
//    Austin
//    Ernst
//    Hunold
//    Lorentz
//    Pataballa

oci_free_statement($stid);
oci_close($conn);

?>

例5 LIKE 句でのバインド

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

// 'South' からはじまるすべての都市を探します
$stid oci_parse($conn"SELECT city FROM locations WHERE city LIKE :bv");
$city 'South%';  // '%' は SQL でのワイルドカードです
oci_bind_by_name($stid":bv"$city);
oci_execute($stid);
oci_fetch_all($stid$res);

foreach (
$res['CITY'] as $c) {
    print 
$c "<br>\n";
}
// 出力は
//   South Brunswick
//   South San Francisco
//   Southlake

oci_free_statement($stid);
oci_close($conn);

?>

例6 REGEXP_LIKE でのバインド

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

// 'ing' を含むすべての都市を探します
$stid oci_parse($conn"SELECT city FROM locations WHERE REGEXP_LIKE(city, :bv)");
$city '.*ing.*';
oci_bind_by_name($stid":bv"$city);
oci_execute($stid);
oci_fetch_all($stid$res);

foreach (
$res['CITY'] as $c) {
    print 
$c "<br>\n";
}
// 出力は
//   Beijing
//   Singapore

oci_free_statement($stid);
oci_close($conn);

?>

IN 句の中の条件数が少なくて固定なのであれば、個々にバインド変数を割り当てればいいでしょう。 実行時に不明な値は NULL が設定されます。 こうすればひとつのステートメントをすべてのユーザーで使い回すことができ、 Oracle の DB キャッシュの効率を最大化させることができます。

例7 IN 句での複数の値のバインド

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql 'SELECT last_name FROM employees WHERE employee_id in (:e1, :e2, :e3)';
$stid oci_parse($conn$sql);
$mye1 103;
$mye2 104;
$mye3 NULL// pretend we were not given this value
oci_bind_by_name($stid':e1'$mye1);
oci_bind_by_name($stid':e2'$mye2);
oci_bind_by_name($stid':e3'$mye3);
oci_execute($stid);
oci_fetch_all($stid$res);
foreach (
$res['LAST_NAME'] as $name) {
    print 
$name ."<br>\n";
}

// 出力は
//   Ernst
//   Hunold

oci_free_statement($stid);
oci_close($conn);

?>

例8 クエリが返す ROWID のバインド

<?php

// このようなテーブルを作ります
//   CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//   INSERT INTO mytab (id, salary, name) VALUES (1, 100, 'Chris');
//   COMMIT;

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$stid oci_parse($conn'SELECT ROWID, name FROM mytab WHERE id = :id_bv FOR UPDATE');
$id 1;
oci_bind_by_name($stid':id_bv'$id);
oci_execute($stid);
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS);
$rid $row['ROWID'];
$name $row['NAME'];

// 名前を大文字に変換してそれを保存します
$name strtoupper($name);
$stid oci_parse($conn'UPDATE mytab SET name = :n_bv WHERE ROWID = :r_bv');
oci_bind_by_name($stid':n_bv'$name);
oci_bind_by_name($stid':r_bv'$rid, -1OCI_B_ROWID);
oci_execute($stid);

// テーブルに入る内容: 1, 100, CHRIS

oci_free_statement($stid);
oci_close($conn);

?>

例9 INSERT での ROWID のバインド

<?php

// この例では id と name を挿入し、それから salary を更新します
// このようなテーブルを作ります
//   CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// Based on original ROWID example by thies at thieso dot net (980221)

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$m oci_error();
    
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql "INSERT INTO mytab (id, name) VALUES(:id_bv, :name_bv)
        RETURNING ROWID INTO :rid"
;

$ins_stid oci_parse($conn$sql);

$rowid oci_new_descriptor($connOCI_D_ROWID);
oci_bind_by_name($ins_stid":id_bv",   $id,    10);
oci_bind_by_name($ins_stid":name_bv"$name,  32);
oci_bind_by_name($ins_stid":rid",     $rowid, -1OCI_B_ROWID);

$sql "UPDATE mytab SET salary = :salary WHERE ROWID = :rid";
$upd_stid oci_parse($conn$sql);
oci_bind_by_name($upd_stid":rid"$rowid, -1OCI_B_ROWID);
oci_bind_by_name($upd_stid":salary"$salary,   32);

// 挿入する id と name
$data = array(1111 => "Larry",
              
2222 => "Bill",
              
3333 => "Jim");

// それぞれの salary
$salary 10000;

// 挿入し、その後すぐに各行を更新します
foreach ($data as $id => $name) {
    
oci_execute($ins_stid);
    
oci_execute($upd_stid);
}

$rowid->free();
oci_free_statement($upd_stid);
oci_free_statement($ins_stid);

// 新しい行を表示します
$stid oci_parse($conn"SELECT * FROM mytab");
oci_execute($stid);
while (
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS)) {
    
var_dump($row);
}

oci_free_statement($stid);
oci_close($conn);

?>

例10 PL/SQL ストアドファンクションでのバインド

<?php

//  PHP プログラムを実行する前に、ストアドファンクションを
//  SQL*Plus あるいは SQL Developer で作ります
//
//  CREATE OR REPLACE FUNCTION myfunc(p IN NUMBER) RETURN NUMBER AS
//  BEGIN
//      RETURN p * 3;
//  END;

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$p 8;

$stid oci_parse($conn'begin :r := myfunc(:p); end;');
oci_bind_by_name($stid':p'$p);

// 返り値は OUT 変数に格納されます。デフォルトの型は文字列型なので、
// length が 40 ということは最大で 40 まで返される可能性があるということです
oci_bind_by_name($stid':r'$r40);

oci_execute($stid);

print 
"$r\n";   // 24 と表示します

oci_free_statement($stid);
oci_close($conn);

?>

例11 PL/SQL ストアドプロシージャでのパラメータのバインド

<?php

//  PHP プログラムを実行する前に、ストアドプロシージャを
//  SQL*Plus あるいは SQL Developer で作ります
//
//  CREATE OR REPLACE PROCEDURE myproc(p1 IN NUMBER, p2 OUT NUMBER) AS
//  BEGIN
//      p2 := p1 * 2;
//  END;

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$p1 8;

$stid oci_parse($conn'begin myproc(:p1, :p2); end;');
oci_bind_by_name($stid':p1'$p1);

// プロシージャの 2 番目のパラメータは OUT 変数です。デフォルトの型は文字列型なので、
// length が 40 ということは最大で 40 まで返される可能性があるということです
oci_bind_by_name($stid':p2'$p240);

oci_execute($stid);

print 
"$p2\n";   // 16 と表示します

oci_free_statement($stid);
oci_close($conn);

?>

例12 CLOB 列のバインド

<?php

// 実行する前にテーブルを作成します。
//     CREATE TABLE mytab (mykey NUMBER, myclob CLOB);

$conn oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$mykey 12343;  // この例のための任意のキー

$sql "INSERT INTO mytab (mykey, myclob)
        VALUES (:mykey, EMPTY_CLOB())
        RETURNING myclob INTO :myclob"
;

$stid oci_parse($conn$sql);
$clob oci_new_descriptor($connOCI_D_LOB);
oci_bind_by_name($stid":mykey"$mykey5);
oci_bind_by_name($stid":myclob"$clob, -1OCI_B_CLOB);
oci_execute($stidOCI_DEFAULT);
$clob->save("A very long string");

oci_commit($conn);

// CLOB データを取得します

$query 'SELECT myclob FROM mytab WHERE mykey = :mykey';

$stid oci_parse ($conn$query);
oci_bind_by_name($stid":mykey"$mykey5);
oci_execute($stid);

print 
'<table border="1">';
while (
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_LOBS)) {
    print 
'<tr><td>'.$row['MYCLOB'].'</td></tr>';
    
// ループ内で、大きなサイズの変数を解放してから次のフェッチに進めます。
    // これで、PHP のピークメモリ利用量を抑えます。
    
unset($row);
}
print 
'</table>';

?>

例13 PL/SQL の BOOLEAN のバインド

<?php

$conn 
oci_connect('hr''welcome''localhost/XE');
if (!
$conn) {
    
$e oci_error();
    
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$plsql 
  
"begin
    :output1 := true;
    :output2 := false;
   end;"
;

$s oci_parse($c$plsql);
oci_bind_by_name($s':output1'$output1, -1OCI_B_BOL);
oci_bind_by_name($s':output2'$output2, -1OCI_B_BOL);
oci_execute($s);
var_dump($output1);  // true
var_dump($output2);  // false

?>

返り値

成功した場合に TRUE を、失敗した場合に FALSE を返します。

注意

警告

クォートは不要なので、magic_quotes_gpcaddslashes()oci_bind_by_name() と同時に使わないでください。 自動的に追加されたクォートはデータベースの中にそのまま書き込まれてしまいます。 oci_bind_by_name() はデータをそのままの形で追加し、クォートやエスケープ文字の除去は行わないからです。

注意:

WHERE 句の中の CHAR 型のカラムに文字列をバインドするときには、 Oracle における CHAR 型のカラムの比較が スペースで埋めた (固定長形式で) 行われることを覚えておきましょう。 WHERE 句を期待通りに動作させるには、 PHP の変数側でもスペースを追加してカラムの幅と同じにしておく必要があります。

注意:

PHP の variable 引数は参照渡しです。 ループの形式によっては期待通りの動きをしないこともあります。

<?php
foreach ($myarray as $key => $value)  {
    
oci_bind_by_name($stid$key$value);
}
?>

これは、それぞれのキーに対して $value の指す場所をバインドします。 つまり、すべてのバインド変数の値は ループの最後の処理で $value が指す値となります。 期待通りに動かすには、次のようにします。

<?php
foreach ($myarray as $key => $value) {
    
oci_bind_by_name($stid$key$myarray[$key]);
}
?>

参考

add a note add a note

User Contributed Notes 9 notes

up
1
adrian dot crossley at hesa dot ac dot uk
5 years ago
Sometimes you get the error "ORA-01461: can bind a LONG value only for insert into a LONG column".  This error is highly misleading especially when you have no LONG columns or LONG values.

From my testing it seems this error can be caused when the value of a bound variable exceeds the length allocated.

To avoid this error make sure you specify lengths when binding varchars e.g.
<?php
oci_bind_by_name
($stmt,':string',$string, 256);
?>

And for numerics use the default length (-1) but tell oracle its an integer e.g.
<?php
oci_bind_by_name
($stmt,':num',$num, -1, SQLT_INT);
?>
up
1
ajitsingh4u at gmail dot com
6 years ago
//Calling Oracle Stored Procedure
//I assume that you have a users table and three columns in users table i.e. id, user, email in oracle
// For example I made connection in constructor, you can modify as per your requirement.
//http://www.devshed.com/c/a/PHP/Understanding-Destructors-in-PHP-5/1/
<?php
class Users{
    private
$connection;
   
    public function
__construct()
    {
       
$this->connection = oci_connect("scott", "tiger", $db); // Establishes a connection to the Oracle server;
   
}

    public function
selectUsers($start_index=1, $numbers_of_rows=20)
    {
       
$sql ="BEGIN sp_users_select(:p_start_index, :p_numbers_of_rows, :p_cursor, :p_result); END;";
       
$stmt = oci_parse($this->connection, $sql);

       
//Bind in parameter
       
oci_bind_by_name($stmt, ':p_start_index', $start_index, 20);
       
oci_bind_by_name($stmt, ':p_numbers_of_rows', $numbers_of_rows, 20);

       
//Bind out parameter
       
oci_bind_by_name($stmt, ':p_result', $result, 20); // returns 0 if stored procedure succeessfully executed.

        //Bind Cursor
       
$p_cursor = oci_new_cursor($this->connection);
       
oci_bind_by_name($stmt, ':p_cursor', $p_cursor, -1, OCI_B_CURSOR);

       
// Execute Statement
       
oci_execute($stmt);
       
oci_execute($p_cursor, OCI_DEFAULT);

       
oci_fetch_all($p_cursor, $cursor, null, null, OCI_FETCHSTATEMENT_BY_ROW);

        echo
$result;
        echo
'<br>';
       
var_dump($cursor); // $cursor is an associative array so we can use print_r() to print this data.
        // you can return data from this function to use it at your user interface.
   
}

    public function
deleteUser($id)
    {
       
$sql ="BEGIN sp_user_delete(:p_id, :p_result); END;";
       
$stmt = oci_parse($this->connection, $sql);

       
// bind in and out variables
       
oci_bind_by_name($stmt, ':p_id', $id, 20);
       
oci_bind_by_name($stmt, ':p_result', $result, 20);

       
//Execute the statement
       
$check = oci_execute($stmt);

        if(
$check == true)
       
$commit = oci_commit($this->connection);
        else
       
$commit = oci_rollback($this->connection);

        return
$result;
    }
   
   
// You can make function for insert ,update using above two functions

}
?>
up
0
xorinox at gmx dot ch
1 month ago
Working with Oracle and raw types in and out worked like the following for me.

<?php
 
/*oracle procedure
  procedure open_session(
    i_instance_id in raw,
    o_session_id out raw,
    o_errcode out number,
    o_errmsg out varchar2
  ); 
  */

  //open database
 
$conn = DBOpen( DB_DEV_USER );

 
//get session id
 
$sql = "begin p_loader.open_session( hextoraw( :instance_id ), :session_id, :errcode, :errmsg ); end;";
 
$stmt = oci_parse( $conn, $sql );
 
$instanceId = DB_INSTANCE_ID;
 
oci_bind_by_name( $stmt, ":instance_id", $instanceId, 1, SQLT_CHR );
 
oci_bind_by_name( $stmt, ":session_id", $sessionId, 16, SQLT_BIN );
 
oci_bind_by_name( $stmt, ":errcode", $errcode, 12, SQLT_INT );
 
oci_bind_by_name( $stmt, ":errmsg", $errmsg, 4000, SQLT_CHR );
 
 
oci_execute( $stmt );
 
$sessionId = bin2hex( $sessionId ); //now this is a hex string
 
  //close database
 
DBClose( $conn );
?>
up
0
jjeffman at cpovo.net
6 months ago
It is very important to set up the maxlength of the returning parameter (:r), even when it is returning a number, otherwise the ORA-01460 exception (unimplemented or unreasonable conversion requested) may be raised.
up
0
abiyi2000 at yahoo dot com
3 years ago
I unfortunately spent the whole day trying to make this work as part of OCI bind_by_name insert:

<?php
     
if(is_numeric($v2)){
       
oci_bind_by_name($stmth, $bvar, $v2,  -1, OCI_B_INT);
      }else{
       
$v2 = (string) $v2;
       
oci_bind_by_name($stmth, $bvar, $v2, -1, SQLT_CHR);
      }
?>

The string field is always inserting correctly w/o any truncation. The string field is a  varchar2(160) CHAR, but the data used to populate it is 40 chars in length.

The numeric part is of Type Number in the database which is being used to store unix time (10 digit seconds since 1970/01/01.

The problem, the insert was truncating to 9 digits with some bogus value not even related to the input i.e., it's not just a matter of dropping the leftmost or rightmost digit, it'll just insert a 9 digit bogus number.

The only way I was able to resolve this for the numeric field was to set the maxlength to 8 (not 10 which is the number of digits in the input):

<?php
     
if(is_numeric($v2)){
       
oci_bind_by_name($stmth, $bvar, $v28, OCI_B_INT);
      }else{
       
$v2 = (string) $v2;
       
oci_bind_by_name($stmth, $bvar, $v2, -1, SQLT_CHR);
      }
?>

Hopefully you'll see this soon before you expend a lot of time repeating the same problem I had.
up
0
avenger at php dot net
5 years ago
Dont forget the 5th parameter: $type. It's will slowly your code some times. Eg:

<?php
$sql
= "select * from (select * from b xxx) where rownum < :rnum";
$stmt = OCIParse($conn,$sql);
OCIBindByName($stmt, ":rnum", $NUM, -1);
OCIExecute($stmt);
?>

Below code was slow 5~6 time than not use bind value.Change the 3rd line to:

<?php
OCIBindByName
($stmt, ":rnum", $NUM, -1, SQLT_INT);
?>

will resloved this problem.

This issue is also in the ADODB DB class(adodb.sf.net), you will be careful for use the SelectLimit method.
up
0
Anonymous
7 years ago
This is what the old OCI_B_* constants are now called:
(PHP 5.1.6 win32)

OCI_B_NTY - SQLT_NTY
OCI_B_BFILE - SQLT_BFILEE
OCI_B_CFILEE - SQLT_CFILEE
OCI_B_CLOB - SQLT_CLOB
OCI_B_BLOB - SQLT_BLOB
OCI_B_ROWID - SQLT_RDD
OCI_B_CURSOR - SQLT_RSET
OCI_B_BIN - SQLT_BIN
OCI_B_INT - SQLT_INT
OCI_B_NUM - SQLT_NUM
up
0
Chris Delcamp
7 years ago
This is an example of returning the primary key from an insert so that you can do inserts on other tables with foreign keys based on that value.  The date is just used to provied semi-unique data to be inserted.

$conn = oci_connect("username", "password")
$stmt = oci_parse($conn, "INSERT INTO test (test_msg) values (:data) RETURN test_id INTO :RV");
$data = date("d-M-Y H:i:s");
oci_bind_by_name($stmt, ":RV", $rv, -1, SQLT_INT);
oci_bind_by_name($stmt, ":data", $data, 24);
oci_execute($stmt);
print $rv;
up
0
hfuecks at nospam dot org
9 years ago
Note that there have been some changes on the constant identifiers and the documentation is currently not entirely accurate.

Running the following script;

<?php
foreach (array_keys(get_defined_constants()) as $const) {
    if (
preg_match('/^OCI_B_/', $const) ) {
        print
"$const\n";
    }
}
?>

Under PHP 4.4.0 I get;

OCI_B_SQLT_NTY < renamed to OCI_B_NTY with PHP5
OCI_B_BFILE
OCI_B_CFILEE
OCI_B_CLOB
OCI_B_BLOB
OCI_B_ROWID
OCI_B_CURSOR
OCI_B_BIN

Under PHP 5.0.4 I get;

OCI_B_NTY
OCI_B_BFILE < docs are wrong right now
OCI_B_CFILEE < docs are wrong right now
OCI_B_CLOB
OCI_B_BLOB
OCI_B_ROWID
OCI_B_CURSOR
OCI_B_BIN < it's a mystery
To Top