Calling MySQL stored procedure in PHP only updates one row - php

I have a stored procedure in MySQL that should update a column in a table. When I run
CALL recalculate_city_ids();
from a MySQL prompt, the correct number of rows are updated (a few hundred). When I run the command from PHP, only a single row is updated and I get no error.
Here's the PHP:
$con = mysqli_connect('localhost', 'user', 'pass', 'dbname' );
$result = $con->query( 'call recalculate_city_ids()' );
mysql_close($con);
And the SQL for the sproc:
DROP PROCEDURE IF EXISTS recalculate_city_ids;
DELIMITER $$
CREATE PROCEDURE recalculate_city_ids()
READS SQL DATA
BEGIN
DECLARE o_id INT DEFAULT 0;
DECLARE o_latitude FLOAT;
DECLARE o_longitude FLOAT;
DECLARE done INT DEFAULT 0;
DECLARE cur_users CURSOR FOR SELECT id, latitude, longitude FROM user WHERE latitude IS NOT NULL ORDER BY fname;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1;
OPEN cur_users;
users: LOOP
FETCH cur_users INTO o_id, o_latitude, o_longitude;
IF done=1 THEN
LEAVE users;
END IF;
SELECT #closest_city_distance:=fn_distance_cosine(o_latitude, o_longitude, latitude, longitude) AS distance, #closest_city_id:=id AS id FROM category WHERE zone="city" AND active=1 ORDER BY distance LIMIT 1;
UPDATE user SET city_id = IF(#closest_city_distance<=30, #closest_city_id, 0) WHERE id=o_id;
END LOOP users;
CLOSE cur_users;
END
$$
I can run other queries from PHP using mysqli (also tried the mysql object). I'm also unable to create stored procedures from PHP (no error) and had to do that part from a MySQL prompt as well.
PHP and my MySQL prompt are using the same username.

I think that PHP doesn't like it when a query returns multiple result sets. I don't really need to return anything since this is just a glorified UPDATE statement, so I changed my
SELECT #closest_city_distance:=fn_distance_cosine... query to
SELECT fn_distance_cosine(o_latitude, o_longitude, latitude, longitude) as distance,id into closest_city_distance, closest_city_id FROM category WHERE zone="city" AND active=1 ORDER BY distance LIMIT 1;
Since that was the only place a result set was getting returned, eliminating the returned sets fixed the problem.

Related

interrupt the execution of the stored procedure (mysql) in php

I wrote a stored procedure (mysql)
CREATE PROCEDURE `set_SiteAttendance`(IN _UserName VARCHAR(20) CHARSET utf8, IN _EventDesc VARCHAR(250) CHARSET utf8, IN _EventTime BIGINT(20))
BEGIN
DECLARE _EventID INT;
DECLARE cursorGetID CURSOR FOR
SELECT id
FROM client_pages
WHERE name = _EventDesc
LIMIT 0, 1;
-- try to add a new record to the database
INSERT INTO client_pages (id, name) SELECT (IFNULL(MAX(id), 0) + 1), _EventDesc FROM client_pages;
-- get id from the database records
OPEN cursorGetID;
FETCH cursorGetID INTO _EventID;
-- set the data on the visit of the page in the database
INSERT INTO login_history VALUES (NULL, _UserName, _EventID, _EventTime);
END
When I call it using MySQL Workbench, it works correctly.
CALL set_SiteAttendance('MyName', 'page#1', 100);
When I call it using php, then the stored procedure aborts on the INSERT statement:
$query = "CALL set_SiteAttendance('$user_name', '$user_page', $user_ticks)";
mysql_query($query);
mysql_error() call issues
Duplicate entry 'page#1' for key 'name'
why it happens and how to fix?
Well, that's pretty obvious. You have a unique index on name, so your query INSERT INTO client_pages (id, name) SELECT (IFNULL(MAX(id), 0) + 1), _EventDesc FROM client_pages; can only be run once with same _EventDesc parameter.
Remove the index or change the logic of your procedure.
I decided my problem:
INSERT IGNORE INTO client_pages (id, name) SELECT (IFNULL(MAX(id), 0) + 1), _EventDesc FROM client_pages;
Error (name was found) was ignored and procedure is not interrupted

MySQL Stored Procedure select not returning anything

I have the following stored procedure in a MySQL db. It doesn't return anything when I run it from my PHP code(Which I know is correct because it works for all of my other stored procedures). When I log into phpmyadmin and execute the stored procedure from the "Routines" page it works just fine. Any help would be much appreciated.
DELIMITER //
drop procedure if exists spGetTeam //
CREATE PROCEDURE spGetTeam(IN tid INT)
BEGIN
SELECT team_id, team_name FROM teams WHERE team_id = tid;
END //
DELIMITER ;
I'm calling the sp from my php like so:
$sql = 'CALL spGetTeam(2)';
The sp is called with the following:
$result = mysqli_query($con,$sql);
while($row = mysqli_fetch_assoc($result)) {
//handle return
}
This started working the next day. Not sure what happened. No code was changed. If I ever figure it out I will update the answer.

Insert ID field generated from trigger, but not passed along

In MySQL, I have a trigger:
BEGIN
IF (EXISTS(SELECT * FROM devices WHERE device_id = NEW.device_id)) THEN
SET NEW.id = NULL;
ELSE
INSERT INTO objects (object_type) VALUES ('3');
SET NEW.id = LAST_INSERT_ID();
END IF;
END
When this trigger gets a new id (from the objects table) it inserts the id into the id column of the devices table.
When I refer to it (for example with mysql_insert_id(); in PHP), its empty.
How can I return the insert id from the trigger (LAST_INSERT_ID();) to the function in PHP as the mysql_insert_id(); ?
Personally I use stored procedures.
Here is a basic example with PDO:
Code to create the Stored Procedures:
CREATE DEFINER=`user`#`localhost` PROCEDURE `InsertUser`(IN `Input_username` INT, OUT `Out_ID` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
INSERT INTO users(
username)
VALUES (
Input_username);
SET Out_ID = LAST_INSERT_ID();
SELECT Out_ID;
END
And PHP code:
$insert = "CALL InsertUser(:Input_username,
#Out_ID)";
$bdd = new PDO('mysql:host=localhost;dbname=db-name', 'user', 'password');
$stmt = $bdd->prepare($insert);
$stmt->bindParam(':Input_username', rand(), PDO::PARAM_STR); // to create random name
$stmt->execute();
$tabResultat = $stmt->fetch();
$id_user = $tabResultat['Out_ID'];
var_dump($id_user);
I hope I have helped. :)
This behaviour is by design:
If a stored procedure executes statements that change the value of LAST_INSERT_ID(), the changed value is seen by statements that follow the procedure call.
For stored functions and triggers that change the value, the value is restored when the function or trigger ends, so following statements will not see a changed value.
Workaround 1: Stored Procedures
Unfortunately this introduces a risk of inconsistencies between your table and objects, as insertions could still happen outside of this procedure (this problem could be adressed with convoluted access restrictions on the table)
Workaround 2:
Save the value in a user variable:
CREATE TRIGGER
....
BEGIN
INSERT INTO objects (object_type) VALUES ('3');
SET NEW.id = LAST_INSERT_ID();
SET #myLastInsertID = LAST_INSERT_ID();
END //
INSERT INTO your_table... -- trigger the above
SELECT #myLastInsertID; -- here is your value
Workaround 3:
Simply get the value from object ;)
INSERT INTO your_table... -- trigger the above
SELECT MAX(autoinc_column) FROM objects; -- here is your value!
Workarounds 2 and 3 should be wrapped in a transaction to ensure no-one interferes with #myLastInsertID or object during the process.

Adodb.GetRow() not returning data when there is a Insert before a Select in the query

I'm new. Most of the times I find solutions here just by reading but now I have to ask you directly because of the weirdness of my subject.
I have an application in php and I used to use the mssql libraries to connect to MS Server 2008 but now I migrated part of my code to connect through ADODB http://adodb.sourceforge.net/
I have a store procedure which I use to validate/insert/update/delete rows depending of parameters I send, so at the very bottom I have a line of code like this
Select #Result Result
This variable just tell me everytime if the proccess went correctly or if I'm missing something so the row doesn't get inserted/deleted/updated.
Here the code of my store procedure
create procedure sp_MyTable #id int, #name varchar(100), #type varchar(10)
as
declare #Results varchar(100)
set #Result=#type
--validations!
if exists(select * from MyTable where name=#name)begin
set #Result='No insert:('
end
if #Result='insert'
insert into MyTable (name)values(#name)
select #Result Result
Here and example of code to create my connection in php
$pQry='exec sp_MyTable #id="0",#name="Hello",#type="insert"';
require ("php/ExtClases/adodb5/adodb.inc.php");
$db = ADONewConnection('mssqlnative');
$db->debug = false;
$db->Connect($datCon['sServer'], $datCon['UID'], $datCon['PWD'], $datCon['Database']);
$ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
$rs = $db->Execute($pQry);
$rows=$rs->GetRows();
So, it is supposed to return and Array like this
print_r($rows);
//Array ([0]=>Array( [Result] => insert )) )
But It prints just nothing.
Using Management Studio I already ran this procedure directly on my own computer and at the server online and both cases retrieved data, so the store procedure is fine.
If I remove the insert statement:
create procedure sp_MyTable #id int, #name varchar(100), #type varchar(10)
as
declare #Results varchar(100)
set #Result=#type
--validations!
if exists(select * from MyTable where name=#name)begin
set #Result='No insert:('
end
/*
No insert!
*/
select #Result Result
It works!.
print_r($rows);
//Array ([0]=>Array( [Result] => insert)) )
_UPDATE: even if I print something (print 'something') in the store procedure ADODB ignores the select statement, so the select must be totally alone.
I think I will consider searching for another way.
_.
PD: Sorry for my bad english.
Regards.
Well, it took a few hours of my appreciated life but at last now I know what is going on.
MSSQL driver use to ignore all but the last statement (as I remember...). So, if you have something like this
$query="select * from table1; select some, data from table2; select yadda yadda from table3";
$conn=mysql_connect($sServer,$UID,$PWD);
$baseDatos=mysql_select_db($Database,$conn);
$res=mysql_query($query);
While($row=mssql_fetch_array($res)){
print($row);
}
You will have printed the results only of table3.
( ACTUALLY Here it is written that you can have multiple recorset and navigate through them with mssql http://www.php.net/manual/es/function.mssql-next-result.php but at the moment I don't know why it takes just the last one as the first one. Maybe it doesn't recognize prints or inserts as recorsets at all)
ADODB library actually uses SQLSRV to handle connections and queries to any sql server (mssqlnative). SQLSRV is the official driver released for Microsoft so is slightly different. You need to use the function sqlsrv_next_result or it will be return just the first result whatever it is (print,insert,select,etc)
here the link
http://www.php.net/manual/en/function.sqlsrv-next-result.php
and another guy who had the same problem
SQLSRV and multiple selects in Stored Procedure
what I did is not pretty but with patience I think I can fix it in the future, for now I just need the last recorset (table3) and not the first, so ...
/*here my temporary fix*/
do {
$result = array();
while ($row = sqlsrv_fetch_array($this->_queryID)) {
$result[] = $row;
}
} while (!is_null(sqlsrv_next_result($this->_queryID)));
return $result;
/**/
I overwrite the variable $result with every step into the results :). Funny code.
Cheers

Trying to Call MYSQL Procedure to return int value based on Condition to php

I'm trying to create an SQL procedure where is returns a specified value from the members table.
DELIMITER $$
DROP PROCEDURE IF EXISTS `qrgdev`.`ConfirmMember` $$
CREATE PROCEDURE `qrgdev`.`ConfirmMember` (
check_Username varchar(45),
check_Password varchar(255))
BEGIN
DECLARE intcheckId INTEGER(1);
DECLARE intAccessLevel INTEGER(1) DEFAULT 0;
SELECT id INTO intCheckId FROM members WHERE Username=Check_Username;
IF (intCheckId=0)
SELECT AccessLevel INTO intAccessLevel FROM members WHERE passwrd=check_Password;
ELSE
IF (intCheckId>0) THEN
Update members
Set LastSignIn=CURRENT_TIMESTAMP
Where ID=intCheckId;
SELECT AccessLevel INTO intAccessLevel FROM members WHERE id=intCheckId;
ELSE
Insert into members
(ID, Username, Administrator, Passwrd, LastSignIn)
values
(null, check_Username, 0, null, CURRENT_TIMESTAMP);
END IF;
END IF;
RETURN(intAccessLevel);
END $$
DELIMITER ;
so that i can have php set conditions based on that value
//...
$result = $mysqli->query("Call ConfirmMember($username,$password)");
//...
this started as a function before i learned that php cant call sql functions, its why it still hols return at the bottom and also get the point i want to return the value.
create an SQL procedure where is returns a specified value
There's your biggest problem. Procedures do not return values. Functions return values. OTOH you can pass references to variables as arguments in both procedures and functions - and the procedure/function can change the value.
this started as a function before i learned that php cant call sql functions
Who told you that? It's complete nonsense.
$result = $mysqli->query("Call ConfirmMember($username,$password)");
I assume you've escaped and quoted those variables.
Change PROCEDURE to FUNCTION then invoke it as....
SELECT ConfirmMember($username,$password)

Categories