Signatur
Beschreibung
pg_put_copy_data() überträgt einen Datenblock im COPY-Format an einen PostgreSQL-Server, der zuvor mit einem COPY FROM STDIN-Befehl in den COPY-Modus versetzt wurde. Die Funktion ist Teil des PostgreSQL COPY-Protokolls, das einen hochperformanten Massendatenimport ermöglicht – deutlich schneller als viele einzelne INSERT-Anweisungen.
Der übergebene $data-String muss dem vom Server erwarteten COPY-Format entsprechen (standardmäßig tabulatorgetrennte Felder mit Zeilenumbrüchen als Datensatz-Trenner, oder CSV-Format, je nach dem beim COPY-Befehl angegebenen Format). Jeder Aufruf kann einen oder mehrere vollständige Datensätze oder auch nur einen Teil eines Datensatzes enthalten – der Server puffert die Daten, bis pg_put_copy_end() aufgerufen wird.
Typischerweise wird pg_put_copy_data() in einer Schleife aufgerufen, um große Datenmengen chunkweise zu übertragen. Nach dem letzten Datenblock muss die COPY-Operation zwingend mit pg_put_copy_end() abgeschlossen werden, um dem Server das Ende der Daten zu signalisieren.
- Geeignet für den Import großer CSV- oder tabulatorgetrennter Datensätze
- Deutlich effizienter als Massen-INSERTs bei großen Datenmengen
- Erfordert eine zuvor per
pg_query()gestarteteCOPY ... FROM STDIN-Abfrage
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $connection Pflicht | PgSql\Connection | Eine aktive PostgreSQL-Datenbankverbindung, die zuvor mit pg_connect() oder pg_pconnect() erstellt wurde. |
|
| $data Pflicht | string | Die zu sendenden Daten im COPY-Format des Servers (z. B. tabulatorgetrennte Felder mit \n als Zeilenende oder CSV). Der String darf leer sein. |
Rückgabewert
0 zurück, wenn die Daten erfolgreich gepuffert wurden, 1 wenn die Daten sofort an den Server gesendet wurden, oder false bei einem Fehler (z. B. wenn keine COPY-Operation aktiv ist oder die Verbindung ungültig ist).Beispiele
Massendatenimport mit COPY FROM STDIN
<?php
$conn = pg_connect('host=localhost dbname=testdb user=postgres password=secret');
if (!$conn) {
die('Verbindung fehlgeschlagen');
}
// Tabelle muss existieren: CREATE TABLE personen (id INT, name TEXT, alter INT);
// COPY-Operation starten
$result = pg_query($conn, "COPY personen (id, name, alter) FROM STDIN");
if (!$result) {
die('COPY-Befehl fehlgeschlagen: ' . pg_last_error($conn));
}
// Daten zeilenweise senden (tabulatorgetrennt)
$rows = [
[1, 'Anna Müller', 30],
[2, 'Bernd Schmidt', 45],
[3, 'Clara Weber', 28],
];
foreach ($rows as $row) {
$line = implode("\t", $row) . "\n";
$status = pg_put_copy_data($conn, $line);
if ($status === false) {
die('Fehler beim Senden der Daten: ' . pg_last_error($conn));
}
}
// COPY-Operation abschließen
if (!pg_put_copy_end($conn)) {
die('Fehler beim Abschließen der COPY-Operation: ' . pg_last_error($conn));
}
echo 'Import erfolgreich abgeschlossen.' . PHP_EOL;
pg_close($conn);
CSV-Datei chunkweise importieren
<?php
$conn = pg_connect('host=localhost dbname=testdb user=postgres password=secret');
if (!$conn) {
die('Verbindung fehlgeschlagen');
}
$csvFile = '/tmp/produkte.csv'; // CSV ohne Header-Zeile
$handle = fopen($csvFile, 'r');
if (!$handle) {
die('CSV-Datei konnte nicht geöffnet werden');
}
// COPY mit CSV-Format starten
$result = pg_query($conn, "COPY produkte (id, name, preis) FROM STDIN WITH (FORMAT csv, DELIMITER ',')");
if (!$result) {
die('COPY-Befehl fehlgeschlagen: ' . pg_last_error($conn));
}
// Datei in 8-KB-Blöcken übertragen
while (!feof($handle)) {
$chunk = fread($handle, 8192);
if ($chunk === false) {
break;
}
if (pg_put_copy_data($conn, $chunk) === false) {
fclose($handle);
die('Fehler beim Übertragen: ' . pg_last_error($conn));
}
}
fclose($handle);
// Operation abschließen
if (!pg_put_copy_end($conn)) {
die('Fehler beim Abschluss: ' . pg_last_error($conn));
}
echo 'CSV-Import erfolgreich.' . PHP_EOL;
pg_close($conn);
// Wichtig · Fallstricke
Reihenfolge beachten: Vor dem Aufruf von pg_put_copy_data() muss zwingend ein COPY ... FROM STDIN-Befehl per pg_query() ausgeführt worden sein. Andernfalls gibt die Funktion false zurück.
Abschluss nicht vergessen: Jede mit COPY FROM STDIN gestartete Operation muss mit pg_put_copy_end() abgeschlossen werden. Wird dies unterlassen, bleibt die Verbindung im COPY-Modus blockiert und weitere Abfragen schlagen fehl.
Sicherheit: Da die Daten im COPY-Protokoll direkt übertragen werden (kein SQL-Parsing), sind SQL-Injections über $data nicht möglich. Dennoch sollten Steuerzeichen und das COPY-Abschlusszeichen (\. am Zeilenanfang) in den Nutzdaten geprüft bzw. maskiert werden, um Protokollfehler zu vermeiden.
Performance: Für den Import von Millionen von Datensätzen empfiehlt es sich, die Daten in größeren Chunks (z. B. 64 KB) zu senden statt zeilenweise, um den Overhead pro Funktionsaufruf zu minimieren.