Pg end copy: примеры (PHP)

Работа с pg_end_copy в PHP 8: примеры и альтернативы
Раздел: Базы данных (PostgreSQL)
pg_end_copy(PgSql\Connection $connection): bool

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

Назначение и применение

Функция pg_end_copy в PHP используется для завершения операции копирования данных из PHP в базу данных PostgreSQL, которая была инициирована с помощью команды COPY ... FROM STDIN и функций pg_put_line или pg_copy_from. Эта функция синхронизирует состояние соединения с PostgreSQL после передачи данных, что является обязательным шагом.

Аргументы функции

Функция принимает один необязательный аргумент:

  • $connection (ресурс подключения к PostgreSQL) — идентификатор соединения с базой данных. Если аргумент не указан, используется последнее соединение, открытое функциями pg_connect или pg_pconnect.

Возвращаемое значение: true в случае успешного завершения операции копирования, false — при возникновении ошибки.

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

Базовый пример копирования данных

Пример передачи строк данных в таблицу с последующим завершением операции:

<?
$conn = pg_connect("host=localhost dbname=test user=postgres");
// Инициируем копирование
pg_query($conn, "COPY my_table FROM STDIN");
// Передаем данные
pg_put_line($conn, "1\tЗначение 1\n");
pg_put_line($conn, "2\tЗначение 2\n");
// Завершаем операцию
$result = pg_end_copy($conn);
if ($result) {
    echo "Данные успешно скопированы";
}
?>
Данные успешно скопированы
Пример с проверкой ошибок
<?
$conn = pg_connect("host=localhost dbname=test");
if (!pg_query($conn, "COPY my_table FROM STDIN")) {
    die("Ошибка начала копирования");
}
pg_put_line($conn, "3\tТест\n");
if (!pg_end_copy($conn)) {
    echo "Ошибка завершения копирования: ". pg_last_error($conn);
}
?>
Ошибка завершения копирования: ERROR:  syntax error at or near "COPY"

Альтернативные функции в PHP

Для работы с операцией COPY в PHP существуют и другие функции:

Копирует данные из таблицы в массив. Удобна для экспорта данных без промежуточных файлов.

Копирует данные из массива в таблицу. Эта функция инкапсулирует весь процесс копирования, включая завершение, что делает ее более удобной для простых случаев, чем ручное использование pg_put_line и pg_end_copy.

Выбор функции: pg_copy_from предпочтительнее для загрузки данных из PHP-массивов. pg_end_copy необходима при потоковой передаче данных через pg_put_line или чтении из внешних источников построчно.

Аналоги в других языках программирования

Python (psycopg2)

Используется метод copy_from объекта cursor. Операция автоматически завершается.

import psycopg2
conn = psycopg2.connect("dbname=test")
cur = conn.cursor()
cur.copy_from(open('data.csv'), 'my_table', sep='\t')
conn.commit()
Node.js (pg)

Используется потоковая передача через COPY FROM STDIN.

const { Client } = require('pg');
const client = new Client();
await client.connect();
const stream = client.query("COPY my_table FROM STDIN");
stream.write("1\tValue1\n");
stream.write("2\tValue2\n");
stream.end(); // Выполняет роль pg_end_copy
PostgreSQL (psql)

Команда \copy в терминале. Отличие: \copy выполняется на стороне клиента, а SQL COPY — на стороне сервера.

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

Отсутствие активной операции COPY

Ошибка возникает при вызове pg_end_copy без предварительного начала операции.

<?
$conn = pg_connect("...");
$result = pg_end_copy($conn); // Предупреждение и false
var_dump($result);
?>
Warning: pg_end_copy(): No copy in progress in ...
bool(false)
Потеря соединения во время копирования

Если соединение разрывается до вызова pg_end_copy, операция завершается с ошибкой.

Несоответствие формата данных

Передача данных в формате, отличном от ожидаемого таблицей, приводит к ошибке на стороне PostgreSQL, которую можно получить через pg_last_error после вызова pg_end_copy.

Изменения в последних версиях PHP

В PHP 8 функция pg_end_copy не претерпела значительных изменений в сигнатуре или поведении. Основные изменения, связанные с расширением PostgreSQL (pgsql), в PHP 8 касаются улучшения согласованности типов и обработки ошибок. Важно отметить, что в PHP 8 многие функции расширения pgsql теперь выбрасывают исключения в случае ошибок, если не используется режим подавления ошибок с @. Однако pg_end_copy по-прежнему возвращает false при ошибке, и для получения деталей необходимо использовать pg_last_error.

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

Потоковое копирование из файла

Эффективная загрузка большого CSV-файла без полной загрузки в память.

Пример php
<?
$conn = pg_connect("...");
pg_query($conn, "COPY large_table FROM STDIN WITH (FORMAT CSV)");
$handle = fopen('huge_data.csv', 'r');
while (($line = fgets($handle)) !== false) {
    pg_put_line($conn, $line);
}
pg_end_copy($conn);
fclose($handle);
?>
Копирование с использованием транзакций

Операция COPY выполняется внутри транзакции для обеспечения целостности данных.

Пример php
<?
pg_query($conn, "BEGIN");
try {
    pg_query($conn, "COPY log_table FROM STDIN");
    pg_put_line($conn, "...");
    if (!pg_end_copy($conn)) {
        throw new Exception(pg_last_error($conn));
    }
    pg_query($conn, "COMMIT");
} catch (Exception $e) {
    pg_query($conn, "ROLLBACK");
    echo "Ошибка: ". $e->getMessage();
}
?>
Генерация данных на лету

Динамическое создание и отправка данных, например, из генератора.

Пример php
<?
function generateData() {
    for ($i = 0; $i < 1000; $i++) {
        yield $i . "\t" . md5($i) . "\n";
    }
}
pg_query($conn, "COPY hash_table FROM STDIN");
foreach (generateData() as $line) {
    pg_put_line($conn, $line);
}
pg_end_copy($conn);
?>
Обработка бинарных данных

Использование бинарного режима COPY (требует предварительной подготовки данных в специальном формате PostgreSQL).

Пример php
<?
// Предполагается, что бинарные данные уже подготовлены
pg_query($conn, "COPY bin_table FROM STDIN WITH (FORMAT BINARY)");
pg_put_line($conn, $binaryData);
// Важно: в бинарном режиме данные передаются не через текстовые строки
// Этот пример концептуален, реальная реализация сложнее
pg_end_copy($conn);
?>

PHP pg_end_copy function comments

En
Pg end copy Sync with PostgreSQL backend