ScotlandPHP

oci_bind_by_name

(PHP 5, PHP 7, PECL OCI8 >= 1.1.0)

oci_bind_by_nameПрикрепляет переменную PHP к соответствующей метке в SQL-выражении

Описание

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

Прикрепляет переменную variable к метке bv_name. Такое прикрепление позволяет повысить производительность и избежать SQL-инъекций.

Прикрепление переменной позволяет базе данных повторно использовать кэшированные контекстные выражения от предыдущих запросов, даже если они первоначально были запущены другим пользователем или процессом. Это также снижает риск SQL-инъекций, поскольку данные в таком случае никогда не рассматриваются как инструкции SQL. Данные не требуется экранировать или заключать в кавычки.

Прикрепленные PHP-переменные могут быть изменены и снова выполнены без необходимости повторной обработки запроса или повторного прикрепления.

В Oracle, прикрепление переменных обычно разделяют на IN (прикрепляет значения, передаваемые в базу данных) и OUT (прикрепляет значения, возвращаемые PHP). Переменная может быть одновременно IN и OUT. Независимо от этого, характер прикрепленния переменных будет определен во время выполнения.

Необходимо указать maxlength при использовании OUT-привязки, что позволяет PHP зарезервировать больше памяти для хранения возвращаемого значения

Для IN-привязки рекомендуется также указать параметр maxlength, если выражение выполняется несколько раз с различными значениями PHP-переменной. В противном случае, Oracle может урезать размер данных до размера первоначального значения переменной PHP. Если максимальная длина значения неизвестна, рекомендуется вызывать oci_bind_by_name() перед каждым вызовом oci_execute(). Прикрепление неоправданно большой переменной повлияет на процесс сохранения базы данных.

Вид прикрепления указывает Oracle как работать с памятью при чтении данных. Для IN-прикрепления адрес в памяти должен содержать допустимые данные при вызове oci_execute(). Это значит, что значение переменной должно находиться в памяти во время исполнения. Если это не так, возможны некорректные результаты или ошибки наподобие "ORA-01460: unimplemented or unreasonable conversion requested" (запрошены невыполнимые или некорректные преобразования) Для OUT-прикрепления основным признаком является установка значения в переменную PHP.

Для многократно выполняемого выражения, привязка одних и тех же значений может уменьшить возможности оптимизатора Oracle по выработке наилучшего варианта выполнения инструкции. Длительное прикрепление выражений, которые редко исполняются, может также не принести пользы. Тем не менее, в обоих случаях, прикрепление является более безопасным, чем конкатенация строки запроса и непроверенных пользовательских данных.

Список параметров

statement

Допустимый идентификатор выражения OCI8.

bv_name

Метка с префиксом в виде двоеточия, используемая в выражении. Двоеточие опционально в bv_name. Oracle не использует знак вопроса для меток.

variable

Переменная PHP, ассоциированная с bv_name

maxlength

Устанавливает максимальный размер данных. Если указать -1, функция будет использовать текущий размер переменной variable в качестве максимального. При этом переменная variable должна существовать и содержать данные во время вызова oci_bind_by_name().

type

Тип данных, к которому Oracle будет приводить значения. По умолчанию type имеет значение SQLT_CHR. Oracle приводит данные от данного типа к типу поля (или типу переменной PL/SQL), если это возможно.

Если необходимо прикрепить переменную абстрактного типа (LOB/ROWID/BFILE), следует предварительно использовать oci_new_descriptor(). Параметр length не используется для абстрактных типов и должен быть установлен в -1.

Допустимые значения параметра type:

  • SQLT_BFILEE или OCI_B_BFILE - для BFILE-объектов;

  • SQLT_CFILEE или OCI_B_CFILEE - для CFILE-объектов;

  • SQLT_CLOB или OCI_B_CLOB - для CLOB-объектов;

  • SQLT_BLOB или OCI_B_BLOB - для BLOB-объектов;

  • SQLT_RDD или OCI_B_ROWID - для ROWID-объектов;

  • SQLT_NTY или OCI_B_NTY - для именованных типов даты;

  • SQLT_INT или OCI_B_INT - для целых чисел;

  • SQLT_CHR - для символов VARCHAR;

  • SQLT_BIN или 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); // завершение транзакции

// Таблица содержит пять записей: 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// притворимся, что не получили это значение
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 OUT-прикрепление ROWID, возвращаемое при INSERT

<?php

// В данном примере добавляется запись с идентификатором и именем,
// после чего увеличивается заработная плата
// Создание таблицы:
//   CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// На основе собственных ROWID на примере thies[at]thieso.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);

// идентификаторы и имена для вставки
$data = array(1111 => "Larry",
              
2222 => "Bill",
              
3333 => "Jim");

// Заработная плата для каждого сотрудника
$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-прикреплено. По умолчаннию типом данных будет строка.
// Прикрепление со значением 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);

