Insertar ficheros de imagen en Teradata como BLOBs usando Windows Scripting Host y OLEDB/ADO.

Las Bases de Datos actuales -y más las Data Warehouses- almacenan ya no sólo datos de los tipos básicos (caracteres, números, fechas) sino que cada vez más son requeridas para almacenar datos heterogéneos: documentos (.pdf, .doc …), imágenes, sonidos, etc…

Teradata -como casi todos los SGBDRs- maneja datos binarios grandes (BLOBs -Binary Large OBjects-) y es capaz de almacenarlos de forma eficiente. La documentación invita a utilizar estas capacidades, pero aparece la eterna pregunta: ¿Cómo cargo esos datos en la Base de Datos?

Las utilidades Teradata ofrecen pocas alternativas: las únicas que son capaces de llevar a cabo la tarea son ‘SQL Assistant’ y ‘bteq’, y ambas con funcionalidad limitada.

Así que si se necesita una solución rápida y fácil para incorporar los datos binarios, enseguida se piensa en Windows Scripting Host y Visual Basic Script por su simplicidad y facilidad de programación. (He de decir que, aunque no soy ningún fan de Microsoft, encuentro que el WSH es una muy buena herramienta)

No nos podemos olvidar del acceso a la base de datos: personalmente me gusta OLEDB, con lo que una instalación del Teradata OLEDB provider es necesaria. Utilizaremos ADO como capa de acceso a la base de Datos.

Con todos estos ingredientes podemos comenzar la tarea: cargar imágenes (pero podría ser cualquier otro tipo de datos binario) a partir de ficheros .jpg en Teradata.

Lo primero, vamos a crear una tabla que contenga, por ejemplo, el nombre del fichero y la imagen como columna BLOB:

 BTEQ -- Enter your DBC/SQL request or BTEQ command:

CREATE SET TABLE MY_DATABASE.PRUEBA_BLOB,
           NO FALLBACK,
           NO JOURNAL
           (
              NOM_FICHERO VARCHAR(64) NOT NULL  CHARACTER SET LATIN,
              BLOB_IMAGE  BLOB(2M)        NULL
           )
           UNIQUE PRIMARY INDEX (NOM_FICHERO)
;

 *** Table has been created.
 *** Total elapsed time was 1 second.

 BTEQ -- Enter your DBC/SQL request or BTEQ command:

La columna BLOB se puede dejar sin tamaño, pero esto hará que tome el valor por defecto: 2 Gb. ¿Un poco excesivo, no? Nos conformamos con unas muy generosas 2 megas por imagen.

Con la tabla creada nos sumergimos en el mundo del Visual Basic Script:

Const CONNECTIONSTRING = "Provider=TDOLEDB;Data Source=MY_DW;
User Id=myuser;password=mypass;" 'OLEDB
Dim vNombreFichero

'Conexión
Dim objConnection

Main

Sub Main

   If WScript.Arguments.Length  1 Then
      vNombreFichero = InputBox("Introduzca el nombre del fichero a tratar:", "PruebaBLOB.vbs")
      If vNombreFichero = "" Or IsNull(vNombreFichero) Then
         WScript.Echo "ERROR: Falta fichero a tratar." & Chr(13) & Chr(10) & Chr(13) & Chr(10) & "(Uso: PruebaBLOB.vbs )"
         WScript.Quit
      End If
   Else
      vNombreFichero = WScript.Arguments(0)
   End If

   Wscript.Echo "Let's roll..." 

   AbrirConexion

   CerrarConexion

   Wscript.Echo "Bye."
End Sub

Sub AbrirConexion

   Set objConnection = WScript.CreateObject("ADODB.Connection")

   objConnection.ConnectionString = CONNECTIONSTRING
   objConnection.Open()

   Wscript.Echo "Conectando a Teradata..."

   If Err.Number  0 Then
      Wscript.Echo "Err# " & Err.Number & " - " & Err.Description
   Else
      Wscript.Echo "Connected to database as " & objConnection.Properties("User Name") & " en " & objConnection.Properties("Server Name") & "."
   End If
End Sub

Sub CerrarConexion
   objConnection.Close()
   Set objConnection = Nothing
End Sub

Esto no es más que probar la conexión -abrir y cerrar- y una comprobación básica de que debe llegar el nombre del fichero como argumento:

C:\Procesos\CargarBLOBs>cscript PruebaBLOB.vbs  foto1.jpg
Microsoft (R) Windows Script Host versión 5.6
Copyright (C) Microsoft Corporation 1996-2001. Reservados todos los derechos.

Let's roll...
Conectando a Teradata...
Connected to database as myuser en MY_DW.
Bye.

C:\Procesos\CargarBLOBs>

Así pues, todo parece funcionar (‘so far, so good…‘)

Lo bueno empieza ahora. La primera idea que nos viene a la cabeza es utilizar los FileSystemObjects del WSH para abrir el fichero, leerlo e insertarlo en la base de datos. Pero la cosa no va por ahí: el manejo de ficheros que se proporciona en el WSH y sus ‘streams’ están pensados para trabajar únicamente en modo texto, por lo que no nos sirven de mucho.

Los tiros van por otro lado: Las últimas versiones de ADO incorporan un objeto que permite trabajar con datos binarios: ‘ADODB.Stream’.

En efecto, con objetos ADODB.Stream podemos manipular ficheros binarios:

Sub InsertarImagen

   'Cargar BLOB con fichero
   Const adTypeBinary = 1

   'Create Stream object
   Dim inStream
   Dim vBuffer
   Set inStream = CreateObject("ADODB.Stream")
   inStream.Open
   inStream.type=adTypeBinary

   Wscript.Echo "Cargando Fichero Imagen..."
   inStream.LoadFromFile vNombreFichero

   Wscript.Echo "Tamaño de la imagen: " & inStream.Size
   ...

Para ver que la cosa funciona bastará hacer una prueba y verificar que inStream.Size da el tamaño del fichero de imagen:

C:\Procesos\CargarBLOBs>cscript PruebaBLOB.vbs  foto1.jpg
Microsoft (R) Windows Script Host versión 5.6
Copyright (C) Microsoft Corporation 1996-2001. Reservados todos los derechos.

Let's roll...
Conectando a Teradata...
Connected to database as myuser en MY_DW.
Cargando Fichero Imagen...
Tamaño de la imagen: 710312
Bye.

C:\Procesos\CargarBLOBs>

Así pues, vemos que el objeto ADO.Stream funciona según lo esperado.

Siguiente asunto: ¿qué tipo de dato ADO utilizamos para ‘mapear’ el dato BLOB? Esta es fácil: la documentación de ADO lo indica claramente: LongVarBinary.

Aquí hay dos cosas a tener en cuenta: Primero, en ADO todos los parámetros de longitud variable necesitan un argumento de tamaño en la creación del objeto:

Si hacemos:

   Set objParm2 = objCommand.CreateParameter("blob_image", adLongVarBinary,
adParamInput)
   objCommand.Parameters.Append objParm2

Tendremos que:

C:\Procesos\CargarBLOBs\PruebaBLOB.vbs(157, 4) ADODB.Parameters:
Objeto Parameter mal definido. Se proporcionó información incompleta o incoherente.

Por lo que hay que definir el parámetro con tamaño:

   Set objParm2 = objCommand.CreateParameter("blob_image", adLongVarBinary,
adParamInput, 2097152)
   objCommand.Parameters.Append objParm2

La segunda cuestión a recordar es que debemos asignar el valor del parámetro no con ‘Value’, sino con AppendChunk.

 objParm2.AppendChunk inStream.Read

Teniendo en cuenta estas dos cosas podemos ya ejecutar un ‘ADO.Command’ con el ‘INSERT’:

   ...
   Dim objCommand
   Dim sCommandText
   Dim objParm1,objParm2

   sCommandText = "INSERT INTO MY_DATABASE.PRUEBA_BLOB(NOM_FICHERO, BLOB_IMAGE) " & _
                  "VALUES ( ?, ? )"

   Set objCommand = Wscript.CreateObject("ADODB.Command")

   objCommand.CommandType = adCmdText

   objCommand.CommandText = sCommandText 

   'Command Prepared
   objCommand.Prepared = True

   objCommand.ActiveConnection = objConnection

   'Parámetros:
   Set objParm1 = objCommand.CreateParameter("nom_fichero", adVarChar,
adParamInput, 64 )
   objCommand.Parameters.Append objParm1

   objParm1.Value = vNombreFichero

   Set objParm2 = objCommand.CreateParameter("blob_image", adLongVarBinary,
adParamInput, 2097152) 'inStream.Size
   objCommand.Parameters.Append objParm2

   objParm2.AppendChunk inStream.Read

   objCommand.Execute

   'Close the stream
   inStream.Close()
   Set inStream = Nothing

   Set objCommand = Nothing

