Why Does This Pdo Statement Silently Fail

Why does this PDO statement silently fail?

TL;DR

  1. Always have set PDO::ATTR_ERRMODE to PDO::ERRMODE_EXCEPTION in your PDO connection code. It will let the database tell you what the actual problem is, be it with query, server, database or whatever.
  2. Always replace every PHP variable in the SQL query with a question mark, and execute the query using prepared statement. It will help to avoid syntax errors of all sorts.

Explanation

Sometimes your PDO code produces an error like Call to a member function execute() or similar. Or even without any error but the query doesn't work all the same. It means that your query failed to execute.

Every time a query fails, MySQL has an error message that explains the reason. Unfortunately, by default such errors are not transferred to PHP, and all you have is a silence or a cryptic error message mentioned above. Hence it is very important to configure PHP and PDO to report you MySQL errors. And once you get the error message, it will be a no-brainer to fix the issue.

In order to get the detailed information about the problem, either put the following line in your code right after connect

$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

(where $dbh is the name of your PDO instance variable) or - better - add this parameter as a connection option. After that all database errors will be translated into PDO exceptions which, if left alone, would act just as regular PHP errors.

After getting the error message, you have to read and comprehend it. It sounds too obvious, but learners often overlook the meaning of the error message. Yet most of time it explains the problem pretty straightforward:

  • Say, if it says that a particular table doesn't exist, you have to check spelling, typos, letter case. Also you have to make sure that your PHP script connects to a correct database
  • Or, if it says there is an error in the SQL syntax, then you have to examine your SQL. And the problem spot is right before the query part cited in the error message.

You have to also trust the error message. If it says that number of tokens doesn't match the number of bound variables then it is so. Same goes for absent tables or columns. Given the choice, whether it's your own mistake or the error message is wrong, always stick to the former. Again it sounds condescending, but hundreds of questions on this very site prove this advice extremely useful.


Note that in order to see PDO errors, you have to be able to see PHP errors in general. To do so, you have to configure PHP depends on the site environment:

  • on a development server it is very handy to have errors right on the screen, for which displaying errors have to be turned on:

      error_reporting(E_ALL);
    ini_set('display_errors',1);
  • while on a live site, all errors have to be logged, but never shown to the client. For this, configure PHP this way:

      error_reporting(E_ALL);
    ini_set('display_errors', 0);
    ini_set('log_errors', 1);

Note that error_reporting should be set to E_ALL all the time.

Also note that despite the common delusion, no try-catch have to be used for the error reporting. PHP will report you PDO errors already, and in a way better form. An uncaught exception is very good for development, yet if you want to show a customized error page, still don't use try catch for this, but just set a custom error handler. In a nutshell, you don't have to treat PDO errors as something special but regard them as any other error in your code.

P.S.

Sometimes there is no error but no results either. Then it means, there is no data to match your criteria. So you have to admit this fact, even if you can swear the data and the criteria are all right. They are not. You have to check them again. I've short answer that would help you to pinpoint the matching issue, Having issue with matching rows in the database using PDO. Just follow this instruction, and the linked tutorial step by step and either have your problem solved or have an answerable question for Stack Overflow.

PDO INSERT statement silently failing

You could try and print internal error information, in case exceptions aren't actually being thrown:

// http://php.net/manual/en/pdostatement.errorinfo.php
$error = $query->errorInfo();

// see if anything is output here
print_r($error);

You also mentioned in a comment that is was erroring out before the execute() call. It might be because you are using all lowercase names for bindparam().

http://php.net/manual/en/pdostatement.bindparam.php

Try changing your parameter binding to this:

$query->bindParam(':status', $status);
$query->bindParam(':system', $system);
$query->bindParam(':first_name', $first_name);
$query->bindParam(':last_name', $last_name);
$query->bindParam(':primary_num', $primary_num);

Or better yet; remove the above lines and set them in the execute() call:

$query->execute([
'status' => $status,
'first_name' => $first_name,
'last_name' => $last_name,
'primary_num' => $primary_num,
]);

If the above information doesn't help, can you make sure you have error reporting enabled? Taken from the instructions on this answer, you can do so like this:

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

PDO prepare silently fails

