SQL para leer XML del archivo en la base de datos PostgreSQL

12

¿Cómo puedo escribir SQL para leer un archivo XML en un XMLvalor PostgreSQL ?

PostgreSQL tiene un tipo de datos XML nativo con la XMLPARSEfunción de analizar una cadena de texto a ese tipo. También tiene formas de leer datos del sistema de archivos; el COPYcomunicado, entre otros.

Pero no veo una manera de escribir declaraciones SQL PostgreSQL nativas para leer el contenido de una entrada del sistema de archivos y usarlo para completar un XMLvalor. ¿Cómo puedo hacer esto?

nariz grande
fuente

Respuestas:

10

Similar a esta respuesta a una pregunta anterior, y si no desea las restricciones depg_read_file() (en resumen: pg_read_fileno puede leer archivos fuera del directorio de la base de datos y lee el texto en la codificación de caracteres de la sesión actual).

Esta función funciona para cualquier ruta, pero debe crearse como superusuario:

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 se introdujo en 9.4, por lo que para versiones anteriores necesitaría:

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;$$;

luego:

select convert_from(stack.bytea_import('/tmp/test.xml'), 'utf8')::xml;
Jack dice que intente topanswers.xyz
fuente
1
+1, gracias por señalar que hay límites para las funciones de lectura de archivos.
bignose
1
+1 buen truco para eludir pg_read_file(). Lo mismo también se puede lograr con una tabla temporal y COPY- complete solo 1 columna de 1 fila.
Erwin Brandstetter
4

La pg_read_binary_filefunción puede hacer esto.

Tiene limitaciones: nuevo en PostgreSQL 9.1 o superior; debe ser una sesión propiedad del superusuario de la base de datos; debe leer un archivo dentro del directorio de la base de datos o debajo. Esos son aceptables en mi caso de uso.

Entonces, lo siguiente funcionará para crear un XMLvalor nativo de un archivo:

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

En PostgreSQL 8.3 - 9.0, la pg_read_filefunción se puede utilizar, con la limitación adicional de que no puede especificar una codificación específica de archivo (lee el archivo como texto en la codificación de la sesión actual).

-- PostgreSQL earlier than 9.1.
SELECT
    XMLPARSE(DOCUMENT pg_read_file('foo.xml'));
nariz grande
fuente
3

He publicado una implementación completa de lo que está pidiendo en una respuesta reciente sobre SO .

Las características clave son la xpath()función, pg_read_file()manejo de matriz, funciones plpgsql, ..

Erwin Brandstetter
fuente
Bastante diferente (y más pesado) de lo que necesito en este caso. Pero +1 por la buena dirección, gracias.
bignose
No es que el peso pesado, mi ejemplo es muy completo con elementos redundantes para demostrar variantes de sintaxis.
Erwin Brandstetter