0

Using PostgreSQL 9.6 and PHP 7.2, I am creating a PDO connection, preparing an INSERT query, binding the parameters, then executing the prepared query. I have ATTR_ERRMODE set to ERRMODE_EXCEPTION, and in fact can cause exceptions to be thrown by the execute if, for example, the prepared query has 4 parameters, but I’ve only bound 3.

But if my prepared query doesn’t include a field with a NOT NULL constraint, then the execute hangs for maybe 20 seconds, then the browser displays “the connection was reset”. The Postgres log says:

ERROR:  null value in column "fullname" violates not-null constraint
DETAIL:  Failing row contains (345, fredf, fredf@bedrock.net, yabadabadoo, null, Bedrock, none, user).
STATEMENT:  INSERT INTO users (username, password, location, description, email, role) VALUES ($1, $2, $3, $4, $5, $6)
LOG:  could not receive data from client: An existing connection was forcibly closed by the remote host.

These 4 log entries repeat a total of 10 times.

I understand this situation is really a programming issue -- the query should be consistent with the requirements of the database design. But I’d really like to coax the Postgres PDO driver into telling me what the error was, rather than have to go dig through logs.


Sample code

/*

Sample code to demonstrate failure of prepared query execute()
to throw an exception when the prepared query omits a field
with a NOT NULL constraint.

CREATE TABLE users (
  id                SERIAL PRIMARY KEY,
  username      varchar(50) NOT NULL,
  email           varchar(100) NOT NULL,
  password      varchar(255) NOT NULL,
  fullname      varchar(100) NOT NULL,
  location      varchar(100) NOT NULL,
  description text NOT NULL,
  role            varchar(50) NOT NULL DEFAULT ''
);

*/
    $host   = "localhost";  
    $user   = "postgres";  
    $pass   = "password";  
    $dbname = "database";  
    /**
     * Initialize the PDO connection. 
     */
        $dsn = 'pgsql:host=' . $host . ';dbname=' . $dbname;
        $options = [
            PDO::ATTR_PERSISTENT => true,  
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION  
            ]; 
        try {  
            $handler = new PDO($dsn, $user, $pass, $options);  
        } catch (PDOException $e) {  
            echo $e->getMessage();
            die();  
        } 

     /**
      * Demonstrate failure of execute() to return an error or throw an exception
      * Error condition omits the fullname field from the INSERT query, which has a 
      * "not null" constraint.
      */
        $demonstrateProblem = 1;

        $badQuery = "INSERT INTO users (username, password, location, description, email, role) " . 
                    "VALUES (:username, :password, :location, :description, :email, :role)";

        $goodQuery = "INSERT INTO users (username, password, fullname, location, description, email, role) " . 
                    "VALUES (:username, :password, :fullname, :location, :description, :email, :role)";

        if ($demonstrateProblem == 1) {
            $query = $badQuery;
        } else  {
            $query = $goodQuery;
        }

        $stmt = $handler->prepare($query);  
        if (!$stmt) {
            echo "Error in prepare, errorInfo():<br>";
            print_r($handler->errorInfo());
        }
    /**
     * Bind the variables
     */
        $username   = "fredf";
        $password   = "yabadabadoo";
        $fullname   = "Fred Flintstone";
        $location   = "Bedrock";
        $description = "none";
        $email      = "fredf@bedrock.net";
        $role       = "user";

        $stmt->bindParam(':username', $username);
        $stmt->bindParam(':password', $password);
        if ($demonstrateProblem == 0) {
            $stmt->bindParam(':fullname', $fullname);
        } else {
            // nothing to do, :fullname is not in the prepared query!
        }
        $stmt->bindParam(':location', $location);
        $stmt->bindParam(':description', $description);
        $stmt->bindParam(':email', $email);
        $stmt->bindParam(':role', $role);
    /**
     * Execute a prepared statement.
     */
        echo "Executing prepared query...<br>";
        try {
            $res = $stmt->execute(); // <-- this statement hangs when the query prepare is bad.
            if ($res) {
                echo "execute returns true<br> ";
            } else {
                echo "execute returns false<br> ";               
            }
        } catch (PDOException $e) {  
            echo "execute error " . $e->getMessage();  // <-- this never appears
        }

PostgreSQL log (sequence repeats 10 times)

 ERROR:  null value in column "fullname" violates not-null constraint
 DETAIL:  Failing row contains (345, fredf, fredf@bedrock.net, yabadabadoo, null, Bedrock, none, user).
 STATEMENT:  INSERT INTO users (username, password, location, description, email, role) VALUES ($1, $2, $3, $4, $5, $6)
 LOG:  could not receive data from client: An existing connection was forcibly closed by the remote host.
