This question already has answers here:
Why does this PDO statement silently fail?
(2 answers)
Closed 5 years ago.
Here is a snippet of my code:
$qry = '
INSERT INTO non-existant-table (id, score)
SELECT id, 40
FROM another-non-existant-table
WHERE description LIKE "%:search_string%"
AND available = "yes"
ON DUPLICATE KEY UPDATE score = score + 40
';
$sth = $this->pdo->prepare($qry);
$sth->execute($data);
print_r($this->pdo->errorInfo());
This should give me an error because the tables don't even exist. All I get however is this:
Array ( [0] => 00000 )
How can I get a better description of the error so I can debug the issue?
Try this instead:
print_r($sth->errorInfo());
Add this before your prepare:
$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
This will change the PDO error reporting type and cause it to emit a warning whenever there is a PDO error. It should help you track it down, although your errorInfo should have bet set.
Old thread, but maybe my answer will help someone. I resolved by executing the query first, then setting an errors variable, then checking if that errors variable array is empty. see simplified example:
$field1 = 'foo';
$field2 = 'bar';
$insert_QUERY = $db->prepare("INSERT INTO table bogus(field1, field2) VALUES (:field1, :field2)");
$insert_QUERY->bindParam(':field1', $field1);
$insert_QUERY->bindParam(':field2', $field2);
$insert_QUERY->execute();
$databaseErrors = $insert_QUERY->errorInfo();
if( !empty($databaseErrors) ){
$errorInfo = print_r($databaseErrors, true); # true flag returns val rather than print
$errorLogMsg = "error info: $errorInfo"; # do what you wish with this var, write to log file etc...
/*
$errorLogMsg will return something like:
error info:
Array(
[0] => 42000
[1] => 1064
[2] => 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 'table bogus(field1, field2) VALUES ('bar', NULL)' at line 1
)
*/
} else {
# no SQL errors.
}
Maybe this post is too old but it may help as a suggestion for someone looking around on this :
Instead of using:
print_r($this->pdo->errorInfo());
Use PHP implode() function:
echo 'Error occurred:'.implode(":",$this->pdo->errorInfo());
This should print the error code, detailed error information etc. that you would usually get if you were using some SQL User interface.
Hope it helps
From the manual:
If the database server successfully
prepares the statement, PDO::prepare()
returns a PDOStatement object. If the
database server cannot successfully
prepare the statement, PDO::prepare()
returns FALSE or emits PDOException
(depending on error handling).
The prepare statement likely caused an error because the db would be unable to prepare the statement. Try testing for an error immediately after you prepare your query and before you execute it.
$qry = '
INSERT INTO non-existant-table (id, score)
SELECT id, 40
FROM another-non-existant-table
WHERE description LIKE "%:search_string%"
AND available = "yes"
ON DUPLICATE KEY UPDATE score = score + 40
';
$sth = $this->pdo->prepare($qry);
print_r($this->pdo->errorInfo());
Related
This question already has answers here:
Can I bind an array to an IN() condition in a PDO query?
(23 answers)
Closed 7 years ago.
Note: I see this question as a probable serious issue in PDO Drivers. I can pretty much understand the difference between an array and string. So, please consider testing this on your sandbox before Deleting or making duplicate.
$pdo = db()->getInstance();
$sql = "SELECT * FROM clients WHERE client_id IN :clients";
$params = [ ":clients" => "(223,224,225)" ];
$stmt = $pdo->prepare($sql);
try{
$stmt->execute($params);
} catch( \Exception $e){
die("Query Execution Failed" . $e->getMessage());
}
Query Execution FailedSQLSTATE[42000]: Syntax error or access
violation: 1064 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 ''(223,224,225)'' at line 1
The issue here is instead of translating to:
SELECT * FROM clients WHERE client_id IN (223,224,225)
it is translating to:
SELECT * FROM clients WHERE client_id IN '(223,224,225)'
There are no arrays here. I am just providing a parameter clients to replace :clients. Why does it add the quotes around?
First of all, I agree with you (somewhat). It's a issue, not very serious one. Maybe they kept it knowingly. Or, maybe your stupid question has some debate potentials.
Every PDO parameter gets wrapped with quotes. (Personally I think should not be). When you pass the IN string at once, it puts quote around it which fails the query. But, you can do that (put quotes) with individual item. So, pass parameter to each item instead of preparing string before.
Now, to the solution:
$pdo = db()->getInstance();
$sql = "SELECT * FROM clients WHERE client_id IN :clients";
$clients = [223,224,225];
/* You could use bind with ? here. I am just making this with named parameters so that you could echo SQL */
$params = [];
$replacement = [];
foreach ($clients as $key => $value){
$replacement[] = ":client$key";
$params[":client" . $key] = $value;
}
$sql = str_replace(":clients", "(" . implode(",",$replacement) . ")", $sql);
echo $sql;
/* SELECT * FROM clients WHERE client_id IN (:client0,:client1,:client2) */
$stmt = $pdo->prepare($sql);
try{
$stmt->execute($params);
print_pre($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch( \Exception $e){
die("Query Execution Failed" . $e->getMessage());
}
This works like a charm. I tried by creating a dummy clients table. But the thing is your actual SQL now becomes:
SELECT * FROM clients WHERE client_id IN ('223','224','225')
Most people might not give a shit about it but you might lose some performance because the query is converting the id to string with quotes, especially you have a large database, complex queries and prefer integers.
I'm having a bit of trouble with a transaction query. I have 2 tables,
"subjects" and linking table call "tutorsubjects". I am using a MariaDB version 10.0.21. I have created the following query but I keep getting a "Syntax error or access violation: 1064" error.
public function addSubject($values){
try {
$temp = $this->db->query("
BEGIN;
INSERT INTO subjects
(subject_code, subject_name, subject_grade, subject_description, subject_category)
VALUES (:subject_code, :subject_name, :subject_grade, :subject_description, :subject_category);
SET #last_id = LAST_INSERT_ID();
INSERT INTO tutorsubject
(tutor_id , subject_id)
VALUES (:tutor_id, #last_id);
COMMIT;",$values);
return $temp;
} catch (DBException $e) {
echo "Error:<br/>" . $e->getMessage();
return null;
} catch (Exception $e) {
echo "Error:<br/>" . $e->getMessage();
return null;
}
}
The following is the values that are parsed through to the query
$array = array("subject_code" => $code,
"subject_name" => $subject_name,
"subject_grade" => $grade,
"subject_description" => $subject_description,
"subject_category" => $subject_category,
"tutor_id"=>$selecttutor);
I get the following error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''reach'.'subjects' ('subject_code', 'subject_name', 'subject_grade', 'subject_de' at line 1
Raw SQL : INSERT INTO 'reach'.'subjects' ('subject_code', 'subject_name', 'subject_grade', 'subject_description', 'subject_category') VALUES (:subject_code,:subject_name,:subject_grade,:subject_description,:subject_category);
My issue is that when I run this query in phpMyAdmin it completes without any issues. I am using a PDO MySQL class found here as the foundation for my DB interactions. I am starting to think that perhaps the class does not directly support transactions?
Any thoughts would be greatly appreciated.
Try having PHP do the work + using PDO transaction methods, values part not tested so you need to make sure its correct:
$this->db->beginTransaction();
$this->db->query("INSERT INTO subjects
(subject_code, subject_name, subject_grade, subject_description, subject_category)
VALUES (:subject_code, :subject_name, :subject_grade, :subject_description, :subject_category)", $values);
$values['last_id'] = $this->db->lastInsertId();
if (empty($values['last_id'])) {
$this->db->rollBack();
} else {
$this->db->query("INSERT INTO tutorsubject
(tutor_id , subject_id)
VALUES (:tutor_id, :last_id)", $values);
$this->db->commit();
}
You should try leaving the COMMIT and BEGIN queries alone.
Try:
// start the transaction
$this->db->query("BEGIN;");
//rest of your queries with db->query() go here
$this->db->query("INSERT INTO subjects
(subject_code, subject_name, subject_grade, subject_description, subject_category)
VALUES (:subject_code, :subject_name, :subject_grade, :subject_description, :subject_category);
SET #last_id = LAST_INSERT_ID();
INSERT INTO tutorsubject
(tutor_id , subject_id)
VALUES (:tutor_id, #last_id);");
//commit
$this->db->query("COMMIT;");
MySQL is trying to execute all these as one query and it doesn't recognise the whole command as separate queries. PhpMyadmin separates them on its own and that's why they run correctly there.
Something is adding apostrophes around database and table names. This is syntactically wrong (unless you have a certain ansi mode turned on). They need to be backtics (`).
This question already has answers here:
Why does this PDO statement silently fail?
(2 answers)
Closed 5 years ago.
Here is a snippet of my code:
$qry = '
INSERT INTO non-existant-table (id, score)
SELECT id, 40
FROM another-non-existant-table
WHERE description LIKE "%:search_string%"
AND available = "yes"
ON DUPLICATE KEY UPDATE score = score + 40
';
$sth = $this->pdo->prepare($qry);
$sth->execute($data);
print_r($this->pdo->errorInfo());
This should give me an error because the tables don't even exist. All I get however is this:
Array ( [0] => 00000 )
How can I get a better description of the error so I can debug the issue?
Try this instead:
print_r($sth->errorInfo());
Add this before your prepare:
$this->pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
This will change the PDO error reporting type and cause it to emit a warning whenever there is a PDO error. It should help you track it down, although your errorInfo should have bet set.
Old thread, but maybe my answer will help someone. I resolved by executing the query first, then setting an errors variable, then checking if that errors variable array is empty. see simplified example:
$field1 = 'foo';
$field2 = 'bar';
$insert_QUERY = $db->prepare("INSERT INTO table bogus(field1, field2) VALUES (:field1, :field2)");
$insert_QUERY->bindParam(':field1', $field1);
$insert_QUERY->bindParam(':field2', $field2);
$insert_QUERY->execute();
$databaseErrors = $insert_QUERY->errorInfo();
if( !empty($databaseErrors) ){
$errorInfo = print_r($databaseErrors, true); # true flag returns val rather than print
$errorLogMsg = "error info: $errorInfo"; # do what you wish with this var, write to log file etc...
/*
$errorLogMsg will return something like:
error info:
Array(
[0] => 42000
[1] => 1064
[2] => 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 'table bogus(field1, field2) VALUES ('bar', NULL)' at line 1
)
*/
} else {
# no SQL errors.
}
Maybe this post is too old but it may help as a suggestion for someone looking around on this :
Instead of using:
print_r($this->pdo->errorInfo());
Use PHP implode() function:
echo 'Error occurred:'.implode(":",$this->pdo->errorInfo());
This should print the error code, detailed error information etc. that you would usually get if you were using some SQL User interface.
Hope it helps
From the manual:
If the database server successfully
prepares the statement, PDO::prepare()
returns a PDOStatement object. If the
database server cannot successfully
prepare the statement, PDO::prepare()
returns FALSE or emits PDOException
(depending on error handling).
The prepare statement likely caused an error because the db would be unable to prepare the statement. Try testing for an error immediately after you prepare your query and before you execute it.
$qry = '
INSERT INTO non-existant-table (id, score)
SELECT id, 40
FROM another-non-existant-table
WHERE description LIKE "%:search_string%"
AND available = "yes"
ON DUPLICATE KEY UPDATE score = score + 40
';
$sth = $this->pdo->prepare($qry);
print_r($this->pdo->errorInfo());
I have code:
$stmt = $db->prepare(" bla bla ");
$stmt->execute();
print_r($db->errorInfo());
This returns: Array ( [0] => 00000 [1] => [2] => )
Why not returned error info ?
The following reports the error correctly:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
if (($stmt = $dbh->prepare(" bla bla ")) === false) {
print_r($dbh->errorInfo());
}
if ($stmt->execute() === false) {
print_r($stmt->errorInfo());
}
Note in the above that parse errors caused during prepare() are reported against $dbh. Whereas even if the prepare() succeeds, then execute() may cause an error, but that error is reported against $stmt.
In the test above, I got the error report immediately after the prepare():
Array
(
[0] => 42000
[1] => 1064
[2] => 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 'bla bla' at line 1
)
But this behavior changes if you use emulated prepares.
When you enable that attribute, the prepare() is virtually a no-op. It just saves the query string in the $stmt, and then the actual prepare of the statement is delayed until you call execute(). So the error, if any, is reported against $stmt whether it happens at prepare time or at execute time.
I tested changing the error-reporting line as follows:
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
// prepare won't report SQL errors, it's virtually a no-op.
if (($stmt = $dbh->prepare(" bla bla ")) === false) {
print_r($dbh->errorInfo());
}
// execute will report errors of parsing or execution.
if ($stmt->execute() === false) {
print_r($stmt->errorInfo());
}
In this case, no error was reported at prepare(), and but I got the same error as above at execute(). Again, you must examine $stmt to get the error after execute().
SQLSTATE 00000 means "Success". Per the PHP documentation:
If the SQLSTATE error code is not set or there is no driver-specific error, the elements following element 0 will be set to NULL.
$data = $mysqli->prepare("SELECT amount FROM items WHERE id=:id");
echo 'forward1';
if(!$data->execute(array(':id' => $id)))
die("error executing".$data->error);
echo '2';
$row = $data->fetch_object();
die('Losing my mind'.$row->amount);
This will only echo "forward1", not "error executing..." or "2". It works with *$mysqli->query". If I add quotes '' to :id in the query, it will echo "forward1error executing".
First, make sure you understand the prepared statements syntax and working model.
As in:
$data = $mysqli->prepare("SELECT amount FROM items WHERE id=(?)");
// THIS ^^ actually "prepares" an object to be used in the statement
$data->bind_param("i",$id)
// ...then you "bind" the parameter for your statement as "i"(nteger)
echo 'forward1';
if(!$data->execute()) // And now you simply run it, with no other args
die("error executing".$data->error);
echo '2';
$row = $data->fetch_object();
die('Loosing my mind'.$row->amount);
I suggest though using something more like
$data->execute() or die("error executing".$data->error);
The main steps of a prepared statement are:
1. Prepare the query with some placeholder values;
2. "Bind" the required number of values to the query;
3. Execute it!
I fail to see why this is relevant in your case, with such a simple query. I also assume you actually need it for something bigger.
Please let me know if I misunderstood your point or code sample.
Oh, and.. have fun! :-)
Turn on your error reporting.
You get a fatal error by accessing the method execute on your mysqli::statement after prepare failed. Check if $data === false before calling execute.
Error message: 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 ':id' at line 1
See this answer to why this error is triggered: MYSQLI::prepare() , error when used placeholder :something
See the PHP manual on how to use mysqli, or use PDO instead.