My bets are on: $GLOBALS['db'] is not set or not an instance of pdo (anymore?) and therefor a PHP Fatal error: Call to a member function prepare() on a non-object occurs and php bails out.

$sql = 'REPLACE INTO sessions SET id=:id, access=:access, data=:data';
logger('This is the last line in this function that appears in the log.');
if ( !isset($GLOBALS['db']) ) {
logger('there is no globals[db]');
return;
}
else if ( !is_object($GLOBALS['db']) ) {
logger('globals[db] is not an object');
return;
}
else if ( !($GLOBALS['db'] instanceof PDO) ) {
logger('globals[db] is not a PDO object');
return;
}
else {
logger('globals[db] seems ok');
}

$stmt = $GLOBALS['db']->prepare($sql);
logger('This never gets logged! :(');

This PDO prepared statement returns false but does not throw an error

I'm pretty sure that MySQL chokes on the desc field name - it is a reserved word. You'd have to put it into "`" quotes or, better, change the field name.

As for error reporting, use the errorInfo method. You can make PDO actually output the result of a failed query in the exception, but the default behaviour - I think - is to throw an exception only if the query can't be made at all, but it doesn't fail if the query is faulty.

Is there a reason my execute command for PDO isn't working?

i have tested your code the error occurs because u have a space between the dbname and the =. A semicolon after the DBNAME is also missing (it is not needed).

class Database{
private function connect()
{
$string = DBDRIVER . ":host=" .DBHOST.";dbname=".DBNAME.";";
if ($conn = new PDO($string, DBUSER, DBPASS)) {
return $conn;
} else {
die("Could not connect to database");
}
}

Now it works for me.

i am using this connection class for a long time, maybe you want to use it.

class Connection{

private const CONNECTION = [
"Host" => "",
"User" => "",
"Password" => "",
"Databasename" => ""
];

/**
* Includes the pdo connection.
* @var \PDO|null
*/
private \PDO|null $PDO = null;

/**
* Includes the already called instance.
* @var Connection|null
*/
private static self|null $Connection = null;

/**
* Creates the DB connection and sets it to the class.
* @return void
* @throws Exception
*/
private function __construct()
{
$Connection_str = 'mysql:';
$Connection_str .= 'host=' . self::CONNECTION["Host"] . ';';
$Connection_str .= 'dbname=' . self::CONNECTION["Databasename"] . ';';
$Connection_str .= 'charset=utf8mb4';
$this->PDO = new \PDO($Connection_str, self::CONNECTION["User"], self::CONNECTION["Password"]);
$this->PDO->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->PDO->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false);
$this->PDO->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
}

/**
* Returns the static DB connection instance.
* @return Connection
* @throws Exception
*/
public static function get(): Connection
{
return !isset(self::$Connection) ? self::$Connection = new self : self::$Connection;
}

/**
* Returns the PDO instance.
* @return PDO
* @throws Exception
*/
public function getPDO(): \PDO
{
return $this->PDO;
}
}

You can use the connection class using the following code:

$SQLString = "select * from users";
$Data = [

];
$Query = Connection::get()->getPDO()->prepare($SQLString);
$Query->execute($Data);
$Data = $Query->fetchAll();

PDO error: $pdo-prepare()-execute() throws err Call to a member function fetch() on boolean

You need a PDOStatement to fetch, execute only returns true or false. You should only execute the PDOStatement. That will give you back a result object you can fetch or an error. For PDO error handling see My PDO Statement doesn't work.

$stmt = $pdo->prepare('select timezone from wo_users where user_id=?');
$stmt->execute(array($wo['user']['user_id']));
while($row = $stmt->fetch()){
var_dump($row);
die;
}

As you can see from the manual query works because:

PDO::query() returns a PDOStatement object, or FALSE on failure.

where as execute:

Returns TRUE on success or FALSE on failure.

the prepare is what we need:

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

and fetch (this one is the description, not the return):

Fetches a row from a result set associated with a PDOStatement object

CREATE EVENT statement not working with PDO?

The section on prepared statements in mysql manual contains the list of SQL statements that you use in a prepared statement. CREATE EVENT statement is not included in this list, so you cannot use it as a prepared statement.

You have to create the sql statement via string concatenation and execute it as such. You must add further checks to ensure that this will not cause an sql injection vulnerability.



Related Topics



Leave a reply



Submit