it-swarm.it

SQL per leggere XML da file nel database PostgreSQL

Come posso scrivere SQL per leggere un file XML in un valore PostgreSQL XML?

PostgreSQL ha un tipo di dati XML nativo con la funzione XMLPARSE per analizzare una stringa di testo in quel tipo. Ha anche modi per leggere i dati dal filesystem; l'istruzione COPY, tra gli altri.

Ma non vedo un modo per scrivere istruzioni SQL PostgreSQL native per leggere il contenuto da una voce del filesystem e usarlo per popolare un valore XML. Come posso fare questo?

12
bignose

Il pg_read_binary_file la funzione può farlo.

Presenta limitazioni: novità in PostgreSQL 9.1 o versioni successive; deve essere una sessione di proprietà del superutente del database; deve leggere un file nella directory del database o in basso. Sono accettabili nel mio caso d'uso.

Quindi il seguente funzionerà per creare un valore XML nativo da un file:

-- PostgreSQL 9.1 or later.
SELECT
    XMLPARSE(DOCUMENT convert_from(
        pg_read_binary_file('foo.xml'), 'UTF8'));

In PostgreSQL 8.3 - 9.0, il pg_read_file È possibile utilizzare la funzione, con l'ulteriore limitazione che non è possibile specificare una codifica specifica del file (legge il file come testo nella codifica della sessione corrente).

-- PostgreSQL earlier than 9.1.
SELECT
    XMLPARSE(DOCUMENT pg_read_file('foo.xml'));
4
bignose

Simile a this rispondi a una domanda precedente, e se non vuoi le restrizioni di pg_read_file() (in breve: pg_read_file non è in grado di leggere file all'esterno della directory del database e legge il testo nella codifica dei caratteri della sessione corrente).

Questa funzione funziona per qualsiasi percorso, ma deve essere creata come superutente:

create or replace function stack.bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
begin
  select lo_import(p_path) into l_oid;
  select lo_get(l_oid) INTO p_result;
  perform lo_unlink(l_oid);
end;$$;

lo_get è stato introdotto in 9.4, quindi per le versioni precedenti avresti bisogno di:

create or replace function stack.bytea_import(p_path text, p_result out bytea) 
                   language plpgsql as $$
declare
  l_oid oid;
  r record;
begin
  p_result := '';
  select lo_import(p_path) into l_oid;
  for r in ( select data 
             from pg_largeobject 
             where loid = l_oid 
             order by pageno ) loop
    p_result = p_result || r.data;
  end loop;
  perform lo_unlink(l_oid);
end;$$;

poi:

select convert_from(stack.bytea_import('/tmp/test.xml'), 'utf8')::xml;

Ho pubblicato un'implementazione completa di ciò che stai chiedendo in un risposta recente su SO .

Le caratteristiche principali sono la funzione xpath(), pg_read_file(), gestione dell'array, funzioni plpgsql, ..

3