Pg result error field: примеры (PHP)

Работа с pg_result_error_field: обработка ошибок PostgreSQL в PHP
Раздел: Базы данных (PostgreSQL)
pg_result_error_field(PgSql\Result $result, int $field_code): string|false|null

Описание функции pg_result_error_field

Функция pg_result_error_field() в PHP предназначена для получения конкретных полей из отчета об ошибке, связанной с выполнением запроса PostgreSQL. Она применяется при обработке ошибок в расширении pgsql для детализации проблем, возникающих во время выполнения SQL-запросов.

Аргументы функции
  • $result (обязательный) — ресурс результата запроса, возвращаемый функциями pg_query(), pg_send_query() и подобными.
  • $field_code (обязательный) — целочисленная константа, определяющая запрашиваемое поле ошибки. Доступные константы включают:
    • PGSQL_DIAG_SEVERITY
    • PGSQL_DIAG_SQLSTATE
    • PGSQL_DIAG_MESSAGE_PRIMARY
    • PGSQL_DIAG_MESSAGE_DETAIL
    • PGSQL_DIAG_MESSAGE_HINT
    • PGSQL_DIAG_STATEMENT_POSITION
    • PGSQL_DIAG_INTERNAL_POSITION
    • PGSQL_DIAG_INTERNAL_QUERY
    • PGSQL_DIAG_CONTEXT
    • PGSQL_DIAG_SOURCE_FILE
    • PGSQL_DIAG_SOURCE_LINE
    • PGSQL_DIAG_SOURCE_FUNCTION

Примеры использования pg_result_error_field

Получение кода состояния SQLSTATE
<?
$conn = pg_connect("host=localhost dbname=test");
$result = pg_query($conn, "SELECT * FROM non_existent_table");
if (!$result) {
    $sqlstate = pg_result_error_field($result, PGSQL_DIAG_SQLSTATE);
    echo "SQLSTATE: $sqlstate";
}
?>
SQLSTATE: 42P01
Получение основного сообщения и деталей
<?
$result = pg_query($conn, "INSERT INTO users VALUES (NULL)");
if (!$result) {
    $message = pg_result_error_field($result, PGSQL_DIAG_MESSAGE_PRIMARY);
    $detail = pg_result_error_field($result, PGSQL_DIAG_MESSAGE_DETAIL);
    echo "Сообщение: $message\n";
    echo "Детали: $detail";
}
?>
Сообщение: null value in column "id" violates not-null constraint
Детали: Failing row contains (null).

Похожие функции в PHP

Функция pg_result_error() возвращает полное сообщение об ошибке в виде строки. В отличие от pg_result_error_field(), она не позволяет получить отдельные поля, но полезна для быстрого получения всей информации.

Функция pg_last_error() возвращает последнее сообщение об ошибке для соединения. Она не привязана к конкретному результату запроса, поэтому может использоваться для асинхронных запросов.

Выбор функции

pg_result_error_field() предпочтительнее при необходимости детального разбора ошибки. Для простого логирования подходит pg_result_error(). pg_last_error() применяется для обработки ошибок соединения.

Альтернативы в других языках

Python (psycopg2)

В psycopg2 ошибки представлены объектами исключений с атрибутами, аналогичными полям в PostgreSQL.

import psycopg2
conn = psycopg2.connect("dbname=test")
cur = conn.cursor()
try:
    cur.execute("SELECT * FROM non_existent")
except psycopg2.Error as e:
    print("SQLSTATE:", e.pgcode)
    print("Сообщение:", e.pgerror)
SQLSTATE: 42P01
Сообщение: relation "non_existent" does not exist
JavaScript (Node.js с pg)

В библиотеке pg ошибки передаются в колбэках как объекты с полями.

client.query('SELECT * FROM non_existent', (err, res) => {
    if (err) {
        console.log('Code:', err.code);
        console.log('Message:', err.message);
    }
});
Code: 42P01
Message: relation "non_existent" does not exist

Pg result error field в MySQL

В MySQL для получения деталей ошибки используются функции SHOW ERRORS или свойства объекта ошибки в MySQLi.

$mysqli = new mysqli("localhost", "user", "pass", "test");
$mysqli->query("SELECT * FROM non_existent");
if ($mysqli->errno) {
    echo "Код ошибки: ".$mysqli->errno;
    echo "Сообщение: ".$mysqli->error;
}
Код ошибки: 1146
Сообщение: Table 'test.non_existent' doesn't exist