// Второй параметр процедуры OUT-прикреплен. По умолчаннию типом данных будет строка.
// Прикрепление со значением 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_gpc или addslashes() одновременно с oci_bind_by_name(), так как кавычек быть не должно. Все указанные кавычки будут записаны в базу данных, потому что oci_bind_by_name() вставляет данные дословно и не удаляет кавычки или символы экранирования.

Замечание:

Если прикрепляется строка к CHAR-полю в выражении WHERE, помните, что Oracle использует при сравнении значения CHAR, дополненные пробелами. Переменная PHP должна быть дополнена пробелами до того же размера, что и поле, чтобы выражение WHERE выполнялось верно.

Замечание:

Переменная PHP variable является ссылкой. Некоторые виды циклов могут работать не так, как ожидается:

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

В этом случае каждый ключ прикрепляется к $value, поэтому все прикрепленные переменные указывают на значение в последней итерации цикла. Вместо этого следует использовать:

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

Смотрите также

  • oci_bind_array_by_name() - Связывает PHP массив с массивом Oracle PL/SQL
  • oci_parse() - Подготавливает запрос к выполнению

add a note add a note

User Contributed Notes 15 notes

up
2
martin dot abbrent at ufz dot de
1 year ago
Example #7 only shows the binding of a small fixed number of values in an IN clause. There is also a way to bind multiple conditions with a variable number of values.

<?php
$ids
= array(
   
103,
   
104
);

$conn         = oci_pconnect($user, $pass, $tns);
// Using ORACLE table() function to get the ids from the subquery
$sql          = 'SELECT * FROM employees WHERE employee_id IN (SELECT column_value FROM table(:ids))';
$stmt         = oci_parse($conn, $sql);
// Create collection of numbers. Build in type for strings is ODCIVARCHAR2LIST, but you can also create own types.
$idCollection = oci_new_collection($conn, 'ODCINUMBERLIST', 'SYS');

// Maximum length of collections of type ODCINUMBERLIST is 32767, maybe you should check that!
foreach ($ids as $id) {
   
$idCollection->append($id);
}

oci_bind_by_name($stmt, ':ids', $idCollection, -1, SQLT_NTY);
oci_execute($stmt, OCI_DEFAULT);
oci_fetch_all($stmt, $return);
oci_free_statement($stmt);

oci_close($conn);

?>
up
2
abiyi2000 at yahoo dot com
6 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
1
jjeffman at cpovo.net
3 years 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
splintyg at gmail dot com
3 days ago
Guys, i've been looking for long time, how to pass clob to and get from procedure
CREATE OR REPLACE PROCEDURE myproc(p1 IN clob, p2 OUT clob);

Here You are an answer:

<?php
        $conn
= oci_connect("TEST", "html", "//hostname", "UTF8");

   
$filename = "./clob.txt";
   
$handle = fopen($filename, "r");
   
$f = fread($handle, filesize($filename));
   
fclose($handle);

   
$stid = oci_parse($conn, "begin myproc(:p1, :p2); end;");
   
$p1 = oci_new_descriptor($conn, OCI_D_LOB);
   
$p2 = oci_new_descriptor($conn, OCI_D_LOB);
   
   
oci_bind_by_name($stid, ":p1", $p1, -1, OCI_B_CLOB);
   
oci_bind_by_name($stid, ":p2", $p2, -1, OCI_B_CLOB);
   
$p1->writeTemporary($f, OCI_TEMP_BLOB);
   
oci_execute($stid); -- Figure out OCI_NO_AUTO_COMMIT
    oci_commit
($conn);
    echo
$p2->load();
   
   
$p1    ->close();
   
$p2    ->close();
   
oci_free_statement($stid);
   
oci_close($conn);
?>

And perfect book about "PHP and Oracle"
http://www.oracle.com/technetwork/topics/php/underground-php-oracle-manual-098250.html
up
0
splintyg at gmail dot com
3 days ago
Guys, i've been looking for long time, how to pass clob to and get from procedure
CREATE OR REPLACE PROCEDURE myproc(p1 IN clob, p2 OUT clob);

Here You are an answer:

<?php
        $conn
= oci_connect("TEST", "html", "//hostname", "UTF8");

   
$filename = "./clob.txt";
   
$handle = fopen($filename, "r");
   
$f = fread($handle, filesize($filename));
   
fclose($handle);

   
$stid = oci_parse($conn, "begin myproc(:p1, :p2); end;");
   
$p1 = oci_new_descriptor($conn, OCI_D_LOB);
   
$p2 = oci_new_descriptor($conn, OCI_D_LOB);
   
   
oci_bind_by_name($stid, ":p1", $p1, -1, OCI_B_CLOB);
   
