PostgreSQL PHP PDO выполняет зависание, когда подготовленный запрос пропускает поле NOT NULL - PullRequest
0 голосов
/ 12 сентября 2018

Используя PostgreSQL 9.6 и PHP 7.2, я создаю соединение PDO, готовлю запрос INSERT, связываю параметры, затем выполняю подготовленный запрос.У меня ATTR_ERRMODE установлено значение ERRMODE_EXCEPTION, и фактически он может вызвать исключение при выполнении, если, например, подготовленный запрос имеет 4 параметра, но я ограничен только 3.

Ноесли мой подготовленный запрос не содержит поле с ограничением NOT NULL, то выполнение будет зависать, возможно, на 20 секунд, а затем в браузере отобразится «соединение было сброшено».В журнале Postgres написано:

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.

Эти 4 записи журнала повторяются в общей сложности 10 раз.

Я понимаю, что эта ситуация действительно является проблемой программирования - запрос должен соответствовать требованиямдизайна базы данных.Но мне бы очень хотелось, чтобы драйвер Postgres PDO объяснил мне, в чем была ошибка, а не копался в журналах.


Пример кода

/*

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
        }

PostgreSQLlog (последовательность повторяется 10 раз)

 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.

Ответы [ 3 ]

0 голосов
/ 12 сентября 2018

Я думаю, вам нужно поместить оператор подготовки и связать код параметра в блок try.Надеюсь, что это решит проблему.

0 голосов
/ 13 сентября 2018

Пожалуйста, найдите код, который я использовал.

$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();
}

Вы можете попробовать с этим кодом. Как я получаю ниже ошибка при вставке нуля в ненулевой столбец.

SQLSTATE [23502]: нарушение не нулевое: 7 ОШИБКА: нулевое значение в столбце "*******" нарушает ограничение не нулевое ДЕТАЛИ: В ошибочном ряду содержится (null, 2709651, 2018-09-13 12: 07: 03.356125, тест).

И эта ошибка связана с обработкой исключений.

0 голосов
/ 12 сентября 2018

Итак, вы пытаетесь добавить данные со значением NULL для поля с ограничением NOT NULL. Вам нужно либо определить значение по умолчанию в Postgresql для столбца «полное имя», либо сделать его NULL-совместимым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...