Calling stored procedure with Out parameter using PDO - php

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";

Related

PHP PDO (MSSQL) can not get OUPUT parameters

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

PDO PostgreSQL binding error

I found that when I'm trying to run update query with params, I'm getting error
inconsistent types deduced for parameter
Maybe that's because the type of target field (character varying), everything works fine with text column type. But I don't want to change column type only because of this. Then I was told that I should pass params directly (using bindValue or bindParam, determining the type of each value) instead of sending params array to execute method.
But when I do so I'm getting error
ERROR: bind message supplies 0 parameters, but prepared statement
"pdo_stmt_00000001" requires 1
The test code is
$Stmt = $DB->prepare("SELECT * FROM test_table WHERE test_field=:test_field");
$Stmt->bindValue(':test_field', 'test', PDO::PARAM_STR);
$Stmt->execute();
var_dump($DB->errorInfo());
So, as far as understand, binding does not work at all. Or I'm doing it wrong.
But maybe there is a way of solving it?
I'm running PHP 5.4.12 with PostgreSQL 9.2.3, libpq 8.4.16.
Well, it seems that the only solution is to cast all text values to text like this:
update test_table set test_field = :test_field::text
Otherwise error about inconsistent types is occurring.
I do it this way:
$stmt = $DB->prepare("SELECT * FROM test_table WHERE test_field=:test_field");
$stmt->execute(array(":test_field" => 'test'));
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if($result)
{
return $result['id'];
// Or whatever you're trying to get.
}
return null;
You just have to throw in an array of parameters in the execute function, no need to add a special line for the binding.
Tell me if it works for you (or not).

Cant get stored procedure resultset via PDO PHP

I cant seem to get any output from my stored procedure (MYSQL) using PDO (PHP).
Stored procedure:
CREATE PROCEDURE getUserId(serviceId VARCHAR(64), serviceInput VARCHAR(32))
BEGIN
SELECT id FROM users WHERE servid = serviceId AND service = serviceInput;
END
PHP code:
$mysqlConn = mysqlPDOLogin();
$stmt = $mysqlConn->prepare("CALL getUserId(?,?);");
$stmt->bindParam(1, $USERID);
$stmt->bindParam(2, $USERPROVIDER);
$stmt->execute();
$returned_a = $stmt->fetch();
echo $returned_a['id'];
It doesnt get anything back. Ive copied the basic select code out of the stored procedure and used it directly in the PHP code and it works, but cant get it to work via stored procedure.
Any help would be appreciated...
You're not doing any apparent error checking. Prepare(), bindParam() and execute() will all alert you to errors by either returning false or throwing an exception, depending on the error reporting mode PDO is in.
I'm going to assume you're in "return false" mode.
You need to check that $stmt is a PDOStatement object, that the bindParam statements didn't return false and that execute didn't return false. If any of them did then you need to use errorCode() and errorInfo() to find out what went wrong.
Also, it looks somewhat excessive to me to be using a stored procedure for what is basically a simple query. Why not just do the following?
$stmt = mysqlConn->prepare ('SELECT id FROM users WHERE servid = ? AND service = ?');

Warning: mssql_execute(): supplied argument is not a valid MS SQL-Statement resource

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().

Procedures of Oracle in php with PDO

I'm having a problem with propel 1.6 and a oracle procedure. I post it under PDO because I'm Propel just for proxying my call to PDO.
Basically the procedure get the user name and password, checks that is
OK and return the user.
For that reason it returns an types.cursorType.
The sql start like this.
CREATE OR REPLACE
PROCEDURE "SP_LOGIN" (R_CURSOR OUT types.cursorType, UserId IN
VARCHAR2, Password IN VARCHAR2)
my php code is:
$con = Propel::getConnection();
$sql = 'BEGIN SP_LOGIN(:CURSOR, :0, :1); END;';
$stmt = $con->prepare($sql);
$result_arr;
$stmt->bindParam(":CURSOR", $result_arr, PDO::PARAM_STR || PDO::PARAM_INPUT_OUTPUT);
$stmt->bindParam(":0", $username, PDO::PARAM_STR);
$stmt->bindParam(":1", $password, PDO::PARAM_STR);
$stmt->execute();
$result_arr = $stmt->fetchAll();
Now that throws an exception of type:
{PDOException} SQLSTATE[HY000]: General error: 6550 OCIStmtExecute:
ORA-06550: lĂ­nea 1, columna 7:
PLS-00306: numbers or types of bad arguments calling 'SP_LOGIN'
What I'm doing wrong?
Thanks in advance.
P.S: I ask this question on the Propel forum and they direct me to search for the PDO solution.
I'd suspect the problem is the first parameter. You tell PDO that it's a string (PDO::PARAM_STR) but it's actually types.cursorType. There's a user comment in the PHP manual that suggests that ref cursors are not supported.
Unluckily, the Oracle driver for PDO is experimental and (IMHO) basically abandoned.
checks that is OK and return the user
No - according to the prototype it returns a cursor. Cursors have no meaning outside PL/SQL. If you change the type to a sys_refcursor and explicitly initialize $result_arr as an array, I'd expect it to have a better chance to work.
Although looking at Alvaro's answer and the absence of a non-scalar paramter type I think it might not.

Categories