Pg end copy: примеры (PHP)
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 или чтении из внешних источников построчно.
Аналоги в других языках программирования
Используется метод 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()Используется потоковая передача через 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Команда \copy в терминале. Отличие: \copy выполняется на стороне клиента, а SQL 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-файла без полной загрузки в память.
<?
$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 выполняется внутри транзакции для обеспечения целостности данных.
<?
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();
}
?>Динамическое создание и отправка данных, например, из генератора.
<?
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).
<?
// Предполагается, что бинарные данные уже подготовлены
pg_query($conn, "COPY bin_table FROM STDIN WITH (FORMAT BINARY)");
pg_put_line($conn, $binaryData);
// Важно: в бинарном режиме данные передаются не через текстовые строки
// Этот пример концептуален, реальная реализация сложнее
pg_end_copy($conn);
?>