Parfait
  • 104,375
  • 17
  • 94
  • 125
abh
  • 111
  • 7
  • Are you wrapping your SQL call in PHP with `try ... catch` to catch exceptions? Surely you can abbreviate your PHP code block and not need the 100 lines. – Parfait Sep 12 '18 at 01:23
  • yes, and the exception handler works perfectly for other errors such as when the query contains 4 parameters, but only 3 are bound. I'll see if I can shorten the code, but can't do that until the morning, thanks. – abh Sep 12 '18 at 02:09
  • 1
    How are you running this? Are you using a framework to run this? Via web? Try running at command line offline. – Parfait Sep 12 '18 at 19:14
  • I'm running it from a local (Windows 10) install of Apache24. The code is based on small, demo I found on github, not a framework. You're idea of running from a cmd line is an excellent one, and in fact it ~does~ throw the exception running that way. So maybe this is something wrong in my Apache configuration -- LMK if you have any ideas? – abh Sep 12 '18 at 21:04
  • 1
    How are you calling the PHP script while on Apache? Navigating to its webpage? And what do you mean by hanging? If you are talking about a blank white page that may mean code after your error attempted to run. Check the apache error logs for any message. Try adding an `exit` after echoing the message in `catch`. – Parfait Sep 12 '18 at 21:27
  • I’m calling it by browsing to localhost/test.php. In the Apache log, I’m getting “child process nnn exited with status 3221225477 – Restarting”, and there are numerous hits on a search for that error code, for example: [link](https://stackoverflow.com/questions/1138269/apache-error-notice-parent-child-process-exited-with-status-3221225477-res) So far none of them are working. I’ll continue to pursue this and will come back and post a solution if I find one that works for me, but now that I know the problem is more of an Apache problem then Posgres or PDO, I’m content to move on. – abh Sep 13 '18 at 00:34

3 Answers3

1

Well, you're trying to add data with NULL value for field with NOT NULL constraint on it. You either need to define default value in the Postgresql for "fullname" column, or make it NULL-able.

  • Yes, my post clearly states that this is a programming issue, however the question is: why doesn't an exception trigger? I've added the source code, if you have any ideas, that would be great. – abh Sep 12 '18 at 11:20
  • Maybe upgrading to PostgreSQL 10 would resolve the problem? – Tomasz Zadora Sep 25 '18 at 16:37
  • I plan on giving that a try. My immediate problem was resolved by reviewing the apache logs to confirm the lack of the exception wasn't due to a bug in my PHP code. But moving to 10 probably makes sense for a number of reasons anyway. Thanks! – abh Sep 26 '18 at 17:50
0

I think, You need to put prepare statement & bind Parameter code into try block. Hope it will solve the issue.

Sachin Raghav
  • 452
  • 5
  • 14
  • Thanks Sachin, I had already tried that idea, but it doesn't help. – abh Sep 12 '18 at 21:05
  • I have used the same code you are using. And now i am getting Exception. I am attaching the code which i have used in another answer. – Sachin Raghav Sep 13 '18 at 06:39
0

Please find code which i used.

$host   = "";             
$user   = "";     
$pass   = "";         
$dbname = "";        
/**
 * Initialize the PDO connection. 
 */
    $dsn = 'pgsql:host=' . $host . ';dbname=' . $dbname;
    $options = [
        PDO::ATTR_PERSISTENT => true,
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        ];
    try {
        $handler = new PDO($dsn, $user, $pass, $options);
    } catch (PDOException $e) {
        echo $e->getMessage();
        die();
    }


try{
$query = "insert into ********  values(null, 2709651, NOW(), 'test')";             
$stmt = $handler->prepare($query);
$res = $stmt->execute();
if ($res) {
            echo "execute returns true<br> ";
        } else {
            echo "execute returns false<br> ";
        }
}catch(PDOException $e){
echo $e->getMessage();
}

You can try with this code. As i am getting below error while inserting null into not-null column.

SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "*******" violates not-null constraint DETAIL: Failing row contains (null, 2709651, 2018-09-13 12:07:03.356125, test).

And this error is from exception handeling.

Sachin Raghav
  • 452
  • 5
  • 14
  • Thanks. After further investigation, the problem I'm having seems to be related to my Apache configuration, not to the PHP code. Apache is throwing an exception of its own handling the error from Postgres. – abh Sep 13 '18 at 11:25