I am unable to execut long script the pdo throws an exception:
SQLSTATE[HY000]: General error
If I submit script which does not contain variables it runs w/o problem.
The same script runs on phpmyadmin interface.
Here is my code snippet:
try {
$dsn = "mysql:host=" . DB_SERVER . ";dbname=" . DB_DEFAULT;
$db = new PDO($dsn, DB_USER, DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$q = $db->query($query);
if (!$q) {
echo $db->errorInfo();
} else {
$rows = $q->fetchAll(PDO::FETCH_ASSOC);
}
} catch (PDOException $e) {
var_dump($e);
}
Here is some test which does not execute by PDO:
SET #ra_LMC:=80.9;
SELECT #ra_LMC;
How I should execut with pdo the multi line scripts?
Thanks
Arman.
PDO does not allow the execution of multiple statements in one query() request.
But your #ra_LMC variable should be visible in the current connection, so you can put your second line (SELECT) into a new query() call.
To read a whole script, you have to parse the file and run each statement with a call to query().
PDO can only execute one statement at a time. You can ether run the SET and SELECT as 2 separate statements. Or you can set the variable using FROM.
SELECT #ra_LMC FROM (SELECT #ra_LMC:=80.9) q
Related
I'm learning to connect to my database and create/read/update/delete information from different tables. Currently I'm using PDO instead of mysqli because I'm having an easier time with prepared statements. What I'm trying to do right now doesn't actually have any value, I just want to know WHY this is happening. Here's my code:
//pdo connection
try {
$conn = new PDO("mysql:host={$db_host};dbname={$db_name}", $db_user, $db_pass);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//READ FROM DB
$stmt = $conn->prepare('SELECT * FROM objects where ID = :id');
$stmt->execute(array(':id'=>8));
print_r($stmt->fetch(PDO::FETCH_OBJ));
while($row = $stmt->fetch(PDO::FETCH_OBJ)) {
$results[] = $row;
}
print_r($results);
} catch(PDOException $e) {
echo 'ERROR: ' . $e->getMessage();
}
Now, what's happening is that if I print_r in this order then only the first print_r works and vice versa (assuming I also move the while loop with the print_r($results) statement. Why is it that I am only allowed to do this once and whichever is first negates the second?
EDIT: Clarification.
I have a PHP script which works perfectly via Apache called through a browser, but the same code called on command line seems to drop the database connection after every call.
So for instance in an included file I have:
$pdo = new PDO('mysql:host=' . HOST . ';dbname=' . DB, USER, PASS, array(PDO::ATTR_PERSISTENT => true));
Then in my script I have:
$stmt = $pdo->prepare('SELECT intGroupID FROM tblquestiongroups WHERE dtDeleted IS NOT NULL ORDER BY RAND()');
$stmt->execute();
$something = $stmt->fetch(PDO::FETCH_ASSOC);
Which works fine, however directly afterwards I have:
$stmt = $pdo->prepare('SELECT intSurveyID FROM tblquestiongroups WHERE tblquestiongroups.intGroupID = :intQuestionId');
$stmt->bindValue(':intQuestionId', $intQuestionId);
$stmt->execute();
Which doesn't and returns:
Call to member function bindValue() on a non-object
Now if I add a new connection, i.e. copy and paste the one in the include file above the second call it all works fine again, i.e.:
$pdo = new PDO('mysql:host=' . HOST . ';dbname=' . DB, USER, PASS, array(PDO::ATTR_PERSISTENT => true));
$stmt = $pdo->prepare('SELECT intSurveyID FROM tblquestiongroups WHERE tblquestiongroups.intGroupID = :intQuestionId');
$stmt->bindValue(':intQuestionId', $intQuestionId);
$stmt->execute();
My first question is why won't PHP keep the connection open for the period of the script?
So onto my second question. As a test I went through and added the connection before all of the calls to database via PDO. Within this script I actually connect to two different servers and as such I have another connection defined which looks like this:
$pdoLocal = new PDO('mysql:host=' . HOST_LOCAL . ';dbname=' . DB_LOCAL, USER_LOCAL, PASS_LOCAL, array(PDO::ATTR_PERSISTENT => true));
So of course to try and get the thing working I have added this line above any calls to the local database. However with this code:
$pdoLocal = new PDO('mysql:host=' . HOST_LOCAL . ';dbname=' . DB_LOCAL, USER_LOCAL, PASS_LOCAL, array(PDO::ATTR_PERSISTENT => true));
$pdoLocal->beginTransaction();
$stmtInsert = $pdoLocal->prepare('INSERT INTO tblresponses_string (strResponses, intSurveyID) VALUES (:strResponses, :intSurveyID)');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$stmtInsert->bindValue(':strResponses', $row['strResponses']);
$stmtInsert->bindValue(':intSurveyID', $surveyID);
$stmtInsert->execute();
}
$pdoLocal->commit();
I get the same error on the first bind.
I guess this is the same problem in that the first statement to get executed is beginTransaction and the PDO connection closes afterwards.
As mentioned this all works fine through Apache.
All help gratefully received.
Your speculations are wrong.
If PHP were indeed dropping a connection, you'd had an error not on bindValue call but on the line where the very PDO connection is used, so, the error would be
Call to member function prepare() on a non-object
So, the problem is not with connection but with query. Set PDO in error mode:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
then see the error message and then either fix it or ask another question regarding this particular error.
Here's PHP code that I'm using:
$query="select * from `myTable` where `email`='$email' limit 0,1";
if(empty($conn))
{
echo "not connected".PHP_EOL;
}
$result = mysql_query($query,$conn);
$row = mysql_fetch_array($result);
if(empty($row))
{
....
When the query is executed in phpmyadmin, I get a single row selected.
However, when I execute the code in php, the row is always empty.
The same goes for several other queries that I've tried to execute. mysql_query always fails.
What could be wrong?
I do not feel there is enough of the code to see what is going on. But based on just what you are showing us, after you get the $result and assign it to $row you have a if statement
if(empty($row)) {...doing something secret...}
which means if something was returned like the row you are expecting NOTHING would happen because (empty($row)) would be false and not execute.
Try this using PDO:
<?php
$email = "example#example.com";
try {
//Instantiate PDO connection
$conn = new PDO("mysql:host=localhost;dbname=db_name", "user", "pass");
//Make PDO errors to throw exceptions, which are easier to handle
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//Make PDO to not emulate prepares, which adds to security
$conn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$query = <<<MySQL
SELECT *
FROM `myTable`
WHERE `email`=:email
LIMIT 0,1;
MySQL;
//Prepare the statement
$stmt = $conn->prepare($query);
$stmt->bindParam(":email", $email, PDO::PARAM_STR);
$stmt->execute();
//Work with results
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
//Do stuff with $row
}
}
catch (PDOException $e) {
//Catch any PDOExceptions errors that were thrown during the operation
die("An error has occurred in the database: " . $e->getMessage());
}
Using mysql_* functions is highly discouraged. It's a guarantee to produce broken code. Please learn PDO or MySQLi from the links in the comment I gave you, and use those instead.
First, confirm $email's value. Echo it right before defining $query to make sure it's what you think it is.
If you've already done that, then you know that's the problem--instead, it's likely that your link identifier $conn is the problem. Instead of using a link identifier, try leaving the second parameter of your query empty, and instead run mysql_connect() at the beginning of your script. That's the best way to do things 99.5% of the time.
See: http://php.net/manual/en/function.mysql-connect.php
I want to select a MySQL database to use after a PHP PDO object has already been created. How do I do this?
// create PDO object and connect to MySQL
$dbh = new PDO( 'mysql:host=localhost;', 'name', 'pass' );
// create a database named 'database_name'
// select the database we just created ( this does not work )
$dbh->select_db( 'database_name' );
Is there a PDO equivalent to mysqli::select_db?
Perhaps I'm trying to use PDO improperly? Please help or explain.
EDIT
Should I not be using PDO to create new databases? I understand that the majority of benefits from using PDO are lost on a rarely used operation that does not insert data like CREATE DATABASE, but it seems strange to have to use a different connection to create the database, then create a PDO connection to make other calls.
Typically you would specify the database in the DSN when you connect. But if you're creating a new database, obviously you can't specify that database the DSN before you create it.
You can change your default database with the USE statement:
$dbh = new PDO("mysql:host=...;dbname=mysql", ...);
$dbh->query("create database newdatabase");
$dbh->query("use newdatabase");
Subsequent CREATE TABLE statements will be created in your newdatabase.
Re comment from #Mike:
When you switch databases like that it appears to force PDO to emulate prepared statements. Setting PDO::ATTR_EMULATE_PREPARES to false and then trying to use another database will fail.
I just did some tests and I don't see that happening. Changing the database only happens on the server, and it does not change anything about PDO's configuration in the client. Here's an example:
<?php
// connect to database
try {
$pdo = new PDO('mysql:host=huey;dbname=test', 'root', 'root');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $err) {
die($err->getMessage());
}
$stmt = $pdo->prepare("select * from foo WHERE i = :i");
$result = $stmt->execute(array("i"=>123));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
$pdo->exec("use test2");
$stmt = $pdo->prepare("select * from foo2 WHERE i = :i AND i = :i");
$result = $stmt->execute(array("i"=>456));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));
If what you're saying is true, then this should work without error. PDO can use a given named parameter more than once only if PDO::ATTR_EMULATE_PREPARES is true. So if you're saying that this attribute is set to true as a side effect of changing databases, then it should work.
But it doesn't work -- it gets an error "Invalid parameter number" which indicates that non-emulated prepared statements remains in effect.
You should be setting the database when you create the PDO object. An example (from here)
<?php
$hostname = "localhost";
$username = "your_username";
$password = "your_password";
try {
$dbh = new PDO("mysql:host=$hostname;dbname=mysql", $username, $password);
echo "Connected to database"; // check for connection
}
catch(PDOException $e)
{
echo $e->getMessage();
}
?>
Alternatively, you can select a MySQL database to use after a PHP PDO object has already been created as below:
With USE STATEMENT. But remember here USE STATEMENT is mysql command
try
{
$conn = new PDO("mysql:host=$servername;", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$conn->exec("use databasename");
//application logic
}
catch(PDOException $e)
{
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
I hope my code is helpful for requested
As far as I know, you have to create a new object for each connection. You can always extend the PDO class with a method which connects to multiple databases. And then use it as you like:
public function pickDatabase($db) {
if($db == 'main') {
return $this->db['main']; //instance of PDO object
else
return $this->db['secondary']; //another instance of PDO object
}
and use it like $yourclass->pickDatabase('main')->fetchAll('your stuff');
The server is running PHP 5.2.8. PDO has mysql 5.1.30 drivers installed.
Alright, so I am trying to figure out some PDO ( and this is just killing me. When I run the code below, I get the expected results, no problem.
However, whenever I try to add more than one column (or *) to the SELECT, there is no reply from the query - no results whatsoever. I have tried everything - I know it must be something simple. Any suggestions as to why more than one column fails to return any rows?
$hostname = "localhost";
$dbname = "dbname";
$username = "username";
$password = "password";
try {
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
/*** echo a message saying we have connected ***/
echo 'Connected to database<br />';
/*** The SQL SELECT statement ***/
$sql = "SELECT LastName FROM staff";
foreach ($dbh->query($sql) as $row) {
echo $row['LastName'] . '<br />';
}
/*** close the database connection ***/
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
Again, if I try to add columns in the statement stored in $sql to anything other than a single column, I get bupkis. For example:
SELECT FirstName, LastName FROM staff
returns zero results. Both columns exist - if requested separately, they return expected results. When combined, the query takes quite some time, then returns nothing.
No exception is caught by the catch block.
I think you have a number of issues here, mostly in your code that handles reading the values returned by the query. I have taken the liberty of changing a few things and rewriting this to use prepare statements, which is a function that PDO provides that you should take advantage of.
On prepare statements:
Why use them: http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
PHP PDO doc: http://php.net/manual/en/pdo.prepare.php
Here is the core code:
try {
//open database
$dbh = new PDO("mysql:host=$hostname;dbname=$dbname", $username, $password);
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
//define sql query
$sql = "SELECT LastName FROM staff";
//prepare the query for execution
$qresult = $dbh->prepare($sql);
//insert code below to handle parameters to the sql query here
//execute the query
$qresult->execute();
//fetch the results
foreach ($qresult->fetch(PDO::FETCH_ASSOC) as $row)
{
echo $row['LastName'] . '<br />';
}
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "<br/>";
die();
}
$qresult = null; //close the result set
$dbh = null; //close the database
Note, that I have replaced the call to query() with a couple of lines that call prepare() then execute(). You can then easily insert the following lines in between the prepare() and execute() calls to handle passing parameterized queries. This will help reduce chances of sql injection.
I have also changed the way you are accessing the retirned valued by specifying that I want them returned as and associative array, PDO::FETCH_ASSOC. This will get you a result set that you can iterate through like you would have using the old mysql interfaces.
If your query was a parameterized query like:
$sql="SELECT LastName FROM staff WHERE LastName=':lastname'";
where :lastname is the parameter.
Here is the code you would insert at the comment to handle this, (this code will handle multiple parameters. Simply add additional elements to the $param array):
//bind parameters to the prepared statement
$param = array(':lastname'=>'Jones');
foreach ($param as $key => $value) {
$qresult->bindValue($key,$value);
}
Make sure you separate the columns in the SELECT with a comma (space on either side of the comma is okay, but not required). If you want to select all columns, have only a * with no other characters.