Типичные ошибки при использовании

Передача некорректного ресурса

Передача нересурсного значения приводит к предупреждению и возврату false.

<?
$value = pg_result_error_field("not_a_resource", PGSQL_DIAG_SQLSTATE);
var_dump($value);
?>
Warning: pg_result_error_field() expects parameter 1 to be resource, string given in ...
bool(false)
Использование после закрытия соединения

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

<?
$conn = pg_connect("...");
$result = pg_query($conn, "SELECT * FROM users");
pg_close($conn);
$error = pg_result_error_field($result, PGSQL_DIAG_SQLSTATE); // Ненадежно
?>
Отсутствие проверки на ошибку

Вызов функции для успешного запроса вернет NULL, что может быть интерпретировано неверно.

<?
$result = pg_query($conn, "SELECT 1"); // Успешный запрос
$error = pg_result_error_field($result, PGSQL_DIAG_SQLSTATE);
var_dump($error);
?>
NULL

Изменения в версиях PHP

PHP 8.0

Тип параметра $result изменен с ресурса (resource) на объект PgSql\Result. Передача ресурса вызывает устаревшее предупреждение.

PHP 8.1

Удалена поддержка передачи ресурса, теперь допускается только объект PgSql\Result.

<?
// PHP 8.0 и выше
$result = pg_query($conn, "SELECT * FROM users");
// $result теперь объект PgSql\Result, а не ресурс
?>

Расширенные примеры использования

Обработка всех полей ошибки
Пример php
<?
$result = pg_query($conn, "SELECT * FROM non_existent");
if (!$result) {
    $fields = [
        PGSQL_DIAG_SEVERITY => 'SEVERITY',
        PGSQL_DIAG_SQLSTATE => 'SQLSTATE',
        PGSQL_DIAG_MESSAGE_PRIMARY => 'MESSAGE_PRIMARY',
        PGSQL_DIAG_MESSAGE_DETAIL => 'MESSAGE_DETAIL',
        PGSQL_DIAG_MESSAGE_HINT => 'MESSAGE_HINT',
        PGSQL_DIAG_STATEMENT_POSITION => 'STATEMENT_POSITION',
        PGSQL_DIAG_INTERNAL_POSITION => 'INTERNAL_POSITION',
        PGSQL_DIAG_INTERNAL_QUERY => 'INTERNAL_QUERY',
        PGSQL_DIAG_CONTEXT => 'CONTEXT',
        PGSQL_DIAG_SOURCE_FILE => 'SOURCE_FILE',
        PGSQL_DIAG_SOURCE_LINE => 'SOURCE_LINE',
        PGSQL_DIAG_SOURCE_FUNCTION => 'SOURCE_FUNCTION'
    ];
    foreach ($fields as $code => $name) {
        $value = pg_result_error_field($result, $code);
        if ($value !== false && $value !== null) {
            echo "$name: $value\n";
        }
    }
}
?>
SEVERITY: ERROR
SQLSTATE: 42P01
MESSAGE_PRIMARY: relation "non_existent" does not exist
STATEMENT_POSITION: 15
Использование с асинхронными запросами
Пример php
<?
pg_send_query($conn, "SELECT * FROM invalid");
while ($result = pg_get_result($conn)) {
    if (pg_result_error($result)) {
        $hint = pg_result_error_field($result, PGSQL_DIAG_MESSAGE_HINT);
        if ($hint) {
            echo "Подсказка: $hint\n";
        }
    }
}
?>
Логирование ошибок с дополнительными данными
Пример php
<?
function log_pg_error($result) {
    $log = [
        'sqlstate' => pg_result_error_field($result, PGSQL_DIAG_SQLSTATE),
        'message' => pg_result_error_field($result, PGSQL_DIAG_MESSAGE_PRIMARY),
        'detail' => pg_result_error_field($result, PGSQL_DIAG_MESSAGE_DETAIL),
        'context' => pg_result_error_field($result, PGSQL_DIAG_CONTEXT),
        'timestamp' => date('Y-m-d H:i:s')
    ];
    file_put_contents('pg_errors.log', json_encode($log)."\n", FILE_APPEND);
}
$result = pg_query($conn, "invalid sql");
if (!$result) {
    log_pg_error($result);
}
?>

PHP pg_result_error_field function comments

En
Pg result error field Returns an individual field of an error report