How to run Transact-SQL with PHP PDO - php

I have a pl/sql script which is made up of multiple statments:
SET #sql = NULL;
**Select values into variable**;
**Build a statment**;
**Prepare and execute statment**;
Run directly from the my-sql database this ouputs a standard table of results.
But as I understand it, PDO has issues/limitations when it comes to running multiple statments and returns zero results for me,
what would be the best way to return this queries results as a normal result set?
My experience with PDO has been limited to standard querires so i appologise if this is the wrong approach.

First how you can pl-sql statements on MySQL DB ?
However If you have some MySQL statements, You can better create a MySQL Procedure and put code into that. Then call the procedure through PDO. Like following example from PDO Prepared Statments
$stmt = $dbh->prepare("CALL sp_returns_string(?)");
$stmt->bindParam(1, $return_value, PDO::PARAM_STR, 4000);
// call the stored procedure
$stmt->execute();

Related

Is it possible to use (with PHP) prepared statements that have been previously declared in the mysql CLI?

In the mysql CLI I have prepared a statement like this:
PREPARE registrarUser FROM 'INSERT INTO Users (Users_name,Email,pass) values (?,?,?)'
In my database the prepared statements have to be done this way,instead of using a php method like this::
$conn->prepare("INSERT INTO Users (Users_name,Email,pass) VALUES (?, ?, ?)");
So I can't use the prepared statement or bind arguments.
I have tried this query which mimics the required statements in mysql CLI
$query = sprintf('
SET #Users_name = "%s";
SET #Email= "%s";
SET #pass = "%s";
EXECUTE registrarUser USING #Users_name, #Email, #pass;',$Users_name,$Email,$pass);
But it returns the following syntax error:
Errormessage: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET #Email= "eds#gmail.com"; SET #pass = "Thinkshap2"; EXECUTE registrar' at line 2
Does anyone know if there is a way to do it?
Thank you very much in advance;
No, it's not possible. Prepared statements have the session scope. Whenever you open a new connection in PHP, you open a new MySQL session. You can use PREPARE and EXECUTE in PHP, but both operations have to be done using the same session.
In other words, statements created with PREPARE do not persist on the database server. They only exist for the lifetime of the current session.
The reason why you are getting a syntax error in PHP is because you have concatenated multiple SQL statements together. You can't do that by default in PHP due to security considerations. Execute each one separately. For example, this works:
$stmt = $mysqli->query("PREPARE registrarUser FROM 'SELECT ?'");
$stmt = $mysqli->query("EXECUTE registrarUser USING 32");
Warning. Using PREPARE and EXECUTE from PHP defeats the main purpose of prepared statements usage in PHP. The main advantage is that you can separate variables from SQL syntax. You can't do that with PREPARE and EXECUTE. This is why both PDO and mysqli have prepared statements. Use mysqli::prepare() and mysqli_stmt::execute()
It's not possible.
From the MySQL manual
The scope of a prepared statement is the session within which it is created...
A prepared statement created in one session is not available to other sessions.

How to use Functions to create Prepared Statements

I am new to these prepared statements (all my code so far has been procedural), and I was trying to create a function for executing prepared statements so I could save time writing a statement for every SQL query I need.
function executeQuery($stmt,$mysqli,$sql,$type,$param1,$param2,$param3){
$stmt = $mysqli -> stmt_init();
$stmt = $mysqli -> prepare($sql);
$stmt->bind_param($type,$param1,$param2,$param3);
$stmt->execute();
$stmt->close();
}
As you can see, my issue is that I would need a different function for prepared statements that only deal with 1 parameter in the query, one for 2 parameters, another for 3 and so on. I thought of making $param an array but I don't think that quite works.
Any ideas?

PDO::query() run into "Cannot execute queries while other unbuffered queries are active."

Maybee some other have the same problem than me.
I run over the error:
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 attribute.
on PDO. As in many threads mentioned the error can at be at least one of the following problems:
The query cursor was not closed with closeCursor() as mentioned here; Causes of MySQL error 2014 Cannot execute queries while other unbuffered queries are active
There are more than two querys with one statement like mentioned here: PDO Cannot execute queries while other unbuffered queries are active
A bug in mysql-driver as mentioned here: What is causing PDO error Cannot execute queries while other unbuffered queries are active?
In my case all above did not help and it took some time till i solved the problem. this was my code (pseudo-code):
$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();
$stmt->query("USE sometable;");
After I changed it to:
$stmt->startTransaction();
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
$stmt->prepare('SELECT * FROM database');
$stmt->execute();
$aData = $stmt->fetchAll();
$stmt->closeCursor();
$stmt->exec("USE sometable;");
It worked for my. What is the difference between query and exec?
PDO::exec() - "Execute an SQL statement and return the number of affected rows"
PDO::query() - "Executes an SQL statement, returning a result set as a PDOStatement object"
Why in this case PDO::query() does not work? The cursor IS closed, when called.
While it could conceivably be true that you've encountered the mysql driver bug here, we can't be sure of that because you've not given us that information (what version of PHP are you using? Does it use mysqlnd => check with php -i | grep mysqlnd? What does the rest of your code look like?).
There are many other possible explanations for your problem. I suspect the issue is actually your failing to close all the cursors, and/or fetch all the results, because $stmt is being reused heavily:
Quoted directly from the PDO::query manual page:
If you do not fetch all of the data in a result set before issuing your next call to PDO::query(), your call may fail. Call PDOStatement::closeCursor() to release the database resources associated with the PDOStatement object before issuing your next call to PDO::query().
You call closeCursor on $stmt, that's true, but you've not closed all cursors that have been created by you:
//<-- what is $stmt here?
$stmt->startTransaction();
//no matter, you've reassigned it a PDOStatement instance
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
//Huh? You're preparing yet another query on an instance of PDOStatement?
$stmt->prepare('SELECT * FROM database');
//you're executing this one, though
$stmt->execute();
//and fetching all data
$aData = $stmt->fetchAll();
//and closing this last statement
$stmt->closeCursor();
But what about the first statement you assigned to $stmt (the stored procedure call)? That cursor isn't closed anywhere
Now for the major difference between PDO::query and PDO::exec. Again, quoting the manual:
PDO::exec() does not return results from a SELECT statement.
Whereas:
PDO::query() executes an SQL statement in a single function call, returning the result set (if any) returned by the statement as a PDOStatement object.
I came across this problem too. It is likely to be a bug. If we take the following code, then you will see how it fails with the message 'General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll().'
$pdo = new \PDO("mysql:host=localhost", "root", "");
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query("USE test");
If you change $pdo->query("USE test"); to $pdo->exec("USE test"); it will work. If you change $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); to $pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true); it will also work. I haven't been able to find a proper solution yet though.
I solve the issue with steps:
After from performed:
$stmt = db::getInstance()->prepare("CALL phones(:phone)");
I close the:
$stmt->startTransaction();
And after that, I open again the transaction to use the query below:
$stmt->prepare('SELECT * FROM database');
My solve it is: One statement to call the procedure "CALL phones(:phone)" and another to execute the query wtih "SELECT * FROM database".
That is it.
Be careful, This can also happen if you are trying to fetch a non SELECT query (Eg - UPDATE/INSERT/ALTER/CREATE)

