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
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
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
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");
}
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
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;