Wilt u het resulterende bestand op de server of op de client?
Serverzijde
Als u iets wilt dat gemakkelijk opnieuw te gebruiken of te automatiseren is, kunt u het ingebouwde COPY-commando van Postgresql gebruiken. bijv.
Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER;
Deze aanpak draait volledig op de externe server - het kan niet naar uw lokale pc schrijven. Het moet ook worden uitgevoerd als een Postgres "superuser" (normaal gesproken "root" genoemd) omdat Postgres niet kan voorkomen dat het vervelende dingen doet met het lokale bestandssysteem van die machine.
Dat betekent niet dat je als superuser verbonden moet zijn (dat automatiseren zou een ander soort beveiligingsrisico zijn), omdat je de SECURITY DEFINER
kunt gebruiken optie om CREATE FUNCTION
om een functie te maken die loopt alsof je een supergebruiker bent .
Het cruciale onderdeel is dat uw functie er is om extra controles uit te voeren, niet alleen om de beveiliging te omzeilen - u kunt dus een functie schrijven die de exacte gegevens exporteert die u nodig hebt, of u kunt iets schrijven dat verschillende opties accepteert zolang ze voldoen aan een strikte witte lijst. Je moet twee dingen controleren:
- Welke bestanden moet de gebruiker worden toegestaan om op schijf te lezen/schrijven? Dit kan bijvoorbeeld een bepaalde map zijn en de bestandsnaam moet mogelijk een geschikte prefix of extensie hebben.
- Welke tafels moet de gebruiker kunnen lezen/schrijven in de database? Dit wordt normaal gesproken gedefinieerd door
GRANT
s in de database, maar de functie wordt nu uitgevoerd als een superuser, dus tabellen die normaal "buiten de grenzen" zouden zijn, zijn volledig toegankelijk. U wilt waarschijnlijk niet dat iemand uw functie aanroept en rijen toevoegt aan het einde van uw "gebruikers"-tabel...
Ik heb een blogpost geschreven waarin deze benadering wordt uitgebreid, inclusief enkele voorbeelden van functies die bestanden en tabellen exporteren (of importeren) die aan strikte voorwaarden voldoen.
Klantzijde
De andere benadering is om de bestandsverwerking aan de clientzijde uit te voeren , d.w.z. in uw applicatie of script. De Postgres-server hoeft niet te weten naar welk bestand u kopieert, hij spuugt de gegevens gewoon uit en de client plaatst deze ergens.
De onderliggende syntaxis hiervoor is de COPY TO STDOUT
commando, en grafische tools zoals pgAdmin zullen het voor je inpakken in een mooi dialoogvenster.
De psql
opdrachtregelclient heeft een speciaal "meta-commando" genaamd \copy
, die dezelfde opties heeft als de "echte" COPY
, maar wordt uitgevoerd in de client:
\copy (Select * From foo) To '/tmp/test.csv' With CSV
Merk op dat er geen afsluitende ;
. is , omdat meta-commando's worden beëindigd door newline, in tegenstelling tot SQL-commando's.
Uit de documenten:
Verwar COPY niet met de psql-instructie \copy. \copy roept COPY FROM STDIN of COPY TO STDOUT aan, en haalt dan de gegevens op in een bestand dat toegankelijk is voor de psql-client. De toegankelijkheid van bestanden en toegangsrechten zijn dus afhankelijk van de client en niet van de server wanneer \copy wordt gebruikt.
De programmeertaal van uw applicatie mag hebben ook ondersteuning voor het pushen of ophalen van de gegevens, maar u kunt in het algemeen geen gebruik maken van COPY FROM STDIN
/TO STDOUT
binnen een standaard SQL-statement, omdat er geen manier is om de input/output-stroom te verbinden. PHP's PostgreSQL-handler (niet PDO) bevat zeer eenvoudige pg_copy_from
en pg_copy_to
functies die kopiëren naar/van een PHP-array, wat mogelijk niet efficiënt is voor grote datasets.