I am having difficulty figuring out how to add data as input to an Oracle cursor being sent to a stored procedure of a package in PHP.
I am trying to send 2 pieces of data through a cursor. I have verified the data is correct up to sending.
PHP Code:
$finalpieces = explode('|',$lkeyarr[$i]); //0=unique id, 1=table
$conn = oci_connect($oracleUsername,$oraclePassword,$oracleService);
$stmt = OCIParse($conn,"BEGIN PROD.PKG_CORE_OBSERVER.StuckPages_Unlock(:cur_PageDetails); END;");
$cur = oci_new_cursor($conn);
OCIBindByName($stmt,':cur_PageDetails',$cur,-1,OCI_B_CURSOR);
ociexecute($stmt,OCI_DEFAULT);
Stored Procedure Details:
PROCEDURE StuckPages_Unlock
(
cur_PageDetails IN OUT SYS_REFCURSOR
)
accepts ref cursor that includes 2 fields:
ProcessID NUMBER(2);
PageUniqueID NUMBER(10);
Any help would be greatly appreciated.
A Ref Cursor is a pointer to a result set. We cannot assign values to a Ref Cursor, we use it with a query:
open my_ref_cursor for
select process_id, page_unique_id
from some_table;
So, your approach is wrong. It is difficult to be sure what you're trying to achieve but I think what you want is a stored procedure which accepts two parameters that it uses to query a table and return a ref cursor. Perhaps, something like this:
PROCEDURE StuckPages_Unlock
(
p_proc_id in some_table.process_id%type
, p_page_id in some_table.page_unique_id_id%type
, cur_PageDetails OUT SYS_REFCURSOR
)
IS
open PageDetails for
select *
from some_table
where process_id = p_proc_id
and page_unique_id = p_page_id;
END;
Related
This question already has answers here:
PHP: Calling MySQL Stored Procedure with Both INPUT AND OUTPUT Parameters (NOT "INOUT")
(2 answers)
Closed 3 years ago.
To call a Stored procedure with an IN parameter is easy like
CREATE PROCEDURE `catalog_delete_product`(IN `inProductId` INT) BEGIN DELETE FROM product_attribute WHERE product_id = inProductId; DELETE FROM product_category WHERE product_id = inProductId; DELETE FROM shopping_cart WHERE product_id = inProductId; DELETE FROM product WHERE product_id = inProductId; END
You can see that it is as easy as that. But how do we call an OUT parameter in MySQL Stored parameter and use it in PHP?
As an example to illustrate it, I will a real world practical example(inserting data into an order table and returning the lastInsertId).
CREATE PROCEDURE `shopping_cart_create_order`(IN `inCartId` INT(11), OUT `newOrderId` INT(11)) BEGIN
DECLARE newOrder int;
-- Insert a new record into orders and obtain the new order ID
INSERT INTO orders (created_on) VALUES (NOW());
-- Obtain the new Order ID
SELECT LAST_INSERT_ID() INTO newOrder;
SET newOrder = newOrderId;
END
At PHP level// Probably at the Model/Entity level First, we need to execute the
shopping_cart_create_order()
stored procedure. Which might probably be in a function.
Second, to get the last order id, we need to query it from the variable
#oid
. It is important that we must call the method
closeCursor()
of the PDOStatement object in order to execute the next SQL statement.
function query($pdo, $sql, $parameters = []){
$query = $pdo->prepare($sql);
$query->execute($parameters);
return $query;
}
function create_order($pdo, $cart_id){
// Binding the parameters
$parameters = [':cart_id' => $cart_id];
// calling stored procedure command
$sql = 'CALL shopping_cart_create_order(:cart_id)';
// prepare for execution of the stored procedure, pass value to the command
and execute the Stored Procedure
$query = query($pdo, $sql, $parameters);
// Then close Cursor. It is important for you to close it.
$query->closeCursor();
// execute the second query to get last insert id
$row = $pdo->query("SELECT #oid AS oid")->fetch();
return $row;
}
I have a stored procedure that I am trying to call from my php. Here is the stored procedure:
BEGIN
DECLARE done INT DEFAULT FALSE;
declare phone_temp VARCHAR(20) default '';
declare phone_cur cursor for SELECT DISTINCT sentNum FROM Queue;
declare continue handler for not found set done = true;
#create temp table
create temporary table if not exists temp_return AS SELECT * FROM Queue LIMIT 0;
#empty if exists
delete from temp_return;
open phone_cur;
phone_loop: LOOP
fetch phone_cur into phone_temp;
if done then
leave phone_loop;
end if;
insert into temp_return SELECT * FROM Queue WHERE num2=phone_temp LIMIT 2;
insert into temp_return SELECT * FROM Queue WHERE num1=phone_temp LIMIT 1;
end loop phone_loop;
close phone_cur;
select * from temp_return;
drop table if exists temp_return;
END
Directly in mysql workbench, calling it works. In php, it does not work. Here is my php:
function grabFromSmsQueue(){
global $myStmt, $conn;
if(isset($myStmt)){
$myStmt -> execute();
}
else{
$query = "CALL myStoredProc();";
$myStmt = $conn->stmt_init();
$myStmt -> prepare($query);
$myStmt -> execute();
}
$result = $myStmt -> get_result();
//print_r ($result);
$info = [];
if(isset($result)){
while($data = $result->fetch_assoc()){
$info[] = $data;
}
}
return $info;
}
Connecting like this, I get the following error
The localhost page isn’t working
localhost didn’t send any data.
ERR_EMPTY_RESPONSE
I traced my problem back to an issue with $data = $result->fetch_assoc(), because when I comment that out and put in the print_r I get something actually returned, which is mysqli_result Object ( [current_field] => 0 [field_count] => 9 [lengths] => [num_rows] => 0 [type] => 1 ). I have drawn the conclusion that it is not working because [num_rows] => 0.
Now, going back to my stored procedure, I took out all mentions of a cursor and replaced it with a hard-coded value, and it worked in both workbench and php. I have already verified that the user connecting through php has permission, that the connection is open, and that the same code can execute other stored procedures (ones that do not include cursors). Does this mean that I can not use cursors in stored procedures that are being called by php? Are there alternatives to cursors? Am I missing something in my php syntax to deal with cursors?
Based on discussions in chat for 3 groupings, and this provided SQLFiddle for test data (not much data there).
Due to testing data with a sliding window of where now() is in relation to that data, the following variable was used to "freeze" now(). Simply to facilitate testing and verification of output.
So, ditch that ultimately and change the 4 references in the code that use it (note that Group 3 uses it twice).
The now() variable:
select #theNow:=now();
-- REM OUT the following line. It is used only for testing (as now will chg, your data won't)
select #theNow:='2016-06-23 14:00:00';
The Query:
select id,sentNum,message,sentTime,startAtTime,sentByTime,msgType,theGrp from
( select id,sentNum,message,sentTime,startAtTime,sentByTime,msgType,theGrp,
if(sentNum!=#lastSentNum,greatest(#sentNumChg:=1,0),least(#sentNumChg:=0,1)) as dummy1,
if(theGrp!=#lastGrp,greatest(#grpChg:=1,0),least(#grpChg:=0,1)) as dummy2,
if(#sentNumChg=1 or #grpChg=1,#seqNum:=1,#seqNum:=#seqNum+1) as seqNum,
#lastSentNum:=sentNum as setLast01,
#lastGrp:=theGrp as setLast02
from
( -- GROUP 1: sentByTime<=now(), INVITE
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 1 as theGrp
from SmsQueue
where sentByTime<=#theNow and msgType='invite'
UNION ALL
-- GROUP 2 startAtTime<=now(), BROADCAST
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 2 as theGrp
from SmsQueue
where startAtTime<=#theNow and msgType='broadcast'
UNION ALL
-- GROUP 3: sentByTime>now() && startAtTime<=now(), INVITE
select `id`, `sentNum`, `message`, `sentTime`, `startAtTime`, `sentByTime`, `msgType`, 3 as theGrp
from SmsQueue
where sentByTime>#theNow and startAtTime<=#theNow and msgType='invite'
) d1
cross join (select #sentNumChg:=0,#grpChg:=0,#lastSentNum:='',#lastGrp:=0,#seqNum:=0) as xParams
order by sentNum,theGrp,sentByTime,id -- id is the tie-break
) d2
where (theGrp=1 and seqNum<3) or (theGrp=2 and seqNum=1) or (theGrp=3 and seqNum=1)
order by sentNum,theGrp;
Output (my client tool is text challenged at the moment):
See my general comments at the top of this answer of mine for advanced variable usage.
Calling SELECT Statements with parameters is great and makes life coding so tidy. My problem comes to when I want to update data in the database using an UPDATE statement.
I have the Stored Proc with the UPDATE statement included, similar to this below
CREATE DEFINER = 'myuser'#'%'
PROCEDURE sp_upd_planning (
IN prop_id int(11),
IN planned_date varchar(15),
IN time_slot int(11),
IN by_who int(11),
IN cost decimal(15,2),
IN complete_date varchar(15),
IN lastupd_user varchar(100))
BEGIN
UPDATE planning
SET
Status = CASE
WHEN CompleteDate IS NOT NULL THEN 4
WHEN PlannedDate IS NULL THEN 2
WHEN PlannedDate IS NULL AND CompleteDate IS NULL THEN 3
END
,PlannedDate = planned_date
,BookingDate = NOW()
,TimeSlot = time_slot
,ByWho = by_who
,Cost = epc_cost
,Complete = CASE WHEN CompleteDate IS NOT NULL THEN 1 ELSE 0 END
,CompleteDate = complete_date
,LastUpdateDate = NOW()
,LastUpdateUser = lastupd_user
WHERE PropID = prop_id;
END
The statement works as should when I run the CALL sp_upd_planning(paramters here); within the database.
I'm using as a submit from a form, I've posted the relevant fields into variables and in my connection I call the Stored Proc again and as before in the database I use the variables to match the parameters needed like this (yes I know it's using mysql_ but I wanted to test quickly so I used this)
mysql_query("CALL sp_upd_planning('$planned', '$timeslot', '$bywho', '$cost', '$completed', '$inputby', $propid)") or die(mysql_error());
When the code executes all looks good and no errors and the main form submits as should with the jquery I set up, but when I check the database nothing is updated.
Why would this be?
It sounds like you aren't executing your statement. In PHP you still have to execute the statement after creation. Also if I remember correctly it is more secure to bind your parameters instead of pass them in the string. Try something like this:
$conn = new mysqli("mysql:host=$host;dbname=$dbname", $username, $password);
// execute the stored procedure
$sql = "CALL sp_upd_planning(:planned, :timeslot, :bywho, :cost, :completed, :inputby, :propid)";
$stmt = $conn->prepare($sql);
$stmt->bindParam('datatypes', $planned, $timeslot, $bywho, $cost, $completed, $inputby, $propid);
$stmt->execute();
Basically by the term datatypes lets assume the planned is a string, timeslot is a date/time, bywho is a string, cost is an int, completed is an int, inputby is a string, and propid is an int then it would say 'sdsiisi'
I am new to stored procedures, and i am having an issue with the results returned by the stored procedure not having any values when i call the stored procedure via PHP. When i manually make the call directly on the MySQL server it works fine and returns 5 values. When i call the procedure through php no values are stored in the binding variables.
Stored Procedure:
DELIMITER $$
CREATE PROCEDURE `TPE_GET_current_repair` (IN current_repair_vid VARCHAR(45))
BEGIN
SELECT current_repair_vid v1;
SELECT
sys_vendor.vendor,
receive_date,
tape_repair_problem_code.tape_repair_problem_reason,
sys_tape_type.tape_type,
sys_capture_location.capture_location
FROM tape_repair
INNER JOIN `sys_vendor` on tape_repair.vendor_id = sys_vendor.id
INNER JOIN `tape_repair_problem_code` on tape_repair.problem_code = tape_repair_problem_code.id
INNER JOIN `sys_tape_type` on tape_repair.tape_type_id = sys_tape_type.id
INNER JOIN `sys_capture_location` on tape_repair.capture_location_id = sys_capture_location.id
WHERE vid = current_repair_vid;
END
PHP:
$repairData = "CALL TPE_GET_current_repair('$vid')";
if ($stmt = $mysqli->prepare($repairData)) {
$stmt->execute();
$stmt->bind_result($rpr_vendor, $rpr_rcv_date, $rpr_problem, $rpr_tape_type, $rpr_capt_loctn);
$stmt->fetch();
}
I fixed the issue, i had forgotten about the first select statement and it was causing the statement to fail.
I've been trying to find an answer to this question, but haven't found any definitive "yes" or "no" in all my research.
I'm running a simple MySQL query like this:
UPDATE item SET `score`=`score`+1 WHERE `id`=1
Is there a way for that query to return the updated value, instead of the number of rows affected? Just as a reference, I'm doing this in PHP, so the actual code looks like:
$sql = "UPDATE item SET `score`=`score`+1 WHERE `id`=1";
$new_value = mysql_query($sql);
//Unfortunately this does not return the new value
I know I could do a second query and just SELECT the value, but I'm trying to cut down on queries as much as possible. Is there a way?
You can do it with a stored procedure that updates, and then selects the new value into an output parameter.
The following returns one column new_score with the new value.
DELIMITER $$ -- Change DELIMITER in order to use ; withn the procedure
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
UPDATE item SET score = score + 1 WHERE id = id_in;
SELECT score AS new_score FROM item WHERE id = id_in;
END
$$ -- Finish CREATE PROCEDURE statement
DELIMITER ; -- Reset DELIMITER to standard ;
In PHP:
$result = mysql_query("CALL increment_score($id)");
$row = mysql_fetch_array($result);
echo $row['new_score'];
No, there's nothing like postgresql's UPDATE ... RETURNING output_expression in MySQL (yet?).
If you don't want to run another Query SELECT then here is another way to do it. I have modified Mr. Berkowski code for reference:
DELIMITER $$
CREATE PROCEDURE increment_score
(
IN id_in INT
)
BEGIN
set #newScore := null;
UPDATE item SET score = IF((#newScore := score+1) <> NULL IS NULL, #newScore, NULL) WHERE id = id_in;
SELECT #newScore;
END
DELIMITER ;
No you cant. You could make a function or stored procedure that could do the insert and return the updated value but that would still require you to execute two queries from within the function or stored procedure.
You can create a trigger, and you will know everything about the modifications.