Start · Sprachen · PHP · Referenz · pg_put_copy_data

pg_put_copy_data

Funktion

Sendet Daten im COPY-Format während einer laufenden PostgreSQL-COPY-Operation an den Server.

seit PHP 5.6.0 Kategorie: db

Signatur

pg_put_copy_data(PgSql\Connection $connection, string $data): int|false

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() gestartete COPY ... 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

Typ
int|false
Beschreibung
Gibt 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);
Import erfolgreich abgeschlossen.

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);
CSV-Import erfolgreich.

// 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.