MySQL stored procedure caused `Commands out of sync` - php

Call procedure works all right in MySQL terminal, but in PHP, caused Commands out of sync; you can't run this command nowCommands out of sync; you can't run this command now
My procedure is
delimiter $$
create procedure getMostSimilar (IN vU_ID INT, IN voffset INT, IN vsize INT)
BEGIN
set #offset = voffset;
set #size = vsize;
set #uid = vU_ID;
prepare SimilarStmt from
"SELECT U_ID, getSimilarity(U_ID, ?) AS similar FROM Answer WHERE U_ID != ? GROUP BY U_ID ORDER BY similar DESC LIMIT ?, ?";
execute SimilarStmt using #uid, #uid, #offset, #size;
deallocate prepare SimilarStmt;
END
$$
where getSimilarity is a function.
In PHP:
function getMostSimilar($U_ID, $offset, $size){
$query = sprintf("CALL getMostSimilar(%s, %s, %s)",
$U_ID, $offset, $size);
$result = mysql_query($query);
print mysql_error();
if (!$result){
return $query;
}
$ans = array();
$len = 0;
while($row = mysql_fetch_assoc($result)){
$ans[$len] = $row;
$len++;
}
return $ans;
}
What should I do now? Thanks!

There seems to be a nasty bug (or feature) that is manifested when calling a stored procedure that returns a result set.. I.e. a stored procedure that ends with a select statement without an INTO clause (see example below).
The mysqli driver (probably) returns 2 result sets. The first is the one returned from the stored procedure and the second a dummy, empty result set. It is like a multiple query command was issued. One solution to this (that does not break on usual (e.g. SELECT) queries), is to consume this dummy result set after processing the legit one (the first).
Example PHP code
function do_query($con, $sql)
{
$result = mysqli_query($con, $sql);
if ($result === true) {
return true;
}
while ($row = mysqli_fetch_assoc($result)) {
// process rows
}
// Hack for procedures returning second dummy result set
while (mysqli_more_results($con)) {
mysqli_next_result($con);
// echo "* DUMMY RS \n";
}
}
Example stored procedure:
CREATE PROCEDURE selectStaleHeaders()
NOT DETERMINISTIC
SELECT TT.*
FROM one_pretty_table AS TT
LEFT JOIN another AS AN on TT.fk_id = AN.id
WHERE TT.id IS NULL;

C.5.2.14. Commands out of sync If you
get Commands out of sync; you can't
run this command now in your client
code, you are calling client functions
in the wrong order.
This can happen, for example, if you
are using mysql_use_result() and try
to execute a new query before you have
called mysql_free_result(). It can
also happen if you try to execute two
queries that return data without
calling mysql_use_result() or
mysql_store_result() in between.
http://dev.mysql.com/doc/refman/5.0/en/commands-out-of-sync.html
I think you need to rewrite the getMostSimilar stored procedure, instead of using prepare and execute (which I thinks is fooling mysql) if you use the parameters in the procedure like in this example I think your error will be fixed.

This "bug" was happening to me with extremely simple procedure even inside phpmyadmin. The reason was that I was declaring general variables (without the # prefix). I changed my variables to user-defined variables prefixed with # and it was solved.

i know it is late and there is already an answer, but i was getting the same message for a whole different reason, so i will leave my solution here:
it was actually a very silly error. It was just a typo in a parameter name.
My function had a parameter named preferable:
create function call_client (pereferable int, client_id int) returns int
in the function body, i was using the parameter preferable with the wrong name:
if prefered = 1 then
...
end if;
once i changed prefered for preferable it started working again.

Related

Calling a procedure returns "success" but nothing has changed in base

I'm trying to call a stored procedure from a php page, but I'm not getting the result I want.
I'm using oci with php, the query execution looks like this:
function executeQuery($c, $query){
$stid = oci_parse($c, $query);
if (!$stid) {
$e = oci_error($c);
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
$response['success'] = oci_execute($stid);
if (!$response['success']) {
$e = oci_error($stid);
$response['error'] = $e;
return $response;
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR);
}
//oci_commit($c); //auto commit is by default with oci_execute but I've tried this too.
oci_free_statement($stid);
}
If my $query is an insert, it work fine and commits the insert, but when it's CALL MY_PROC('VAR1, 'VAR2', VAR3'), $response['success'] is true but nothing has changed on the database.
And if I execute CALL MY_PROC('VAR1', 'VAR2', VAR3') in TOAD's editor and commit, it works as expected I can see the results on the database. But not when I call my procedure from php.
I've tried using EXECUTE instead of CALL, adding COMMIT; at the end of the query, and oci_commit($c) it still not impacts the database.
What am I doing wrong? Is this likely to be a commit problem?
What can I do to get errors instead of a "success"?
Do procedures calls behave differently than inserts and selects, maybe?
The stored procedures calls a package that I didn't write myself and has out parameters, could that be why I'm not getting errors? (Again when I run it in toad with the same values it works fine, and show no error in particular).
My procedure looks like this:
CREATE OR REPLACE MY_PROC(
VAR1 IN VARCHAR2,
VAR2 IN VARCHAR2,
VAR3 IN VARCHAR2
)
IS
BEGIN
ERROR_CODE := NULL; --//inherited from the packages, don't really know what do do with them
ERROR_MSG := NULL;
IF VAR2 = NULL THEN
VAR2 := 'DEFAULT';
END IF;
PKG_USER.CREATE_USER(VAR1, VAR2, VAR3, ERROR_CODE, ERROR_MSG);
IF (ERROR_CODE != NULL OR ERROR_MSG != NULL) THEN
DBMS_OUTPUT.PUT_LINE('ERROR_CODE : ' || ERROR_CODE);
DBMS_OUTPUT.PUT_LINE('ERROR_MSG: ' || ERROR_MSG);
RAISE PROGRAM_ERROR; --//tried doing this to catch the errors but doesn't work
END IF;
END;
/
I guess part of the problem is with those error out parameters, but again it works fine with no error when I run in it TOAD.
EDIT: I just realised that if I try to call a procedure that doesn't exist, like CALL MYY_PROC() it still doesn't return an error, and returns "success".
Another thing to note is that I'm calling a number procedures on different databases. On all the other bases but this one, I get errors normally and calling a proc that doesn't exists rightfully returns:
ORA-06576: not a valid function or procedure name
So IMO it can either be 2 things: copy-paste mistakes (that I'm checking right now) or some database settings like #cdb_dba mentioned.
Btw the platform I'm developing this for uses php4. Obviously not my choice, don't ask.
Well I feel stupid but as it turns out, if your $query variable is null, oci_execute will always return success.
My variable wasn't called $query: I had set (and echoed for confirmation) $queryProcFTTx, but I executed $queryProcFttx. I was tricked by VSCode that highlighted both when I double-clicked the variable, ignoring case.

Laravel never ending EXEC

I'm rewriting a program from pure PHP to Laravel and I have a problem with executing a stored procedure (I didn't write it).
When I try
$sheetLines = DB::select("exec XXXXXXX".dbo.PRICELIST '?'", [$id]);
It keeps on going while PHP hasn't reached max memory. (increasing memory only makes it run longer)
Meanwhile in the old program it takes about 3 seconds and sends the response.
$tsql = "exec XXXXXXX.".dbo.PRICELIST '".$id."'";
Also when I'm calling other stored procedures from other modules everything works fine.
I have noticed that something like this also happens if I try for example:
DB::select(count(price) from orders group by price);
// would work with: count(price) as price_count
I have searched this problem a lot but have found no solution.
I'll be thankful for any help
I would access the underlying PDO driver to execute the stored procedure.
Try
$db = DB::getPdo();
$stmt = $db->prepare("EXEC XXXXXXX.dbo.PRICELIST :id");
$stmt->bindValue(':id', $id);
$result = $stmt->execute();
If that fails to work you could try the query method;
$query = DB::getPdo()->query("EXEC XXXXXXX.dbo.PRICELIST $id");
Regarding your count issue, in Laravel's Eloquent you can do the following;
$count = DB::table('orders')->groupBy('price')->count('price');
I've little experience with PHP, but seen:
set nocount on
Cause oddball behavior in some MSSQL drivers. Especially a stored procedure returns a single recordset, but doesn't output a "(x row(s) affected)" type messages. (Messages can be seen when manually executing a query in SQL Server Management Studio.)
My rule of thumb for complex stored procedure is to add...
set nocount on
...at the start of a stored procedure and conclude with...
set nocount off
....just before the final output.
Example:
create proc spTester
as
begin
set nocount off
-- {... do lots of crazy processing ...}
-- ok, ready to return the final output
set nocount off
select 1 as colA, 2 as colB
end

PHP mysqli prepared statement for stored procedure with out parameter

I have a stored procedure IsUserPresent like:
DELIMITER $$
CREATE PROCEDURE IsUserPresent(
in userid varchar (150),
out isPresent bit
)
BEGIN
SET isPresent=0;
SELECT COUNT(*)
INTO isPresent
FROM users_table
WHERE users_table.userid=userid;
END$$
and I want to call it from PHP using mysqli prepared statement. I am doing it following code snippet but it gives me warning.
$connect=&ConnectDB();
$stmt=$connect->prepare("CALL IsUserPresent(?,?)");
$stmt->bind_param('si',$uid,$userCount);
$stmt->execute();
$toRet = $userCount!=0;
Disconnect($connect);
return $toRet;
Warnings are as follow:
Premature end of data (mysqlnd_wireprotocol.c:1112)
Warning: mysqli_stmt::execute(): RSET_HEADER packet 1 bytes shorter than expected
Warning: mysqli_stmt::execute(): Error reading result set's header
The way stored procedures work with prepared statements is a bit more complicated. PHP manual states that you've got to use session variables (MySQL sessions, not PHP)
INOUT/OUT parameter
The values of INOUT/OUT parameters are accessed using session variables.
So you could do it with
$connect=&ConnectDB();
// bind the first parameter to the session variable #uid
$stmt = $connect->prepare('SET #uid := ?');
$stmt->bind_param('s', $uid);
$stmt->execute();
// bind the second parameter to the session variable #userCount
$stmt = $connect->prepare('SET #userCount := ?');
$stmt->bind_param('i', $userCount);
$stmt->execute();
// execute the stored Procedure
$result = $connect->query('call IsUserPresent(#uid, #userCount)');
// getting the value of the OUT parameter
$r = $connect->query('SELECT #userCount as userCount');
$row = $r->fetch_assoc();
$toRet = ($row['userCount'] != 0);
Remark:
I recommend to rewrite this procedure as a function with one IN parameter that returns INT.
Should be a comment, but due to code formatting posting as answer.
Can't comment on the PHP code, I'm no programmer, but your procedure should be more like this:
DELIMITER $$
CREATE PROCEDURE IsUserPresent(
in p_userId varchar (150),
out p_isPresent bit
)
BEGIN
SELECT EXISTS (SELECT 1 FROM users_table WHERE user_table.userid = p_userId)
INTO p_isPresent;
END$$
Use exists(), since it stops as soon as an entry is found. count() continues to look for records, although this isn't necessary.
And you named a parameter the same as your column name. This is confusing for MySQL and should be avoided at all costs. Good practice is, to prefix parameters with p_ and variables with v_ and/or some indications of what type the variable or parameter is.
For better readability I also changed the paramter names to camel case.
Oh, and finally always include error messages in questions.

Retrieve data returned by a Stored Procedure: Php & MS SQL SERVER

This question relates to:
PHP Version 5.3.6
Microsoft Drivers for PHP for SQL Server
I am trying to properly retrieve data from a stored procedure.
This question assumes the existence of the following stored procedure:
CREATE PROCEDURE test_procedure
AS
BEGIN
SET NOCOUNT ON
--A bunch of SQL statements
--More SQL statements
SELECT 'Doctor Who Rules!'
END
I've tried the following code which runs through all of my commands but does not return the data from the final SELECT.
$sql = "EXEC test_procedure;";
$result = sqlsrv_query($conn,$sql);
$next_result = sqlsrv_next_result($result); // returns a boolean
$row = sqlsrv_fetch_array($result);
Using sqlsrv_execute does not work with the above code either.
How can I return the data geneated by the stored procedure above via PHP?
Thank you.
Addendum #1 (Classic ASP Counterpart)
sqlCMD = "EXEC test_procedure;"
Set conn = Server.CreateObject("ADODB.Connection")
conn.Open _ConnectionString_Variable_
Set rs = conn.Execute(sqlCMD)
I would get back a recordset with one row that has one field with the data "Doctor Who Rules!"
I just hit the same problem a few minutes ago, and this thread pointed me towards a working solution (I'm not sure that it is a "right"solution, but it works).
Actually, the problem was not being caused by "SET NOCOUNT ON". In my case, it was a couple of PRINT statements that were left there after debugging.
Looks like any output from the SP other than the actual recordset, causes the problem.
I figured out the problem.
The PHP code in my example will work properly if SET NOCOUNT ON is ommited from the Stored Procedure. With SET NOCOUNT ON in the procedure, there is no data stream back to PHP and thus, the results of the last SELECT never makes it back.
Therfore, this Stored procedure...
CREATE PROCEDURE test_procedure
#foo varchar(25)
AS
BEGIN
--A bunch of SQL statements
--More SQL statements
SELECT #foo
END
...will work perfectly with this PHP...
$sql = "EXEC test_procedure 'Dr. Who Rules!';";
$result = sqlsrv_query($conn,$sql);
$next_result = sqlsrv_next_result($result);
$row = sqlsrv_fetch_array($result);
You will end up with a recordset with the string "Doctor Who Rules!"

Problem in retrieving the out parameter of a mysql stored procedure through php script

Hi I have a simple MYSQL stored procedure which has an IN (int) and an OUT (int) parameters.
I am calling the stored procedure from a PHP script.
Stored Procedure code:
DELIMITER $$
USE `testing`$$
DROP PROCEDURE IF EXISTS `test_sp_inout_params`$$
CREATE DEFINER=`root`#`localhost` PROCEDURE `test_sp_inout_params`(IN username VARCHAR(30), OUT user_id INT)
BEGIN
INSERT INTO users (`name`) VALUES (username);
SET user_id = LAST_INSERT_ID();
END$$
DELIMITER ;
I am able to run the stored procedure from mysql query window with:
CALL test_sp_inout_params('TestName', #user_id);
SELECT #user_id
But from PHP script I am geting errors.. :(
mysqli_query($conn, "CALL test_sp_inout_params('surya', #user_id)");
$rs = mysqli_query($conn, "SELECT #user_id");
$row = mysqli_fetch_assoc($rs);
var_dump($row);
[EDITED]
The above PHP script executed perfectly, when it is running individually.
But I have another stored procedure.. and when I am calling that before the above php-script, I am geting that sort of warning message.
So, the script I am using is (before the above mentioned php script):
$rs1 = mysqli_query($conn, "CALL test_sp_no_params()");
$arr = array();
while($row1 = mysqli_fetch_assoc($rs1))
$arr[] = $row1;
What is the problem when I am calling the second stored procedure?
Can anyone help me out please!
Thanks in advance,
SuryaPavan
I have recently been having troubles with MySQLI as well. I am using MySQLI::multi_query but I would assume that this may be a solution for you as well. After you call the query, try using this function and let me know if it brings back what you're expecting. Seeing as you're only doing a single query instead of a multi_query I'm sure you could trim some of the fat off of this function as well.
public function getResultSets() {
$retVal = array();
do {
if ($result = $this->mysqli->store_result())
$retVal[] = $result;
} while ($this->mysqli->next_result());
return $retVal;
}
I will say, however, that a stored procedure call will not return anything. If you would like it to then you have to set out parameters and pass them along. For instance, if I have a stored procedure with 2 ins and 2 outs, I would pass this into the MySQLI::multi_query (the multi_query part of it means you can specify multiple queries to pass along the same way you would in mysql workbench).
$thisGuy = new MySQLI(inputParamsHere);
$retVal = $thisGuy->multi_query("CALL myDB.storedProc($var1, $var2, #return1, #return2); select #return1 as firstValue, #return2 as secondValue;");
if ($retVal) getResultSets();
getResultSets() will then return an array that contains the results of each query within it (so long as there is something in the result set, the initial stored procedure call returns nothing and therefore there is an empty result set within the mysqli object that we dispose of it in the function).

Categories