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!
Related
Here is the function where I create a DB connection:
function get_db_connection()
{
$host = "127.0.0.1:3306";
$username = "root";
$password = "";
$db = "crm";
return mysqli_connect($host, $username, $password, $db);
}
Here is a function where I use my query:
function query_user_by_username($username)
{
$conn = get_db_connection();
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
//var_dump($stmt->get_result()->fetch_assoc());
return $stmt;
}
When I execute var_dump inside the function I get NULL which is perfectly fine response for current scenario.
However, when I call this function from another place, I get an error when executing that same var_dump.
Example code:
require_once(__DIR__ . '/../../db/dbh.inc.php');
$db_response = query_user_by_username("zxc");
var_dump($db_response->get_result()->fetch_assoc());
When this is executed, I get the following error:
Fatal error: Uncaught Error: Call to a member function fetch_assoc() on boolean in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php:17 Stack trace: #0 {main} thrown in /opt/lampp/htdocs/src/signinscreen/repo/signin.inc.php on line 17
For some reason, $stmt->get_result() inside the function is an actual object but when returned from the function, it is bool.
Why?
When you call get_db_connection() it creates a new instance of the mysqli class and opens a connection to the MySQL server. This object lives as long as you have a PHP variable pointing to it. In your case the connection is alive only within the scope of your query_user_by_username() function.
Prepared statements in mysqli are by default producing unbuffered results. The results are not fetched from MySQL server automatically and you need to call get_result(), store_result() or fetch them row by row. To fetch the result set from the server the connection must be open.
When you leave the query_user_by_username() function, PHP will close the connection and discard any remaining results. When you try to fetch the result set using get_result() outside the function, there are no results to be fetched because the connection is closed.
To fix this problem you should pass the mysqli connection as an argument to the function.
function query_user_by_username(mysqli $conn, $username)
{
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
return $stmt;
}
Then you should ensure that the connection lives for as long as your code needs it. Effectively it means you should create only one instance of mysqli class and pass it as an argument to functions that require it.
require_once(__DIR__ . '/../../db/dbh.inc.php');
$conn = get_db_connection();
$db_response = query_user_by_username($conn, "zxc");
var_dump($db_response->get_result()->fetch_assoc());
As you can see, mysqli is a low-level API that makes handling database operations difficult. For this reason it is better to use PDO. If you wish to continue using mysqli then you can consider writing a wrapper class or write your function in such a way that they never expose the underlying mysqli functions to your business layer. For example:
function query_user_by_username(mysqli $conn, $username): ?array
{
$stmt = $conn->prepare("SELECT * FROM `users` WHERE `username`=?");
$stmt->bind_param("s", $username);
$stmt->execute();
// only return the data, not the mysqli object
return $stmt->get_result()->fetch_assoc()
}
I'm trying to execute a stored procedure on SQL Server using PDO. Everything runs fine, but when I try to read the output parameter (whose type is UNIQUEIDENTIFIER) the only thing I get is a NULL.
I've tried running my script on Debian 9 with PHP 7.0 and Ubuntu 18.10 with PHP 7.2 and changing the PDO type of my parameter, with no success.
$order_uid = null;
$sql = "EXEC spInsertOrder ?, ?, ?, ?...";
$stmt = $db->prepare($sql);
$stmt->bindParam(29, $order_uid, PDO::PARAM_INPUT_OUTPUT | PDO::PARAM_STR, 50);
if ($stmt->execute() === false) {
echo $stmt->errorCode();
print_r($stmt->errorInfo());
}
I expect to get the UUID that SQL Server emits, instead this error raises:
Fatal error: Uncaught PDOException: SQLSTATE[IMSSP]: An invalid type
for parameter 5 was specified. Only booleans, integers, floating point
numbers, strings, and streams may be used as parameters.
Before you read the value of your OUTPUT parameter, you need to consider the following:
If your stored procedure executes SELECT statements, you need to consume all results with PDOStatement::nextRowset, before accessing the value of your output parameter.
If your statement executes INSERT or UPDATE statements, put SET NOCOUNT ON as first line in your procedure to stop SQL Server to return the count of the affected rows as a resultset.
set your PHP variable to null.
Working example (tested with PHP 7.1.12 and PHP Driver for SQL Server (PDO) 4.3.0+9904):
T-SQL:
CREATE PROCEDURE [dbo].[sp_UID]
#id UNIQUEIDENTIFIER OUTPUT
AS BEGIN
SET NOCOUNT ON
SET #id = NEWID()
END
PHP:
<?php
# Connection info
$server = 'server\instance,port';
$database = 'database';
$uid = 'uid';
$pwd = 'pdw';
# Connection
try {
$dbh = new PDO("sqlsrv:server=$server;Database=$database", $uid, $pwd);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch( PDOException $e ) {
die("Error connecting to SQL Server. ".$e->getMessage());
}
# Stored procedure
try {
$sql = "{CALL sp_UID(?)}";
$uid = null;
$stmt = $dbh->prepare($sql);
$stmt->bindParam(1, $uid, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 36);
$stmt->execute();
// If your procedure returns result set, you need to fetch result and then get the value for your output parameter
/*
do {
while ($row = $stmt->fetch( PDO::FETCH_ASSOC )) {
}
} while ($stmt->nextRowset());
*/
} catch( PDOException $e ) {
die( "Error executing stored procedure: ".$e->getMessage());
}
$stmt = null;
# End
$dbh = null;
echo $uid;
?>
Output:
F689A035-C3DB-4D4E-88FB-52F5DA133FA8
I'm using bindParam to bind the return value of stored procedure once the statement is executed
But i'm getting zero , i've specified output variable of stored procedure as BIGINT
and i'm binding parameter like below
$sql = "{:retval = CALL sp_testProc()}";
$stmt->bindParam('retval', $proc_pass_val, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT, 4);
bindparam is taking Length of data type as last parameter, i'm passing 4 here, but it returns zero, don't know why
Could anybody help me on this
Thanks in Advance
This is what I've done to make it work, Hope this helps someone.
Note: Procedure defined in MSSQL server
Here I want email into a field inorder to get that in an array, you can omit this line select #myemail as student_email; and you can get the value of #myemail into $myemail
My Procedure:
Alter proc [dbo].[sp_test_success](
#Id int=1,
#myemail varchar(250)=null output
)
AS
BEGIN
select #myemail=rtrim(email) from Student where StudentId=#Id;
select #myemail as student_email;-- i put this to get myemail into array
END
Code:
$dbh = new PDO('sqlsrv:Server=Server;Database=database', 'UID', 'Pwd');
$stmt = $dbh->prepare("{CALL sp_test_success(#Id=:Id,#myemail=:myemail)}");
$Id = 4;
$stmt->bindParam('Id', $Id, PDO::PARAM_INT);
$stmt->bindParam('myemail', $myemail, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 500);
$stmt->execute();
$results = array();
do {
$rows= $stmt->fetch();// default fetch type PDO::FETCH_BOTH
$results[]= $rows;
} while ($stmt->nextRowset());
echo "<pre>"; print_r($results);
print "procedure returned $myemail\n"; exit;
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?
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