Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Firebird e Interbase (https://www.clubdelphi.com/foros/forumdisplay.php?f=19)
-   -   Urgente Comparar dos blobs (https://www.clubdelphi.com/foros/showthread.php?t=45931)

Leto_Atreides 18-07-2007 17:29:06

Urgente Comparar dos blobs
 
Hola amigos pacientes y sufridores del Delphi y de firebird
Tengo un problema. Necesito comparar el contenido de dos campos de tipo blob en un procedimiento de firebird. El problema es que si los comparo directamente con los operadores '= <>' no funciona. Creo que lo que hace es comparar directamente los campos pero no los contenidos.
¿Alguien sabe como hacerlo? (A ser posible en el mismo procedimiento de firebird)
Gracias

Ñuño Martínez 19-07-2007 08:07:10

Que yo sepa no se puede. Aun así puedes intentar un truco.

Consiste en añadir un campo a la tabla donde se almacena un identificador único del objeto 'blob' (Por ejemplo, el CRC, md5, GUI... ) y utilizarlo cuando necesites compararlo.

Evidentemente no podrás utilizar "mayor que" ni "menor qué", y es posible, aunque poco provable, que dos blob distintos acaben con el mismo identificador, pero en principio puede funcionar.

Leto_Atreides 19-07-2007 09:11:35

Gracias.

Ya me lo imaginaba, tendré que hacerlo desde el mismo Delphi. Voy a tener que cambiar todos los procedimientos del firebird pero que le vamos a hacer. Es lo que tienen los dichosos blobs. De todas formas gracias

Leto_Atreides 19-07-2007 18:42:32

Bueno lo anterior ya está solucionado. Aunque no he podido hacerlo desde el mismo firebird.
Ahora tengo un problema con los dichosos blobs y es que cuando eliminas el texto que tenías anteriormente el blob no se queda a nil. Claro y esto es un problemón porque yo quiero compararlos y si uno de ellos está a null y otro en realidad también está vacío pero no está a null me dice que son distintos cuando en realidad son iguales.
He intentado hacer una conversión y meter el valor del blob en un richedit y comparar los textos pero no sale bien. Además como comparo muchos campos va demasiado lento. Lo cierto es que no sirve tratar el campo blob como un asstring porque en realidad no es = ''.
También he hecho una comparación con el valor del blob = '' then dentro del procedimiento pero claro está me da error tal y como pensaba que iba a pasar pero hay que probarlo todo, ¿no?
¿A alguien se le ocurre como hacerlo?
Gracias

ariefez 19-07-2007 18:48:04

Esto no lo he probado, pero, puedes apoyarte en una UDF Free UDFLib la funcion en cuestion es F_BLOBBINCMP, esta libreria se menciona en el libro de firebird o tambien implementar la tuya, ya q he escuchado q delphi implementa este tipo de comparacion en sus componentes con los streams, si alguien sabe mas de este tema seria cuestion de usarlo para armar la UDF...

PD: al descargarte el Zip los archivos q interesan son FreeUDFLib.dll y ext_funcs.sql esta ultima para compilar la UDF.

Edito : Existe dos Free UDFLib, la q tiene dicha funcion es Free UDFLib for InterBase V6 for Windows (valido para firebird como lo dice en su descripcion). Si no te baja el archivo dale a: guardar enlace como...

Leto_Atreides 20-07-2007 08:11:28

La verdad es que tengo un problema con las udf. El servidor donde se encuentra la bd tiene linux y trabajo sobre windows, así que no puedo utilizar udfs.
Estaría bien que pudiera saber el código fuente de la función F_BLOBBINCMP que mencionas.
Gracias.

ariefez 20-07-2007 17:31:33

En el enlace q te proporcione se encontraba las fuentes de la Dll ( Free UDFLib for InterBase V6 for Windows si no te baja el archivo le das a: guardar enlace como) la unidad que contiene la funcion es BlobFncs.pas.

Otra cosa, no creo que tener un servidor linux sea el problema para no poder usar UDFs, tan solo seria crear la UDF para linux y declarar la funcion en la base de datos. Una vez echo esto el acceso a dicha funcion desde windows seria tan solo como una sentencia cualquiera. aca te dejo un enlace en el cual hacen esta labor UDF en Interbase aplicable para firebird

Leto_Atreides 21-07-2007 12:59:54

He mirado el código fuente de la fuente que me citabas pero no existe en ninguna de las dos librerías de freeudf.
De todas formas existe una función que convierte los blobs a cadenas de texto pero no he podido implementarla.
En cuanto a lo de compilar las udfs en linux y utilizarlas en windows ya sabía que se podía hacer pero el problema es quizás no me he explicado bien. En realidad es mi jefe el que no quiere que utilicemos las udfs. No me preguntes por qué. Lo cierto es que llevo dos días intentando que funcione.

ariefez 21-07-2007 17:19:30

OK entiendo las razones... como te dije en mi primer post delphi usa algo similar en sus componentes o en alguna parte no me acuerdo donde lo lei, asi q solo era adentrarse un poco :rolleyes:, te dejo un par de funciones, basicamente no hago nada, todo lo hace delphi a la hora de comparar (la comparacion es de forma binaria)....

comparacion mediante streams:
Código Delphi [-]
function CompareStreams(StreamA, StreamB: TMemoryStream): Boolean;
begin
  Result := (Assigned(StreamA) and Assigned(StreamB))
    and (StreamA.Size = StreamB.Size)
    and CompareMem(StreamA.Memory, StreamB.Memory, StreamB.Size);
end;

solo falta convertir el campo a stream, eso se arregla con esta funcion:
Código Delphi [-]
function BlobToStream(Field: TField): TMemoryStream;
begin
  Result := nil;
  if Field.IsBlob then
  begin
    Result := TMemoryStream.Create;
    try
      TBlobField(Field).SaveToStream(Result);
    except
      FreeAndNil(Result);
    end;
  end;
end;

aca va un ejemplo de uso:
Código Delphi [-]
var
  StreamA: TMemoryStream;
  StreamB: TMemoryStream;
begin
  ...
  StreamA := BlobToStream(TuTabla.Fields[1]);
  StreamB := BlobToStream(TuTabla.Fields[2]);

  if CompareStreams(StreamA, StreamB) then
    ShowMessage('Los campos blob son iguales');

  if Assigned(StreamA) then
      StreamA.Free;
  if Assigned(StreamB) then
    StreamB.Free;
  ...
end;

Leto_Atreides 21-07-2007 17:42:50

Gracias por las funciones.
La comparación entre dos campos blobs estaba clara.
Quizás debería haberte explicado mejor cual era el objetivo de la función a resolver.
Por ejemplo. Imaginemos que un paciente se somete a una operación. El cirujano va detallando la evolución del paciente en un campo de tipo blob. Pero para cada una de las revisiones se crea un registro diferente. O sea las evoluciones se guardan en campos blob diferentes. Esto debe ser así. Hay que indicar cuando han cambiado esas obsevaciones de una revisión a otra. Hasta aquí no hay problema. Lo resolví con las funciones que tú indicaste. Ahora bien, existe un caso en el cual se produce un problema. Si se pone algo de texto en el richedit del cual recoge los datos el campo blob y seguidamente se elimina el texto, el campo blob aparece como vacío pero en realidad no lo está.
Si se hace una comparación del stream = nill o = '' nos devuelve false porque en realidad tiene datos pero al mostrarlo en un richedit está vacío. En este caso la función me dice que los datos han cambiado con respecto a un campo que está a nil y no lo han hecho. ¿Está claro? El lunes tendré que averiguar como detectar estos streams que no están vacíos pero que no tienen texto

ariefez 21-07-2007 19:17:15

El problema es por guardar una texto vacio, en ese caso no tendrias que guardar nada osea el valor de dicho campo seria nulo.

Basicamente lo que tendrias que hacer, seria:

Antes de confirmar los cambios, antes del Post, verificar si el texto esta vacio en caso afirmativo asignarle null

Un ejemplo a esto seria

Código Delphi [-]
  ...
  { Para evitar caracteres q no den informacion de nada se tendria q hacer
    una limpieza al texto del DBRichEdit, esto porque puede ingresar un
    espacio una coma u otras cosas que afectarian en la comparacion } 
  ...
  if DBRichEdit1.Text = '' then
    DBRichEdit1.Field.Clear;
  ...
  TuTabla.Post
  ...

suponiendo que usas el TDBRichEdit, ya que no indicas q componentes usas.

Edito para resaltar la sintaxis en delphi :cool:

Leto_Atreides 23-07-2007 08:58:09

Muchas gracias!!!
Parece mentira que una cosa tan simple no se me hubiera ocurrido pero es que siempre estaba pensando desde el punto de vista de firebird.
Ahora mismo lo pruebo

Un saludo


La franja horaria es GMT +2. Ahora son las 19:41:13.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi