PHP PDO cannot get OUT parameter value - php

I just started using PHP PDO with MySQL stored procedures and I have problem with how to get OUT parameters from the procedure call. I looked at many similar stackoverflow topics, but unfortunately I couldn't find a way to resolve my issue :|
Here are the details:
The procedure takes 1 input parameter and has 2 mandatory output parameters, and returns result status in them.
This is how I call it:
$input = 5;
$mydb = new PDO("mysql:host=localhost;dbname=mydb", "user", "pass");
$proc = $mydb->prepare("CALL proc_name($input, #o_code, #o_message)");
$proc->execute();
The procedure returns INT in the #o_code parameter and STRING in the #o_message parameter.
If it's called from CLI, and after the call I write in the CLI
select #o_code, #o_message;
everything is OK, that is I am able to see the values returned in these OUT parameters.
However I cannot do it from PHP code - for some reason I always get FALSE results. The procedure do it's job correctly, but I just cannot get its results.
I tried the following methods to get the values, right after I make the call described above:
$output = $proc->fetch(PDO::FETCH_ASSOC); // also with PDO:FETCH_OBJ
$output = $mydb->query("select #o_code, #o_message");
$output = $mydb->query("select #o_code, #o_message")->fetch();
$output = $mydb->query("select #o_code, #o_message")->fetchColumn();
$output = $mydb->query("select #o_code, #o_message")->fetchAll();
but none of these return any result different from NULL or FALSE. I also tried with bindParam, but still could not make it work.
Thank you for any help on this issue and good day!
----- EDIT -----
Here is the code that I tried with bindParam, which still does not work:
$input = 5;
$proc = $mydb->prepare("CALL proc_name(?, ?, ?)");
$proc->bindParam(1, $input, PDO::PARAM_INT);
$proc->bindParam(2, $code, PDO::PARAM_INT);
$proc->bindParam(3, $message, PDO::PARAM_STR);
$proc->execute();
var_dump($code, $message); // NULL, NULL

The problem was that the first query that is calling the stored procedure is not considered as finished and closed, and PDO will not execute another query until the previous query is done.
The solution was to add $proc->closeCursor();
The whole working sample is:
$input = 5;
$mydb = new PDO("mysql:host=localhost;dbname=mydb", "user", "pass");
$proc = $mydb->prepare("CALL proc_name($input, #o_code, #o_message)");
$proc->execute();
$proc->closeCursor();
$output = $mydb->query("select #o_code, #o_message")->fetch(PDO::FETCH_ASSOC);
var_dump($output); // array('#o_code'=>value, 'o_message'=>value)

Related

Can't call PHP function multiple times

I am trying to fix my previous problem with an extra query.
However, when I am trying to make multiple calls to my PHP function it just shows the first one and not both.
Code:
<?php function test($colour)
{
$pdo = new PDO("pgsql:host=localhost;dbname=testdb","teun",""); // or use a global one
//$pdo = $GLOBALS['pdo'];
$sth = $pdo->prepare("SELECT * FROM threads WHERE cat_id = :cat_id AND thread_date=(
SELECT max(thread_date) FROM threads
)");
$sth->bindParam(':cat_id', $colour, PDO::PARAM_STR, 12);
$sth->execute();
$result = $sth->fetch();
echo $result ["thread_name"];
}
?>
(yes, I know this is unsafe but I want to achieve my thing first before I work on the safe part).
I call it using test ($row['extra_cat_id'])
Thanks!
fetch() only fetches 1 row, see PDOStatement::fetch.
Either iterate using fetch() to fetch 1 by 1, or use the fetchAll() method to fetch all results, see PDOStatement::fetchAll

PHP PDO MSSQL Stored Procedure

I'm having problems trying to run a stored procedure on MSSQL2000 using PHP PDO. I've tried all the combinations, but cant get any results apart from Invalid cursor state error.
The procedure is inside a database that is used by another application. I'm just reaching inside it to pull information out to display on PHP. So modifying the stored procedure (even to instead that SET NOCOUNT ON) is a no-no.
The stored procedure takes two arguments - a start and end date. There is also a RETURN_VALUE parameter.
I can run the following command in the SQL Query Analyzer and dumps rows of data fine:
EXEC [availability_enquiry] '08-24-2015 0:0:0.000', '08-26-2015 0:0:0.000'
Seems pretty straight forward, but when I try to code it and run it, I get nothin:
$dbConn = null;
$connectionString = sprintf('%s:Driver=%s;Server=%s;Database=%s;TrustedConnection=yes;', 'odbc', '{SQL Server Native Client 10.0}', 'mypc', 'testdb');
$dbConn = new PDO($connectionString, 'root', '123qew');
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "EXEC [availability_enquiry] '08-24-2015 0:0:0.000', '08-26-2015 0:0:0.000'";
$stmt = $dbConn->query($sql, PDO::FETCH_ASSOC);
$data = $stmt->fetch();
print_r($data);
I get an PDO Expection: 'Invalid cursor state' on the $stmt->fetch() line.
$stmt = $dbConn->prepare($sql);
$stmt->execute();
$data = $stmt->fetch();
print_r($data);
Still get an PDO Expection: 'Invalid cursor state'. Must be something to do with the fetch. Try something else:
$data = array();
do {
$results[count($results)] = $stmt->fetchAll(PDO::FETCH_ASSOC);
}
while($stmt->nextRowset());
Still nothing!? Any ideas?
UPDATE1:
Tried another method:
$sql = "{CALL availability_enquiry (:startdate, :enddate)}";
$stmt = $dbConn->prepare($sql);
$startdate = "2015-08-24T00:00:00";
$enddate = "2015-08-26T00:00:00";
$stmt->execute(array(
':startdate'=>$startdate,
':enddate'=>$enddate
));
$data = $stmt->fetch();
print_r($data);
Also tried it as:
$startdate = "2015-08-24T00:00:00";
$stmt->bindParam(':startdate', $startdate, PDO::PARAM_STR);
$enddate = "2015-08-26T00:00:00";
$stmt->bindParam(':enddate', $enddate, PDO::PARAM_STR);
$stmt->execute();
But both give me an 'Invalid character value for cast specification' error message. Tried it with my own and the newly suggested date format.
If I use the same format of the date that is inside the table that the stored procedure uses:
$startdate = "2015-08-11 09:42:18.890";
I get an 'Invalid cursor state' error message. I'm hoping this is one step closer?

PHP MySQL PDO Binding Input/Output Same Parameter

I have a simple MYSQL stored procedure I created like this:
CREATE FUNCTION hello (s CHAR(20))
RETURNS CHAR(50) DETERMINISTIC
RETURN CONCAT('Hello, ',s,'!');
Now I created another PHP script to call the stored procedure.
<?php
error_reporting(E_ALL);
$dsn = '***';
$user = '***';
$password = '****';
$dbh = new PDO($dsn, $user, $password);
$stmt = $dbh->prepare("CALL hello(?)");
$value = 'Michael';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";
According to the PHP documentation, adding the PDO::PARAM_INPUT_OUPUT should set the INPUT/OUTPUT parameter flag, but this does not seem to be working.
I am expecting this output: procedure returned Hello Michael!
I am getting this output: procedure returned Michael
How can I bind a parameter that should be used for the input and then get replaced by the output of the query?
That isn't a stored procedure. It's a stored function so it must be called like this:
$stmt = $dbh->prepare("SELECT hello(?)");
I hope that helps!

Accessing MySQL stored procedure output in Zend Framework 2

I have a simple MySQL stored procedure that takes two parameters and inserts a row into a table. I can execute it just fine from Zend Framework 2 like this:
$result = $this->dbAdapter->query('CALL sp_register_user(?, ?)', array('username', 'password'));
I can also access any result sets returned from my stored procedure.
What I want now is to have an output value from my stored procedure as a third parameter, so something like this:
DELIMITER //
CREATE PROCEDURE sp_register_user(IN username VARCHAR(50), IN password VARCHAR(128), OUT code INTEGER)
NOT DETERMINISTIC
COMMENT 'Registers a user'
BEGIN
INSERT INTO user VALUES (username, password);
SET code = 123;
END //
The question is how I can access this output variable from PHP (ZF2). I have only been able to find examples of how to do it directly through PDO, which I am using. Example 4 on this page shows how to do it through PDO directly. My concern is that if I use the PDO object directly, I am losing some abstractions and I am thereby assuming that I will always be using PDO.
Still, I tried to make it work with PDO directly, like this:
$username = 'my_username';
$password = 'my_password';
$code = 0;
$stmt = $this->dbAdapter->createStatement();
$stmt->prepare('CALL sp_register_user(?, ?, ?)');
$stmt->getResource()->bindParam(1, $username);
$stmt->getResource()->bindParam(2, $password);
$stmt->getResource()->bindParam(3, $code, \PDO::PARAM_INT, 3);
$stmt->execute();
However, I get an error saying that the statement could not be executed.
The ideal solution would be one where I could make use of ZF2's abstraction layer, but any ideas on how to access the output parameter are welcome and appreciated.
this must work, because i m using it :
$str = "DECLARE #Msgvar varchar(100);DECLARE #last_id int;
exec CallEntry_Ins $CallLoginId,".$this->usrId .",#Msg = #Msgvar OUTPUT,#LAST_ID = #last_id OUTPUT;
SELECT #Msgvar AS N'#Msg',#last_id AS '#LAST_ID'; ";
$stmt = $db->prepare($str);
$stmt->execute();
$rtStatus = $stmt->fetchAll();
$rtStatus[0]["#LAST_ID"] //accessing Op para

Unable to insert new data into MySQL database after deleting an entry using PHPMyAdmin

I managed to run the following code to insert into my table on first try. Then, I deleted that row in PHPMyAdmin to test my code further. I also noticed that it didn't get deleted on the 1st try. Only after few try. This might be due to I didn't set the $pdoHandle to NULL after I'm done with the query.
Then, unfortunately I couldn't insert new row on subsequent run. I even tried to change the input value and to avail I was unable to insert new row. The following are my PHP codes:
public function CreateNewCustomer($userId,$password,$name,$email)
{
$userId = filter_var($userId,FILTER_SANITIZE_STRING);
$password = filter_var($password,FILTER_SANITIZE_STRING);
$password = sha1($password);
$name = filter_var($name,FILTER_SANITIZE_STRING);
$email = filter_var($email,FILTER_SANITIZE_EMAIL);
do{
$customerId = hexdec(bin2hex(openssl_random_pseudo_bytes(4,$isStrong)));
echo $customerId;
$result = $this->connObject->exec("SELECT COUNT(id) FROM customer_tbl WHERE id=$customerId");
var_dump($result);
}while($result>0);
$statement = $this->connObject->prepare("INSERT INTO customer_tbl (id,name,email) VALUES ($customerId,:name,:email)");
$result = $statement->execute(array(':name'=>$name,':email'=>$email ));
var_dump($result);
$statement = $this->connObject->prepare("INSERT INTO login_tbl (username,password,customer_id) VALUES (:userName,PASSWORD(:password),$customerId)");
$result = $statement->execute(array(':userName'=>$userId,':password'=>$password ));
var_dump($result);
}
I used the following code to access the above method.
function Test($userName,$password,$name,$email)
{
try
{
$dbConnect = new DbConnect();
$pdoHandle = $dbConnect->Connect();
$userAccess = new UserAccess($pdoHandle);
$userAccess->CreateNewCustomer($userName,$password,$name,$email);
}
catch(PDOException $e)
{
$pdoHandle = null;
var_dump($e);
}
$pdoHandle = null;
}
Test('tester','password','TestX','test#example.com');
The var_dump of results is always false.
Is there any problem with my codes or is it something wrong with the database?
UPDATE/SOLUTION:
I just read through the PHP document on PDO::exec() and one of the user contributed notes mentioned that you can't use any SELECT statements (even thou the above only returns the count value) and any statements which might return a rows. The return value of PDO::exec() is the number of affected rows (integer), so the PDOStatement::closeCursor() can't be used to solve it. Even when I set the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true, it still doesn't work.
So, don't use PDO::exec() for any SELECT. I changed my code to PDO::query() instead as below,
do{
$customerId = hexdec(bin2hex(openssl_random_pseudo_bytes(4,$isStrong)));
$statement = $this->connObject->query("SELECT COUNT(id) FROM customer_tbl WHERE id=$customerId");
$statement->execute();
}while($statement->fetchColumn(0)>0);
Hope this would be helpful to anyone looking for a solution with similar problem and always remember to read the PHP document first including the user contributions.
Maybe not the answer but here are some things that you can do if you cannto see an obvious error:
If execute returns false, you can get more information about the error that happened by:
$arr = $statement->errorInfo();
print_r($arr);
or you can set different error reporting modes (e.g. throw an exception instead of the defaultsilent mode):
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
$user = 'dbuser';
$password = 'dbpass';
$dbh = new PDO($dsn, $user, $password);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
This should help you to find the "real" error.
As it turned out (see comments below question), in this case the real error was:
"Cannot execute queries while other unbuffered queries are active.
Consider using PDOStatement::fetchAll(). Alternatively, if your code
is only ever going to run against mysql, you may enable query
buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY"
In this case you have 2 options:
you can set the option to use buffered queries
$dbh = new PDO(’mysql:host=localhost;dbname=test’, ‘root’, ” ,array(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true))
or change your code and close an open cursor (may depend on the db driver you are using). You always should read the documentation which covers a lot of default problems.
Hope this helps.
I'm assuming the method is inside the UserAccess class and the connection you pass in is set to the local $this->connObject.
I suspect after you deleted the record, $customerId is being set to null in your interesting do-while loop with the select statement. If the id column in the DB is a non-null primary key field and you try to insert an explicit null it will fail.
Also, no need to keep setting your DB connection to null... this isn't C and connections aren't persistent (unless you explicitly declare them as such).

Categories