oci_bind_by_name($stid, ":p2", $p2, -1, OCI_B_CLOB);
   
$p1->writeTemporary($f, OCI_TEMP_BLOB);
   
oci_execute($stid); -- Figure out OCI_NO_AUTO_COMMIT
    oci_commit
($conn);
    echo
$p2->load();
   
   
$p1    ->close();
   
$p2    ->close();
   
oci_free_statement($stid);
   
oci_close($conn);
?>

And perfect book about "PHP and Oracle"
http://www.oracle.com/technetwork/topics/php/underground-php-oracle-manual-098250.html
up
0
Anonymous
2 months ago
Bear in mind that you cannot use reserved words for bind variables. Otherwise you'll get ORA-01745: Invalid host/bind variable name error.
up
0
marki at trash-mail dot com
1 year ago
Please note that in my earlier note about having oci_bind_by_name() in a function, this becomes a little more complicated when returning values like "UPDATE table SET bla='blubb' RETURNING id INTO :id".

You can do it as follows:

<?php
function sql($q, &$vars_in=array(), &$vars_out=array()) {
  ...
 
$stid = oci_parse($conn, $q);
  ...
 
reset($vars_in);
  do {
    if (
current($vars_in)===FALSE) {
      break;
    }
   
$b = oci_bind_by_name($stid, key($vars_in), current($vars_in));
   
// insert exception handling here
 
} while (each($vars_in) !== FALSE);

 
// VARS TO RETURN
  // we'll fix this to integer type because for now we need this for index IDs
 
foreach ($vars_out as $k => $v) {
   
$b = oci_bind_by_name($stid, $k, $vars_out[$k], -1, SQLT_INT);
   
// insert exception handling here
 
}

  ...
}
?>

Use like this:

<?php
$blubb
= 'blubb';
$b = array(':bla' => $blubb);
$b_out = array(':id' => ''); // leave value empty
$x = sql($q, $b, $b_out);
$id = $b_out[':id'];
?>

(The point is: you would not be able to return anything into $b[':bla'] because $b[':bla'] becomes current($vars_in) inside sql() and cannot be written to.)
up
0
marki at trash-mail dot com
1 year ago
I had a query that was working properly at first sight, no errors on execute, nothing, but there were simply no results returned at runtime.

Be careful when putting the database commands into a function and binding your variables there while using oci_fetch_xxx() outside the function.

function sql($conn, $stmt, $var) {
  $stid = oci_parse($conn, $stmt);
  ...
  oci_bind_by_name($stid, ':val', $var);
  ...
}
sql($conn, $q, $var);
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);

As you see from the definition of oci_bind_by_name(), $var needs to be passed as reference, so your function has to have this reference ready like this:

function sql($conn, $stmt, &$var) {
  $stid = oci_parse($conn, $stmt);
  ...
  oci_bind_by_name($stid, ':val', $var);
  ...
}

The background is that if you don't pass by reference (in which case $var inside the function is a copy of $var outside the function), then oci_bind_by_name() will work just fine at first glance.
However, since the oci_fetch statements that you use to actually get the data will reference the $var that has ceased to exist when the function finished. In fact, since the varbind seems to be a pointer, that pointer will point to an invalid location at that point and your variables won't be substitued in the SQL.

All this also means that:

1) You have to pass a variable, and not just a value

This doesn't work:

$stid = sql($conn, $q, array('bla'=>'blubb'));

This is better:

$vars = array('bla'=>'blubb');
$stid = sql($conn, $q, $vars);

2) Even when passing as reference to your helper function you cannot use e.g. foreach:

This doesn't work:

function sql($conn, $q, $vars) {
  ...
  foreach ($vars as $k => $v) {
    oci_bind_by_name($stid, $k, $v);
  }
  ...
}

Again, because $k and $v are local variables that will have disappeared once you perform an oci_fetch outside the function.

Instead you have to work the array in a more low-level way like this:

function sql($conn, $q, &$vars) {
  ...
  $stid = oci_parse($conn, $q);
  ...
  reset($vars);
  do {
    if (current($vars)===FALSE) { // end of array
      break;
    }
    $b = oci_bind_by_name($stid, key($vars), current($vars));
    if ($b === FALSE) {
      DIE('Could not bind var');
    }
  } while (each($vars) !== FALSE);
}
$binds = array(':bla1' => 'blubb1',
               ':bla2' => 'blubb2');
$stid = sql($conn, $q, $binds);
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);

Wherever you oci_bind_by_name(), the pointer to the initial data has to exist from beginning to end.
up
0
xorinox at gmx dot ch
3 years 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
adrian dot crossley at hesa dot ac dot uk
8 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
0
avenger at php dot net
8 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
ajitsingh4u at gmail dot com
9 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
Chris Delcamp
10 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
-1
Anonymous
10 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
-1
hfuecks at nospam dot org
12 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