How to use MySQL stored procedures with PHP? [duplicate]

The question is a fairly open one. I've been using Stored Procs with MS SQLServer for some time with classic ASP and ASP.net and love them, lots.
I have a small hobby project I'm working on and for various reasons have gone the LAMP route. Any hints/tricks/traps or good starting points to get into using stored procedures with MySQL and PHP5? My version of MySQL supports Stored Procedures.
#michal kralik - unfortunately there's a bug with the MySQL C API that PDO uses which means that running your code as above with some versions of MySQL results in the error:
"Syntax error or access violation: 1414 OUT or INOUT argument $parameter_number for routine $procedure_name is not a variable or NEW pseudo-variable".
You can see the bug report on bugs.mysql.com. It's been fixed for version 5.5.3+ & 6.0.8+.
To workaround the issue, you would need to separate in & out parameters, and use user variables to store the result like this:
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(:in_string, #out_string)");
$stmt->bindParam(':in_string', 'hello');
// call the stored procedure
$stmt->execute();
// fetch the output
$outputArray = $this->dbh->query("select #out_string")->fetch(PDO::FETCH_ASSOC);
print "procedure returned " . $outputArray['#out_string'] . "\n";
Forget about mysqli, it's much harder to use than PDO and should have been already removed. It is true that it introduced huge improvements over mysql, but to achieve the same effect in mysqli sometimes requires enormous effort over PDO i.e. associative fetchAll.
Instead, take a look at PDO, specifically
prepared statements and stored procedures.
$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";
It isn't actually mandatory to use mysqli or PDO to call stored procedures in MySQL 5. You can call them just fine with the old mysql_ functions. The only thing you can't do is return multiple result sets.
I've found that returning multiple result sets is somewhat error prone anyway; it does work in some cases but only if the application remembers to consume them all, otherwise the connection is left in a broken state.
You'll need to use MySQLI (MySQL Improved Extension) to call stored procedures. Here's how you would call an SP:
$mysqli = new MySQLI(user,pass,db);
$result = $mysqli->query("CALL sp_mysp()");
When using SPs you'll need close first resultset or you'll receive an error. Here's some more information :
http://blog.rvdavid.net/using-stored-procedures-mysqli-in-php-5/
(broken link)
Alternatively, you can use Prepared Statements, which I find very straight-forward:
$stmt = $mysqli->prepare("SELECT Phone FROM MyTable WHERE Name=?");
$stmt->bind_param("s", $myName);
$stmt->execute();
MySQLI Documentation: http://no.php.net/manual/en/book.mysqli.php
I have been using ADODB, which is a great thing for abstracting actual commands to make it portable between different SQL Servers (ie mysql to mssql). However, Stored procedures do not appear to be directly supported. What this means, is that I have run a SQL query as if it is a normal one, but to "call" the SP.
An example query:
$query = "Call HeatMatchInsert('$mMatch', '$mOpponent', '$mDate', $mPlayers, $mRound, '$mMap', '$mServer', '$mPassword', '$mGame', $mSeason, $mMatchType)";
This isn't accounting for returned data,which is important. I'm guessing that this would be done by setting a #Var , that you can select yourself as the return #Variable .
To be Abstract though, although making a first php stored procedure based web app was very difficult to work around (mssql is very well documented, this is not), It's great after its done - changes are very easy to make due to the seperation.

Stored Procedures, MySQL and PHP

The question is a fairly open one. I've been using Stored Procs with MS SQLServer for some time with classic ASP and ASP.net and love them, lots.
I have a small hobby project I'm working on and for various reasons have gone the LAMP route. Any hints/tricks/traps or good starting points to get into using stored procedures with MySQL and PHP5? My version of MySQL supports Stored Procedures.
#michal kralik - unfortunately there's a bug with the MySQL C API that PDO uses which means that running your code as above with some versions of MySQL results in the error:
"Syntax error or access violation: 1414 OUT or INOUT argument $parameter_number for routine $procedure_name is not a variable or NEW pseudo-variable".
You can see the bug report on bugs.mysql.com. It's been fixed for version 5.5.3+ & 6.0.8+.
To workaround the issue, you would need to separate in & out parameters, and use user variables to store the result like this:
$stmt = $dbh->prepare("CALL sp_takes_string_returns_string(:in_string, #out_string)");
$stmt->bindParam(':in_string', 'hello');
// call the stored procedure
$stmt->execute();
// fetch the output
$outputArray = $this->dbh->query("select #out_string")->fetch(PDO::FETCH_ASSOC);
print "procedure returned " . $outputArray['#out_string'] . "\n";
Forget about mysqli, it's much harder to use than PDO and should have been already removed. It is true that it introduced huge improvements over mysql, but to achieve the same effect in mysqli sometimes requires enormous effort over PDO i.e. associative fetchAll.
Instead, take a look at PDO, specifically
prepared statements and stored procedures.
$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";
It isn't actually mandatory to use mysqli or PDO to call stored procedures in MySQL 5. You can call them just fine with the old mysql_ functions. The only thing you can't do is return multiple result sets.
I've found that returning multiple result sets is somewhat error prone anyway; it does work in some cases but only if the application remembers to consume them all, otherwise the connection is left in a broken state.
You'll need to use MySQLI (MySQL Improved Extension) to call stored procedures. Here's how you would call an SP:
$mysqli = new MySQLI(user,pass,db);
$result = $mysqli->query("CALL sp_mysp()");
When using SPs you'll need close first resultset or you'll receive an error. Here's some more information :
http://blog.rvdavid.net/using-stored-procedures-mysqli-in-php-5/
(broken link)
Alternatively, you can use Prepared Statements, which I find very straight-forward:
$stmt = $mysqli->prepare("SELECT Phone FROM MyTable WHERE Name=?");
$stmt->bind_param("s", $myName);
$stmt->execute();
MySQLI Documentation: http://no.php.net/manual/en/book.mysqli.php
I have been using ADODB, which is a great thing for abstracting actual commands to make it portable between different SQL Servers (ie mysql to mssql). However, Stored procedures do not appear to be directly supported. What this means, is that I have run a SQL query as if it is a normal one, but to "call" the SP.
An example query:
$query = "Call HeatMatchInsert('$mMatch', '$mOpponent', '$mDate', $mPlayers, $mRound, '$mMap', '$mServer', '$mPassword', '$mGame', $mSeason, $mMatchType)";
This isn't accounting for returned data,which is important. I'm guessing that this would be done by setting a #Var , that you can select yourself as the return #Variable .
To be Abstract though, although making a first php stored procedure based web app was very difficult to work around (mssql is very well documented, this is not), It's great after its done - changes are very easy to make due to the seperation.

Categories