Descargar datos LOB de Oracle: código de muestra

Recientemente trabajamos en el lanzamiento de la versión 2.0 de dbForge Data Compare para Oracle. Una de las principales características añadidas a la nueva versión fue la sincronización de datos LOB. Cuando desarrollamos la primera versión del producto, pospusimos esta función debido a problemas con la sincronización de datos LOB. Estos problemas se deben a la naturaleza de los datos almacenados en las columnas BLOB o CLOB. Es grande y simplemente no cabe en el script SQL. Pero encontramos una solución.

En este artículo, veremos los métodos básicos para cargar datos LOB en una tabla.

Usando DBMS_LOB.WRITEAPPEND

El método más simple y conveniente para insertar/actualizar datos LOB en una tabla es usar el paquete DBMS_LOB. En este caso, los datos ingresan a la tabla a través de variables adicionales insertadas en el bloque PL/SQL.

DECLARE
  TMP_BLOB BLOB := NULL;
  SRC_CHUNK RAW(12001);

La variable TMP_BLOB sirve como búfer para el valor LOB. El tipo de datos de la variable temporal se selecciona según el tipo de datos de la columna LOB, por ejemplo, para cargar datos en una columna con tipo de datos CLOB, la variable temporal será el tipo de datos CLOB. XMLTYPE es una modificación del tipo de datos CLOB; por lo que su variable de tiempo será CLOB. Los datos se escriben en el portapapeles en partes usando la variable SRC_CHUNK. La variable utiliza el tipo de datos RAW, cuyo tamaño está determinado por la longitud de los datos cargados. La siguiente secuencia de consulta se utiliza para crear una variable de búfer:

DBMS_LOB.CREATETEMPORARY(TMP_BLOB, TRUE);
DBMS_LOB.OPEN(TMP_BLOB, DBMS_LOB.LOB_READWRITE);

A continuación, puede escribir datos en esta variable. Aquí se utiliza la variable SRC_CHUNK, es decir, primero se asignan datos a la variable y luego la función DBMS_LOB.WRITEAPPEND los datos ingresan a la variable TMP_BLOB.

SRC_CHUNK := 'BBBBBBBBBBBBBBBBBBBBBBBB';
DBMS_LOB.WRITEAPPEND(TMP_BLOB, LENGTH(SRC_CHUNK), SRC_CHUNK);

Si los datos están completamente cargados en TMP_BLOB, esta variable se usa en la cláusula INSERT/UPDATE.

INSERT INTO TABLE_BLOB(ID, BLB) VALUES (1001, TMP_BLOB);

El escenario final será:

DECLARE
  TMP_BLOB BLOB := NULL;
  SRC_CHUNK RAW(12001);
BEGIN
  DBMS_LOB.CREATETEMPORARY(TMP_BLOB, TRUE);
  DBMS_LOB.OPEN(TMP_BLOB, DBMS_LOB.LOB_READWRITE);

 SRC_CHUNK := 'BBBBBBBBBBBBBBBBBBBBBBBB';

  DBMS_LOB.WRITEAPPEND(TMP_BLOB, LENGTH(SRC_CHUNK), SRC_CHUNK);
  DBMS_LOB.CLOSE(TMP_BLOB);

  INSERT INTO TABLE_BLOB(ID, BLB) VALUES (1001, TMP_BLOB);
END;

Subir datos a través de archivos

Este método se ha desarrollado para casos en los que no se puede utilizar DBMS_LOB.WRITEAPPEND. Esto ocurre cuando, por ejemplo, una solicitud de sincronización excede el tamaño aceptable del almacenamiento dedicado para el programa. En este caso, el usuario puede cargar los datos LOB en la tabla a través de archivos. Para hacer esto, el usuario debe tener acceso al directorio en el servidor. Este directorio se utilizará para crear archivos para sincronizar. Para descargar archivos, debe vincular el directorio a una base de datos de Oracle; esto le permitirá llamar al directorio desde el script de sincronización. El directorio se llama a través de un alias asignado al siguiente script:

CREATE DIRECTORY MY_DIR as 'C:temp'

La variable auxiliar también se utiliza para cargar datos en la tabla:

DECLARE
  TMP_BLOB BLOB := NULL;

También se ha anunciado la función auxiliar LOAD_BLOB_FROM_FILE:

FUNCTION LOAD_BLOB_FROM_FILE(FILENAME VARCHAR2, DIRECTORYNAME VARCHAR2)
  RETURN BLOB
IS
  FILECONTENT BLOB := NULL;
  SRC_FILE BFILE := BFILENAME(DIRECTORYNAME,FILENAME);
  OFFSET NUMBER := 1;
BEGIN
  DBMS_LOB.CREATETEMPORARY(FILECONTENT,TRUE,DBMS_LOB.SESSION);
  DBMS_LOB.FILEOPEN(SRC_FILE,DBMS_LOB.FILE_READONLY);
  DBMS_LOB.LOADBLOBFROMFILE (FILECONTENT, SRC_FILE, DBMS_LOB.GETLENGTH(SRC_FILE),
    OFFSET, OFFSET);
  DBMS_LOB.FILECLOSE(SRC_FILE);
  RETURN FILECONTENT;
END;

Esta función carga datos de un archivo en la variable BLOB. La función principal es DBMS_LOB.LOADBLOBFROMFILE, que lee el contenido del archivo. La función DBMS_LOB.LOADCLOBFROMFILE se utiliza para cargar datos de texto. Su parámetro de entrada es el nombre de codificación del archivo. Llamar a LOAD_BLOB_FROM_FILE devuelve el valor LOB que se enviará a la base de datos.

  TMP_BLOB := LOAD_BLOB_FROM_FILE('BLB.bin', 'MY_DIR');
  INSERT INTO TABLE_BLOB(ID, BLB) VALUES (2000, TMP_BLOB);

El escenario final será:

DECLARE
  TMP_BLOB BLOB := NULL;

  FUNCTION LOAD_BLOB_FROM_FILE(FILENAME VARCHAR2, DIRECTORYNAME VARCHAR2)
    RETURN BLOB
  IS
    FILECONTENT BLOB := NULL;
    SRC_FILE BFILE := BFILENAME(DIRECTORYNAME,FILENAME);
    OFFSET NUMBER := 1;
  BEGIN
    DBMS_LOB.CREATETEMPORARY(FILECONTENT,TRUE,DBMS_LOB.SESSION);
    DBMS_LOB.FILEOPEN(SRC_FILE,DBMS_LOB.FILE_READONLY);
    DBMS_LOB.LOADBLOBFROMFILE (FILECONTENT, SRC_FILE, DBMS_LOB.GETLENGTH(SRC_FILE),
      OFFSET, OFFSET);
    DBMS_LOB.FILECLOSE(SRC_FILE);
    RETURN FILECONTENT;
  END;

BEGIN
  TMP_BLOB := LOAD_BLOB_FROM_FILE('BLB.bin', 'DC1_DIR');
  INSERT INTO TABLE_BLOB_LARGE(ID, BLB) VALUES(2000, TMP_BLOB);
END;

Problemas al sincronizar datos CLOB y NCLOB en Oracle 8

Los problemas ocurren porque las versiones anteriores de Oracle no tienen la función LOADSLOBFROMFILE del paquete DBMS_LOB. Esto fuerza el uso de la función DBMS_LOB.LOADFROMFILE, que no tiene parámetros para controlar la codificación de texto. Como resultado, los datos pueden insertarse incorrectamente si existen caracteres no latinos.

Conclusión

Los métodos ilustrados tienen sus pros y sus contras. El uso de DBMS_LOB.WRITEAPPEND le permite descargar datos solo a través de un script, pero en el caso de trabajar con grandes cantidades de datos, no será posible ejecutar dicho scipt. La descarga de LOB desde un archivo también tiene una falla, ya que mover un archivo a una PC servidor trae muchos inconvenientes.

Artículos de interés

Subir