End Sub

Ejecutamos:

C:\Procesos\CargarBLOBs>cscript PruebaBLOB.vbs  foto1.jpg
Microsoft (R) Windows Script Host versión 5.6
Copyright (C) Microsoft Corporation 1996-2001. Reservados todos los derechos.

Let's roll...
Conectando a Teradata...
Connected to database as myuser en MY_DW.
Cargando Fichero Imagen...
Tamaño de la imagen: 710312

C:\Procesos\CargarBLOBs\PruebaBLOB.vbs(161, 4)
OLE DB Provider for Teradata: [NCR] Invalid precision: cbColDef value out of range

¡ERROR! ¿Por qué? Hemos hecho todo según la documentación. ¿Se nos ha pasado algo?

Sí. La respuesta está en la documentación de Teradata: ‘OLE DB Provider for Teradata’. En un lugar recóndito se nos dice que hay que habilitar el tratamiento de LOBs mediante las ‘extended properties’ del OLEDB provider:

Const CONNECTIONSTRING = "Provider=TDOLEDB;Data Source=MY_DW;
User Id=myuser;password=mypass;
Extended Properties=""EnableLOBSupport=Yes;"";" 'OLEDB EnableLOBSupport

Y ahora todo va a ir OK:

C:\Procesos\CargarBLOBs>cscript PruebaBLOB.vbs  foto1.jpg
Microsoft (R) Windows Script Host versión 5.6
Copyright (C) Microsoft Corporation 1996-2001. Reservados todos los derechos.

Let's roll...
Conectando a Teradata...
Connected to database as myuser en MY_DW.
Cargando Fichero Imagen...
Tamaño de la imagen: 710312
Bye.

C:\Procesos\CargarBLOBs>

Y vemos que la inserción se realizó:

 BTEQ -- Enter your DBC/SQL request or BTEQ command:
SELECT * FROM  MY_DATABASE.PRUEBA_BLOB;

SELECT * FROM  MY_DATABASE.PRUEBA_BLOB;

 *** Query completed. One row found. 2 columns returned.
 *** Total elapsed time was 1 second.

NOM_FICHERO  BLOB_IMAGE
------------ -------------------------------------------------------

foto1.jpg    FFD8FFE000104A46494600010101012C012C0000FFFE0029433A5C5

Evidentemente, BTEQ sólo nos muestra el contenido hexadecimal de la imagen. Si queremos ver la foto deberemos utilizar el ‘SQL Assisstant’ o algún otro ‘software’, pero la imagen está ahí. Y eso era lo que queríamos.

Una última cosa: el ejemplo mostrado aquí es fácilmente portable a Visual Basic. Sólo hay que tener en cuenta las diferencias que existen entre VB y VBScript.

Saludos.

Carlos.

5 respuestas a Insertar ficheros de imagen en Teradata como BLOBs usando Windows Scripting Host y OLEDB/ADO.

  1. Zac dice:

    Thanks! This is perfect. Do you have an example of reading the file using VBS? I keep getting an error saying “LOBs are not allowed to be selected in Record or Indicator modes”

    (Used Google Translate)
    Gracias! Esto es perfecto. ¿Tiene usted un ejemplo de lectura usando el archivo VBS? Sigo recibiendo un error diciendo que “LOBs no pueden ser seleccionados en el Registro o Indicador de modos”

  2. carlosal dice:

    I’m not sure about what you mean. You can read the file with ADO.Stream as explained.

    Cheers.

    Carlos.

  3. […] Insertar ficheros en Teradata como BLOBs con bteq En un artículo anterior ya se explicaba cómo Insertar ficheros en Teradata como BLOBs usando Windows Scripting Host y OLEDB/ADO. […]

  4. […] BLOB en Teradata como ficheros usando Windows Scripting Host y OLEDB/ADO. Hemos visto aquí y aquí cómo guardar ficheros en forma de BLOBs en la base de datos. Ambos métodos son sencillos y […]

  5. Carlos F dice:

    Muchas Gracias funciona perfecto!!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: