I'm trying to get OUTPUT using bindParam (PHP PDO). The PHP PDO library is the FreeTDS for MS SQL driver. Whatever I do, I can't seem to get the "OUTPUT" in the the bound params as suggested on php.net. I've verified I can call the EXEC and return a result set (using a select), but the OUTPUT parameters never change.
PHP Code. $this->db is a PDO object
$stmt = $this->db->prepare("EXEC ".$this->db_schema."[".$this->procedure."] :error_num, :error_msg");
$error_num = 0;
$error_msg = '';
$stmt->bindParam(':error_num', $error_num, PDO::PARAM_INT|PDO::PARAM_INPUT_OUTPUT);
$stmt->bindParam(':error_msg', $error_msg, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 2000);
$stmt->execute();
var_dump($stmt);
echo "\nerror_num: $error_num";
echo "\nerror_msg: $error_msg\n\n";
Stored Procedure for test OUTPUT
USE [NGCustom]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [web].[addTest] (
#error_num int OUTPUT,
#error_msg VARCHAR(MAX) OUTPUT
)
AS
BEGIN
SET #error_num = 99
SET #error_msg = 'Error! Oh my gosh!'
END
GO
Output from PHP:
object(PDOStatement)#77 (1) {
["queryString"]=>
string(54) "EXEC [NGCustom].[web].[addTest] :error_num, :error_msg"
}
error_num: 0
error_msg:
AFAIK, the FreeTDS driver does not support OUTPUT parameters. I remember this from when my team was doing our assessment.
Here's why it doesn't work:
http://www.freetds.org/faq.html#ms.output.parameters
EDIT: Here's a reference from pyodbc (which also runs on FreeTDS), so the same applies: https://code.google.com/p/pyodbc/wiki/StoredProcedures
To quote: "Results: Since we can't use output parameters at this point, you'll need to return results in a result set. Usually this means just ending your stored procedure with a SELECT statement."
You'll need to use a SELECT instead.
Your stored procedure is assigning the parameters, but not returning them.
BEGIN
SET #error_num = 99
SET #error_msg = 'Error! Oh my gosh!'
SELECT #error_num, #error_msg; --add this line
END
GO
Related
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
I've been using PDO for awhile now and am refactoring a project so that it uses stored procs instead of inline SQL. I am getting an error that I can't explain.I am using PHP version 5.3.5 and MySQL version 5.0.7.
I'm just trying to get a basic stored proc with an output to work. Here is the stored proc:
DELIMITER //
CREATE PROCEDURE `proc_OUT` (OUT var1 VARCHAR(100))
BEGIN
SET var1 = 'This is a test';
END //
Here is the code I am using to call the proc, $db is an instance of PDO:
$stmt = $db->prepare("CALL proc_OUT(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// call the stored procedure
$stmt->execute();
echo $returnvalue;
Simple right? However, it results in the following error:
exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1414 OUT or INOUT argument 1 for routine mydb.proc_OUT is not a variable or NEW pseudo-variable in BEFORE trigger
If I call the proc directly like so:
CALL proc_OUT(#res);
SELECT #res;
it works as expected which leads me to believe that there is a problem with how it is being called with PHP, however I can't seem to find what the issue is. I am following the instructions in the manual but am still getting this error. Could anyone suggest what I could be doing wrong? Any advice would be very much appreciated. Thanks much!
It would seem that there is a bug at work here, best solution I've found is this:
http://www.php.net/manual/en/pdo.prepared-statements.php#101993
From the comment at the link above:
$dbh->query("CALL SomeStoredProcedure($someInParameter1, $someInParameter2, #someOutParameter)");
$dbh->query("SELECT #someOutParameter");
// OR, if you want very much to use PDO.Prepare(),
// insert "SELECT #someOutParameter" in your stored procedure and then use:
$stmt = $dbh->prepare("CALL SomeStoredProcedure(?, ?)");
$stmt ->execute(array($someInParameter1, $someInParameter2));
See also this: https://stackoverflow.com/a/4502524/815386
Got it! Just add a
SELECT #outputparam;
at the end of the stored procedure, where #outputparam is the name used for the param in the stored procedure definition. If you cannot edit the stored procedure, you should do a second query, for SELECT #outputparam, with PHP PDO to get the output param value.
Tip: If you're using the deprecated DBLib to connect to SQL Server and you modified the stored procedure as suggested, you'll also need to tweak your syntax to get the output param value in the calling PHP script:
$out = 0;
$sth = $db->prepare("DECLARE #myout INT; EXECUTE mysp :firstparam, :secondparam, #myout OUTPUT;"); // the DECLARE trick is needed with DBLib
$sth->bindParam(':firstparam', $firstparam, PDO::PARAM_INT);
$sth->execute();
$sth->bindColumn(1, $out, PDO::PARAM_INT);
$sth->fetch(PDO::FETCH_BOUND);
var_dump($out); // works
You need to specify that your parameter is IN/OUT style like PHP web site example :
http://php.net/manual/en/pdo.prepared-statements.php example #5
<?php
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(?)");
$value = 'hello';
$stmt->bindParam(1, $value, PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
// call the stored procedure
$stmt->execute();
print "procedure returned $value\n";
I try to run one of the stored proc with php. But somehow this is always display the following error message on the screen:
"Warning: mssql_execute(): supplied argument is not a valid MS SQL-Statement resource..."
Please find below for my code for calling the stored proc in php:
$conn = mssql_connect("sql-02", "rsGreen", "abc123");
$db = mssql_select_db("Green");
$Query = "exec rpt_control #list = '".$_REQUEST['list']."',
#suburb = '".$_REQUEST['suburb']."',
#state = '".$_REQUEST['state']."',
#on_off = ".$_REQUEST['switch'];
mssql_execute($Query );
Do anyone know how is going wrong with my code?
Note: When I'm manually run the stored proc, this is working fine and no error display
mssql_execute() executes a prepared statement, not a string containing a SQL statement (which is the function of mssql_query(). You will need to prepare a statement, bind parameters into it, and execute it:
// Prepare it with mssql_init()
$qry = mssql_init("rpt_control", $conn);
if ($qry) {
// We assume these fields are all VARCHAR types...
// If not, see the type constants listed on the mssql_bind() docs...
mssql_bind($qry, '#list', $_REQUEST['list'], SQLVARCHAR);
mssql_bind($qry, '#suburb', $_REQUEST['suburb'], SQLVARCHAR);
mssql_bind($qry, '#state', $_REQUEST['state'], SQLVARCHAR);
mssql_bind($qry, '#switch', $_REQUEST['switch'], SQLVARCHAR);
// Then execute it
mssql_execute($qry);
// And free it
mssql_free_statement($qry);
}
mssql_execute() docs
mssql_bind() docs
Although it would be possible to execute your stored procedure by building a SQL string and sending it to mssql_query(), doing so is not recommended when a prepared statement can be used.
I believe you should be using the sqlsrv functions instead of mssql, but you should refer to the php documentation before asking a question here as it can probably help you get to the root of your problem. mssql_execute() requires a resource, not a string query. You either need to create a stored procedure to call mssql_init() with, or in your case you can probably use mssql_query().
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!"
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.