How can i get the result from oci_execute()? - php

It gives true but when I use oci_fetch($stmt) it shows error.
oci_fetch(): ORA-24374: define not done before fetch or execute and
fetch
$sql = "DECLARE
C1 KTI_OPPL_DB.MH_ONLINE_PACKAGE_DB.TABLE_OF_LOV;
BEGIN
KTI_OPPL_DB.MH_ONLINE_PACKAGE_DB.GET_VESSEL_TYPE_LOV(C1);
END;";
$stmt = oci_parse($conn, $sql);
$r = oci_execute($stmt);
while (oci_fetch($stmt)) {
$nrows = oci_num_rows($stmt);
}

As I was telling you in the comment section, oci_fetch will not provide any result because the statement you are executing is not a sql statement, but a pl/sql procedure.
How to use OCI_FETCH
Fetches the next row from a query into internal buffers accessible either with oci_result(), or by using variables previously defined with oci_define_by_name().
An example using oci_result
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$sql = 'SELECT location_id, city FROM locations WHERE location_id < 1200';
$stid = oci_parse($conn, $sql);
oci_execute($stid);
while (oci_fetch($stid)) {
echo oci_result($stid, 'LOCATION_ID') . " is ";
echo oci_result($stid, 'CITY') . "<br>\n";
}
// Displays:
// 1000 is Roma
// 1100 is Venice
oci_free_statement($stid);
oci_close($conn);
?>
An example with oci_define_by_name
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$sql = 'SELECT location_id, city FROM locations WHERE location_id < 1200';
$stid = oci_parse($conn, $sql);
// The defines MUST be done before executing
oci_define_by_name($stid, 'LOCATION_ID', $locid);
oci_define_by_name($stid, 'CITY', $city);
oci_execute($stid);
// Each fetch populates the previously defined variables with the next row's data
while (oci_fetch($stid)) {
echo "Location id $locid is $city<br>\n";
}
// Displays:
// Location id 1000 is Roma
// Location id 1100 is Venice
oci_free_statement($stid);
oci_close($conn);
?>
In your case, you are executing a PROCEDURE which is providing as output a user defined type. In this case you might try oci_fetch_array to get the result of the procedure passed as an array of three values ( which is what you get from your output ). PHP and Oracle user defined types are tricky, so I'd try this ( Adapt to your code ):
<?php
$stid = oci_parse($conn, 'BEGIN yourprocedure(:rc); END;');
$refcur = oci_new_cursor($conn);
oci_bind_by_name($stid, ':rc', $refcur, -1, OCI_B_CURSOR);
oci_execute($stid);
// Execute the returned REF CURSOR and fetch from it like a statement identifier
oci_execute($refcur);
echo "<table border='1'>\n";
while (($row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS)) != false) {
echo "<tr>\n";
foreach ($row as $item) {
echo " <td>".($item !== null ? htmlentities($item, ENT_QUOTES) : " ")."</td>\n";
}
echo "</tr>\n";
}
echo "</table>\n";
oci_free_statement($refcur);
oci_free_statement($stid);
oci_close($conn);
?>

Without knowing the exact PL/SQL to create your type, we can only guess what TABLE_OF_LOV is. Here is an example that shows getting records from a TABLE OF VARCHAR2, which seems a feasible guess.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 'On');
$c = oci_connect("hr", "welcome", "localhost/XE");
if (!$c) {
$m = oci_error();
trigger_error('Could not connect to database: '. $m['message'], E_USER_ERROR);
}
//
// Create a PL/SQL package that has a 'TABLE OF' OUT parameter
//
$create_pkg = "
CREATE OR REPLACE PACKAGE mypackage AS
TYPE TABLE_OF_LOV IS TABLE OF VARCHAR(20) INDEX BY BINARY_INTEGER;
PROCEDURE GET_VESSEL_TYPE_LOV(p1 OUT TABLE_OF_LOV);
END mypackage;";
$s = oci_parse($c, $create_pkg);
if (!$s) {
$m = oci_error($c);
trigger_error('Could not parse statement: '. $m['message'], E_USER_ERROR);
}
$r = oci_execute($s);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not execute statement: '. $m['message'], E_USER_ERROR);
}
$create_pkg_body = "
CREATE OR REPLACE PACKAGE BODY mypackage AS
PROCEDURE GET_VESSEL_TYPE_LOV(p1 OUT TABLE_OF_LOV) IS
BEGIN
p1(1) := 'one';
p1(2) := 'two';
p1(3) := '';
p1(4) := 'four';
p1(5) := 'five';
END GET_VESSEL_TYPE_LOV;
END mypackage;";
$s = oci_parse($c, $create_pkg_body);
if (!$s) {
$m = oci_error($c);
trigger_error('Could not parse statement: '. $m['message'], E_USER_ERROR);
}
$r = oci_execute($s);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not execute statement: '. $m['message'], E_USER_ERROR);
}
//
// Call the PL/SQL procedure
//
$s = oci_parse($c, "BEGIN mypackage.get_vessel_type_lov(:bv); END;");
if (!$s) {
$m = oci_error($c);
trigger_error('Could not parse statement: '. $m['message'], E_USER_ERROR);
}
$r = oci_bind_array_by_name($s, ":bv", $array, 5, 20, SQLT_CHR);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not bind a parameter: '. $m['message'], E_USER_ERROR);
}
$r = oci_execute($s);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not execute statement: '. $m['message'], E_USER_ERROR);
}
var_dump($array);
?>
Output is:
$ php so3.php
array(5) {
[0]=>
string(3) "one"
[1]=>
string(3) "two"
[2]=>
string(0) ""
[3]=>
string(4) "four"
[4]=>
string(4) "five"
}
You may find other solutions such as writing 'PL/SQL wrappers' in the USING PL/SQL WITH OCI8 chapter on p187 of the free book The Underground PHP and Oracle Manual.

Related

PHPUnit OOP Declaration

I'm trying to understand OOP and inheritance for the code i'm cleaning up.
I have a config file
Config.php
<?php
$odb_host = "localhost";
$odb_name = "Prod";
$odb_user = "admin";
$odb_pass = "password";
?>
Main.php
class upSellCore{
public function ociConnect($odb_user,$odb_pass,$odb_host,$odb_name)
{
$db = "(DESCRIPTION=(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ".$odb_host.")(PORT = 1521 )))(CONNECT_DATA=(SID=".$odb_name.")))";
$conn = oci_connect($odb_user, $odb_pass, $db);
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
else
{
print "ERR01"; // For PHPUnit assertTrue
}
}
}
$sql = "Select * from users ";
$upSell = new upSellCore();
$upSell->ociConnect($odb_user,$odb_pass,$odb_host,$odb_name);
$stid = oci_parse($upSell,$sql); // Line having issue
Since I've already initialize to call OciConnect but when i try to pass over the object to trigger oci_parse
I'm getting the following error :-
PHP Warning: oci_parse() expects parameter 1 to be resource, object given in /I/main.php on line 46
The $conn itself is an object from Oracle class but when i overwrite my object $upSell i can't seem to parse the connection into oci_parse.
Taken from PHPManual for end-to-end without using OOP
<?php
$conn = oci_connect('hr', 'welcome', 'localhost/XE', 'AL32UTF8');
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$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";
?>
You should not be passing the class into the oci_parse function. It is expecting a connection resource. You can get the resource by calling oci_connect. In your class, your function is already doing that, therefore you can return that in the function. See below.
class upSellCore
{
public function ociConnect($odb_user,$odb_pass,$odb_host,$odb_name)
{
$db = "(DESCRIPTION=(ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ".$odb_host.")(PORT = 1521 )))(CONNECT_DATA=(SID=".$odb_name.")))";
$conn = oci_connect($odb_user, $odb_pass, $db);
if (!$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
} else {
print "ERR01";
}
return $conn; // you need to return the connection.
}
}
$sql = "Select * from users ";
$upSell = new upSellCore();
$conn = $upSell->ociConnect($odb_user,$odb_pass,$odb_host,$odb_name); // you get the returned connection here and use it in the following line.
$stid = oci_parse($conn, $sql); // this is expecting a resource

ORA-00932 inconsistent datatypes: expected DATE got NUMBER

I am trying to input a date value from the user and then using that value in the query.
My date value is like this 2017.07.21 08:59:26
$MYDATE= $data[$i]->MYDATE;
//ALSO I ADDED
$str = oci_parse($conn, "ALTER SESSION SET NLS_DATE_FORMAT = 'DD.MM.YYYY HH24:MI:SS'");
oci_execute($str);
//
$sql = 'INSERT INTO MYTABLE(ID,MYDATE)'.'VALUES(:ID,to_date(:MYDATE,\'YYYY.MM.DD HH24:MI:SS\'))';
$compiled = oci_parse($conn, $sql);
oci_bind_by_name($compiled, ':ID', $ID);
oci_bind_by_name($compiled, ':MYDATE', $MYDATE);
oci_execute($compiled);
It gave me this error:
inconsistent datatypes: expected DATE got NUMBER
This script:
<?php
/*
drop table mytable purge;
create table mytable (id number, mydate date);
*/
error_reporting(E_ALL);
ini_set('display_errors', 'On');
$c = oci_connect("hr", "welcome", "localhost/XE");
if (!$c) {
$m = oci_error();
trigger_error('Could not connect to database: '. $m['message'], E_USER_ERROR);
}
$sql = <<<'END'
INSERT INTO MYTABLE(ID,MYDATE) VALUES(:ID,to_date(:MYDATE,'YYYY.MM.DD HH24:MI:SS'))
END;
$id = 1;
//$mydate = '2017.07.21 08:59:26'; // also works
$mydate = date("Y.m.d H:i:s");
echo "input value: ", $mydate, "\n\n";
$s = oci_parse($c, $sql);
if (!$s) {
$m = oci_error($c);
trigger_error('Could not parse statement: '. $m['message'], E_USER_ERROR);
}
$r = oci_bind_by_name($s, ':id', $id);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not bind a parameter: '. $m['message'], E_USER_ERROR);
}
$r = oci_bind_by_name($s, ':mydate', $mydate);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not bind a parameter: '. $m['message'], E_USER_ERROR);
}
$r = oci_execute($s, OCI_NO_AUTO_COMMIT);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not execute statement: '. $m['message'], E_USER_ERROR);
}
// Fetch back the data
$s = oci_parse($c, "select to_char(mydate, 'YYYY.MM.DD HH24:MI:SS') as mydate from mytable");
if (!$s) {
$m = oci_error($c);
trigger_error('Could not parse statement: '. $m['message'], E_USER_ERROR);
}
$r = oci_execute($s, OCI_NO_AUTO_COMMIT);
if (!$r) {
$m = oci_error($s);
trigger_error('Could not execute statement: '. $m['message'], E_USER_ERROR);
}
oci_fetch_all($s, $r);
var_dump($r);
oci_rollback($c);
?>
gives this output:
input value: 2021.04.06 10:50:20
array(1) {
["MYDATE"]=>
array(1) {
[0]=>
string(19) "2021.04.06 10:50:20"
}
}
Things you can do:
do a var_dump() on your input date, to show its type
do a DESC on the table to show your datatype
I believe you'd added it for testing, but in production you would want to avoid running ALTER SESSION for each connection, since this adds overhead. Instead use the TO_DATE, or set the environment variables NLS_DATE_FORMAT and NLS_LANG (both are needed) before PHP starts. See the Globalization chapter in The Underground PHP and Oracle Manual

Error while using PHP to call Oracle Stored Procedure

i am new to PHP, and am testing a simple PHP to call a Stored Procedure. I can connect to the Oracle database, but when i try to call oci_execute($stmt),
it will always failed. There is no issue with the stored procedure as it is being used by my other java program. Please advise what is the problem.
Thank.
$db="(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=DEVORA)(PORT=1590)))(CONNECT_DATA=(SID=xxxORxxx)))";
$conn = oci_connect("xxxx","xxxx",$db);
if (!$conn) {
$m = oci_error();
echo $m['message'], "\n";
exit;
}
else {
print "Connected to Oracle!\n";
}
$sql = 'BEGIN tcwzusr.getuserapp(:output_cur, :userid, :effdate); END;';
$stmt = oci_parse($conn,$sql);
$userid='myid01';
$effdate='01-12-2017';
oci_bind_by_name($stmt,':userid' ,$userid);
oci_bind_by_name($stmt,':effdate' ,$effdate);
$output_cur = oci_new_cursor($conn);
oci_bind_by_name($stmt,':output_cur', $output_cur,-1, OCI_B_CURSOR);
oci_execute($stmt);
if ( !$status ) {
// Rollback the procedure
print "rollback\n";
oci_rollback($conn);
die ("$status_msg\n");
}

How can I put all PHP Oracle error functions in one function?

i try to build one function hold all errors
here is my example:
<?php
$stid = oci_parse($conn, "select does_not_exist from dual");
$r = oci_execute($stid);
if (!$r) {
$e = oci_error($stid); // For oci_execute errors pass the statement handle
print htmlentities($e['message']);
print "\n<pre>\n";
print htmlentities($e['sqltext']);
printf("\n%".($e['offset']+1)."s", "^");
print "\n</pre>\n";
}
?>
i will lost my time if i repeat same codes with any sql query so i want make function check for error like this way
function error($r, $stid){
if(!$r){
$error = oci_error($stid);
$code = "Code"." ".$error["code"];
$sql = "Sql Statment"." ".$error["sqltext"];
$Position = "Position"." ".$error["offset"];
$message = "Message"." ".$error["message"];
$all = array("code"=>$code, "sql"=>$sql, "Position"=>$Position, "message"=>$message);
return($all);
}
}
I WANT TO BT LIKE THIS
$stid = oci_parse($conn, "select does_not_exist from dual");
$r = oci_execute($stid);
$error = error($r, $stid);
echo $error["message"];
echo $error["sql"];
echo $error["code"];
echo $error["Position"];
but it dose not work _ please help to do it
oci_error() should be run on the connection, it's not clear from your variable names what parse is. It seems like this could be problematic.
http://php.net/oci_error

Can I return values to PHP from an anonymous PL/SQL block?

I'm using PHP and OCI8 to execute anonymous Oracle PL/SQL blocks of code. Is there any way for me to bind a variable and get its output upon completion of the block, just as I can when I call stored procedures in a similar way?
$SQL = "declare
something varchar2 := 'I want this returned';
begin
--How can I return the value of 'something' into a bound PHP variable?
end;";
You define an out parameter by using the keyword OUT between the name and data type declaration. IE:
CREATE OR REPLACE PROCEDURE blah (OUT_PARAM_EXAMPLE OUT VARCHAR2) IS ...
If not specified, IN is the default. If you want to use a parameter as both in and out, use:
CREATE OR REPLACE PROCEDURE blah (INOUT_PARAM_EXAMPLE IN OUT VARCHAR2) IS ...
The following example creates a procedure with IN and OUT parameters. The procedure is then executed and the results printed out.
<?php
// Connect to database...
$c = oci_connect("hr", "hr_password", "localhost/XE");
if (!$c) {
echo "Unable to connect: " . var_dump( oci_error() );
die();
}
// Create database procedure...
$s = oci_parse($c, "create procedure proc1(p1 IN number, p2 OUT number) as " .
"begin" .
" p2 := p1 + 10;" .
"end;");
oci_execute($s, OCI_DEFAULT);
// Call database procedure...
$in_var = 10;
$s = oci_parse($c, "begin proc1(:bind1, :bind2); end;");
oci_bind_by_name($s, ":bind1", $in_var);
oci_bind_by_name($s, ":bind2", $out_var, 32); // 32 is the return length
oci_execute($s, OCI_DEFAULT);
echo "Procedure returned value: " . $out_var;
// Logoff from Oracle...
oci_free_statement($s);
oci_close($c);
?>
Reference:
How does one call stored procedures from PHP?
Here my decision:
function execute_procedure($procedure_name, array $params = array(), &$return_value = ''){
$sql = "
DECLARE
ERROR_CODE VARCHAR2(2000);
ERROR_MSG VARCHAR2(2000);
RETURN_VALUE VARCHAR2(2000);
BEGIN ";
$c = $this->get_connection();
$prms = array();
foreach($params AS $key => $value) $prms[] = ":$key";
$prms = implode(", ", $prms);
$sql .= ":RETURN_VALUE := ".$procedure_name."($prms);";
$sql .= " END;";
$s = oci_parse($c, $sql);
foreach($params AS $key => $value)
{
$type = SQLT_CHR;
if(is_array($value))
{
if(!isset($value['value'])) continue;
if(!empty($value['type'])) $type = $value['type'];
$value = $value['value'];
}
oci_bind_by_name($s, ":$key", $value, -1, $type);
}
oci_bind_by_name($s, ":RETURN_VALUE", $return_value, 2000);
try{
oci_execute($s);
if(!empty($ERROR_MSG))
{
$data['success'] = FALSE;
$this->errors = "Ошибка: $ERROR_CODE $ERROR_MSG";
}
return TRUE;
}
catch(ErrorException $e)
{
$this->errors = $e->getMessage();
return FALSE;
}
}
example:
execute_procedure('My_procedure', array('code' => 5454215), $return_value);
echo $return_value;

Categories