Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Crear UDF para Firebird
Ir a página 1, 2  Siguiente
 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Crear UDF para Firebird Responder citando

Hola amigos.

¿Alguien sabe como se puede crear una UDF desde Builder para Firebird? Por ejemplo que archivos incluir en el proyecto.

Deseo crear una UDF que me permita guardar un campo BLOB a un fichero y que recupere de un fichero a un campo BLOB.

Para que necesito esto?, bueno en el proyecto que me encuentro desarrollando debo guardar imagenes en la base y el volumen a guardar va ha ser que crezca demasiado la base de datos, asi que deseo hacer uso de una UDF para que la base de datos sea capaz de guardar los archivos en una carpeta o recuperarlos de ella.

Ahora si alguien posee una UDF que haga esto me ayudaria enormemenete. Wink
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

También estaba interesado en algo asi.

Pero no encontre nada hecho y la verdad es que no tuve tiempo de desarrollarlo, pero busque algunas referencias que te paso.

Si depues podes compartir tu resultado, asi lo podemos probar estaría bueno.

Te dejo unos links que estan buenos:
Example blob UDFs
http://bdn.borland.com/article/0,1410,25785,00.html

Declaring a blob UDF
http://bdn.borland.com/article/0,1410,25786,00.html

Writing Clean and Safe UDFs In Delphi
http://www.ibphoenix.com/a476.htm?a=ibphoenix&page=ibp_howto5

Writing UDF's in Delphi for Interbase/Firebird
http://firebird.sourceforge.net/index.php?op=useful&id=geldenhuis

Writing UDFs for InterBase
http://firebird.sourceforge.net/index.php?op=useful&id=deatz_udf

Creating UDF's IN Delphi
http://www.ibphoenix.com/a476.htm?a=ibphoenix&page=ibp_howto7

También dentro del código fuente de firebird extan las UDF's definidas de ellos.

Suerte
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola amigos, después de estar revisando muchas páginas en ingles, ruso, chino y no se que otros idiomas creo que ya he logrado algo funcional aquí se los paso para que se hagan las respectivas pruebas y logremos depurarlo al máximo:

Primero crear un proyecto en la opción “DLL Wizard”
Elegir la opción “C” y “Multi Theaded”

Al archivo generado reemplazarlo completamente por lo siguiente:
Código:

//---------------------------------------------------------------------------

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include "ibase.h"

//---------------------------------------------------------------------------
typedef struct blob {
   short   (*blob_get_segment)(void *,UCHAR *, USHORT, USHORT *);
   void   *blob_handle;
   long   blob_number_segments;
   long   blob_max_segment;
   long   blob_total_length;
   void   (*blob_put_segment)(void *,UCHAR *, USHORT);
} *TBLOB;

//---------------------------------------------------------------------------
__declspec(dllexport) void __cdecl FileToBlob(char * Fichero, TBLOB B)
{

//  char Buffer[32*1024];
  UCHAR * Buffer;
  int Tam;
  USHORT x;
  FILE * f;
//  if not (Assigned(Filename) and FileExists(Filename)) then Exit;
  f = fopen(Fichero, "rb");
  if( f )
  { Buffer = (UCHAR *) malloc( 32*1024 );
    __try
    {
//Vamos al final y conseguimos el tamaño
      fseek( f, 0, 2);
      Tam = ftell( f );
//Regresamos al inicio
      fseek( f, 0, 0 );
      while( Tam > 0 )
      {
        x = fread((void*)Buffer,sizeof(UCHAR), 32*1024, f);
        (*B->blob_put_segment)( B->blob_handle, Buffer, x);
        Tam -= x ;
      }
    }
    __finally
    {
      fclose(f);
       free(Buffer);
    }
  }
}
//---------------------------------------------------------------------------
__declspec(dllexport) long __cdecl BlobToFile(TBLOB B, char * Fichero)
{
  UCHAR *Buffer;
  int Total = 0;
  int TamBlob;
    USHORT TamMaxSeg, BytesLeidos;

  FILE * f;
  long r = -1;
  if( !B || !B->blob_handle)
    return -1;

  TamMaxSeg  = B->blob_max_segment;
//  if FileExists(FileName) then  DeleteFile(FileName);

//  if not (Assigned(Filename) and FileExists(Filename)) then Exit;
  f = fopen(Fichero, "wb");
  if( f )
  { Buffer = (char *) malloc( TamMaxSeg );
    __try
    { //if (iFileHandle <=3D 0) then Exit;
      while( (*B->blob_get_segment)( B->blob_handle, Buffer, TamMaxSeg, &BytesLeidos) )
      {
        fwrite((void*)Buffer,sizeof(UCHAR), BytesLeidos, f);
        Total += BytesLeidos;
      }
    }
    __finally
    {
      fclose(f);
       free(Buffer);
      r = Total;
    }
  }
  return r;
}

//---------------------------------------------------------------------------


Luego ir a Project/Options
- Elegir “Directories/Contitionals” y en “include Path” se debe agregar la carpeta “INCLUDE” esta se encuentra dentro de “Archivos de progra-ma\Firebird\Firebird_1_5\include”

- En “Linker” desactivar “Create Debug Information, use dynamic RTL, use debug li-braries y generate import library”
- En “Packages” desactivar “build with runtime packages”
- En “Compiler” presionar el botón “Release”
- En “Advanced Compiler” activar “Pentium Pro”
Aceptar
Grabar todo( yo grabe con el nombre de “MisUDFS”)

nuevamente Project/ Build MisUDFS
y se crea el dll
ahora se debe copiar en la carpeta UDF dentro del FireBird

Para declararlas dentro de FireBird usar estas instrucciones
Código:

DECLARE EXTERNAL FUNCTION BLOBTOFILE
    BLOB,
    CSTRING(256)
RETURNS INTEGER BY VALUE
ENTRY_POINT 'BlobToFile' MODULE_NAME 'MisUDFS.dll';

DECLARE EXTERNAL FUNCTION FILETOBLOB
    CSTRING(256),
    BLOB
RETURNS PARAMETER 2
ENTRY_POINT 'FileToBlob' MODULE_NAME 'MisUDFS.dll';

Para hacer pruebas me hice una tabla
Código:

CREATE TABLE PRUEBITA (
    ID             INTEGER NOT NULL,
    NOMBREARCHIVO  VARCHAR(100),
    ARCHIVO        BLOB SUB_TYPE 2 SEGMENT SIZE 1024
);



INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (1, 'F:\Block de No-tas\dir gnuwin.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (2, 'F:\Block de No-tas\direcciones 02.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (3, 'F:\Block de No-tas\Direcciones y claves.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (4, 'F:\Block de No-tas\Escribir en titulo de ventana.txt');
INSERT INTO PRUEBITA (ID, NOMBREARCHIVO) VALUES (5, 'F:\Block de No-tas\para pintar.txt');

COMMIT WORK;

Por los datos pueden ver que poseo una unidad f: con una carpeta llamada “Block de notas” todos los nombres de archivos que están ingresados en la tabla existen en esa carpeta

Para probar FILETOBLOB y hacer que los archivos se carguen en un BLOB hice:
Código:

select NombreArchivo, FileToBlob(NombreArchivo)
from Pruebita

Para probar BLOBTOFILE primero cargue algunos archivos en los campos BLOB y luego puse:
Código:

select ID ,BlobToFile(Archivo, 'f:\PRUEBA_'||id||'.txt' )
from Pruebita
where Archivo is not null

y se crearon ficheros como “f:\Prueba_1.txt”

lo que NO PUDE HACER fue enviar el BLOB como parámetro desde el builder Crying or Very sad

en un TIBQuery puse:
Código:
select BlobToFile( :BLOB, :Archivo ) as Total
from rdb$database

pero me vota error ya que no reconoce el tipo de los parámetros

luego probe:
Código:
select BlobToFile( :BLOB, 'f:\fotito.jpg' ) as Total
from rdb$database


Trata de hacer algo pero bota un error al final

Al final para salvar el problema tuve que hacer lo siguiente:

Primero en el FireBird me cree un procedimiento almacenado
Código:

CREATE PROCEDURE XXPRUEBITA(
    ID INTEGER,
    NOMBREARCHIVO VARCHAR(100))
RETURNS (
    RID INTEGER)
AS
begin
  /* Procedure Text */
  select BlobToFile(Archivo, :NombreArchivo )
  from Pruebita
  where ID = :ID into :RID;
  RID = coalesce(:rid, 0);
  if( :RID > 0 ) then
    update pruebita set Archivo = null where id = :ID;
  suspend;
end


luego en el builder puse ibquery y un storedprocedure conectados al mismo objeto transaccion y escribi esto en un botón:
Código:

void __fastcall TForm1::btnAgregarClick(TObject *Sender)
{
  if(opd->Execute())//objeto TOpenDialog
  {
    Trans->StartTransaction();//Obeto Trasaccion comun
    qr->ParamByName("BLOB")->LoadFromFile(opd->FileName,ftBlob);
    sp->ParamByName("ID")->AsInteger = 1;
    sp->ParamByName("NombreArchivo")->AsString = edtArchivo->Text;//Aquí le paso el nombre con el que deseo grabar el fichero
    qr->ExecSQL();
    sp->ExecProc();
    try
    {
      ShowMessage(  IntToStr(sp->ParamByName("RID")->AsInteger));
    }
    __finally
    {
      Trans->Commit();
    }
  }
}

el query tiene el sgte. Sql:
Código:
 update pruebita
set Archivo = :BLOB
where id = 1


y el objeto storedprocedure esta conectado a mi procedimiento “xxPruebita”

de esta forma he logrado enviar un fichero al servidor y que lo grabe en una carpeta.

Bueno amigos por favor revisenlo, estudienlo. No estoy seguro si realmente es multihilo, y si alguien logra enviar un fichero directamente al servidor sin valerse el procedimiento almacenado que por favor nos lo enseñe.

Si alguien pudiese convertirlo para linux seria muy interesante tambien.

Bueno seguiré investigando, esto de las UDFS me esta requetegustando. Razz
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Hola cecito, la verdad es que espectacular lo que lograste hacer en solo un día.

Apenas me haga un tiempito, lo pruebo y te contesto.
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola cecito, te cuento que acabo de probar tu udf y me gusto.

Logre crearla y declararla sin ningun problema.

En vez de usar archivos de texto, use imágenes y me anduvo bien.

use un query para traerme la tabla
Código:
SELECT  ID, NombreArchivo, FileToBlob(NombreArchivo) AS FOTO
from Pruebita

y anduvo perfecto

tambien probe haciendo una vista
Código:
CREATE VIEW VISTA_BLOB (ID, NOMBRE, FOTO)
AS
  SELECT ID, NOMBREARCHIVO, FileToBlob(NombreArchivo)
  FROM PRUEBITA;

y tambien anduvo perfecto.

mostre las imagenes en un TDBImage y las va trayendo de acuerdo al registro seleccionado.

Para enviar las fotos tuve bastantes dificultades.

En tu codigo de CBuilder le envias tres parámetros mientras que el procedimiento almacenado (SP) solo recibe dos Confused Confused Confused

Tampoco me convencio que crees la tabla con un campo blob, asi que no la cree al principio, pero tu SP no se puede cargar si no lo creas.

La verdad es que no pude ejecutar en un SP propio la función BlobToFile, no se cual es mi problema, quise armar algo asi:
Código:
CREATE PROCEDURE INSERTAR (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
AS
BEGIN
  INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
    VALUES (:ID, :NOMBRE);

// aca esta el problema, no se como hacer que se guarde la foto
select ID , BlobToFile(:FOTO, :NOMBRE)
from Pruebita;

END^


pero no compila de ninguna forma

Estas son mis pruebas por ahora, cuando haga algo mas te comento.
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola Crandel, creo que la vez pasada no me explique bien, pero ahora lo corrijo.

Desde Builder no pude enviar un parámetro tipo BLOB , en otras palabras la función solo me esta aceptando un parámetro BLOB si es que este parámetro existe como campo de una tabla por eso esto es válido
Código:

select ID ,BlobToFile(Archivo, 'f:\PRUEBA_'||id||'.txt' )
from Pruebita
where Archivo is not null

Puesto que el campo "Archivo" pertenece a la tabla pruebita, pero este otro:
Código:
select BlobToFile( :BLOB, :NombreArchivo ) as Total
from rdb$database

No lo acepta por que el parámetro :BLOB no es un campo de la base de datos.

Entonces para solucionar este impase hice las sguientes acciones.
1.- Enviaba un parámetro :BLOB a actualizar un campo blob de una tabla( osea guardaba el BLOB en la tabla), todo esto por medio de un query.
2. Utilizaba un Procedimiento almacenado que buscara en esta tabla al registro que se habia actualizado y su campo blob lo guardaba en un fichero, luego de no haber errorres borrara el contenio de ese campo blob asignadole NULL .

Para lograr esto coloque un query(qr) y un storedprocedure(sp) los dos conectados al mismo objeto transacction(Trans) ( la base de datos tiene su propia Transaccion - TransDB ).

En el query(qr) puse:
Código:
update pruebita
set Archivo = :BLOB
where id = 1

En el StroredProcedure(sp) lo conecte a mi procedimiento "xxxPruebita"( como lo indique antes)
Luego , en el builder puese:
Código:
void __fastcall TForm1::btnAgregarClick(TObject *Sender)
{
  if(opd->Execute())//objeto TOpenDialog
  {
    Trans->StartTransaction();//Obeto Trasaccion comun
    qr->ParamByName("BLOB")->LoadFromFile(opd->FileName,ftBlob);
    sp->ParamByName("ID")->AsInteger = 1;
    sp->ParamByName("NombreArchivo")->AsString = edtArchivo->Text;//Aquí le paso el nombre con el que deseo grabar el fichero
    qr->ExecSQL();
    sp->ExecProc();
    try
    {
      ShowMessage(  IntToStr(sp->ParamByName("RID")->AsInteger));
    }
    __finally
    {
      Trans->Commit();
    }
  }
}


Espero que ahora si puedas recrear lo que hice.

No se donde habia leido que no se podia pasar prámetros BLOB a los procedimientos por eso ni lo intente, voy a revisar tu "procedure" y te cuento.Laughing
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Hey amigo Crandel diste en el clavo. yeeeeeeee Very Happy

He creado el Siguiente Procedimiento:

Código:
CREATE PROCEDURE xxPrueba2 (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
RETURNS (
    RID INTEGER)
AS
--DECLARE R INTEGER = 0;--Forma simplificada de declarar una variable
BEGIN
  INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
    VALUES (:ID, :NOMBRE);
-- Un select siempre debe devolver sus valores a variables( el "into" )
  select BlobToFile(:FOTO, :NOMBRE)
  from rdb$database into :RID;
--rdb$database es una tabla de sistema que siempre devuelve un registro
--Devolvemos el valor de RID, si es mayor a cero no hubo problemas
  suspend;
END

Borre el campo BLOB de mi tabla Pruebita y a quedado ahora asi:
Código:
CREATE TABLE PRUEBITA (
    ID             INTEGER NOT NULL,
    NOMBREARCHIVO  VARCHAR(100)
);

En el Builder coloque los siguientes controles en un formulario:
- Un TIBDatabase(llamado db) conectado a su propio objeto TIBTransaction(TransBD) y perfectamente enlazado a la base de datos
- Un objeto TIBStoredProcedure(sp2) conectado a su propio objeto Transaction(Trans) el cual esta conectado a la base(db)
- Un TOpenPictureDialog(opd)
- Un TEdit(edtID)
- Un Botón(btnInsertar)

y puse este código:
Código:

//Agrega esta libreria para que el TOpenPictureDialog muestre archivos JPG
#include <jpeg.hpp>

void __fastcall TForm1::btnInsertarClick(TObject *Sender)
{
  if(opd->Execute())
  { AnsiString tmp;
    int ID = edtID->Text.ToIntDef(100);
    tmp.printf("F:\\FotosBD\\BD%d%s",ID,ExtractFileExt(opd->FileName));
    Trans->StartTransaction();
    sp2->ParamByName("ID")->AsInteger = ID;
    sp2->ParamByName("Nombre")->AsString = tmp;
    sp2->ParamByName("FOTO")->LoadFromFile(opd->FileName,ftBlob);
    sp2->ExecProc();
    try
    {
      ShowMessage(  IntToStr(sp2->ParamByName("RID")->AsInteger));
    }
    __finally
    {
      Trans->Commit();
    }
    edtID->Text = IntToStr(ID+1);//Para evitar Ingresar a cada rato el ID
  }
}

Todos los archivos se graban en la siguiente ruta "F:\FotosBD" y los archivos los estoy guardando con los sgtes. nombres:
Código:
BD<ID>.<Extensión original>
ejem.  "F:\FotosBD\BD1232.JPG" o "F:\FotosBD\BD111.BMP"

Si todo va bien al ejecutar el procedimiento mostrara un "ShowMessage" con la cantidad de bytes grabados.

Que falta ahora en la UDF:
- Verificar si un archivo existe o no.
- Crear la carpeta donde se va ha grabar el archivo si es que no existiese.
- Crear algo llamado "CrearCarpeta" para que la base de datos pueda crear carpetas
- Tambien cosas como "BorrarCarpeta", "BorrarArchivo" , "ExisteCarpeta" o "ExisteArchivo"

Me gustaría que usemos un "C/C++" lo más estandarizado posible dentro de las funciones para que asi podamos migrarlo a linux( es que al final mi FireBird va ha correr en Linux Rolling Eyes )

Sigo con las pruebas, cualquier correción que haga se las indico, bye Razz
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Te cuento que termine creando el procedimiento almacenado asi:

Código:
CREATE PROCEDURE INSERTAR (ID INTEGER, NOMBRE VARCHAR(100), FOTO BLOB)
RETURNS (RID INTEGER)
AS
BEGIN
  INSERT INTO PRUEBITA(ID, NOMBREARCHIVO)
    VALUES (:ID, :NOMBRE);

  // al asignar el valor a una variable, no hace falta usar el select
  RID = BlobToFile(:FOTO, :NOMBRE);
END


voy a intentar aportar algo a la udf, cuando consiga algo mejor te cuento.
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola cecito, recien me puse de nuevo con la udf.

Algunos puntos:

1. Alguna razón en especial para manipularlos como C y no como C++?

2. Me puse primero con la función BlobToFile para cerrarla, porque parece la mas terminada y estuve revisando el porque el tamaño del bloque de lectura. Por lo visto la función blob_put_segment no acepta mas que ese tamaño, esto es raro porque vos la definiste como un USHORT y no como short.
Buscando en los manuales de interbase no dicen nada del tipo de dato, en los que tengo de firebird no dice nada de la estructura.

Ahora me voy a poner con la otra función.
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola Crandel sabes tambien estoy un poco confundido. en el manual Developer Guide de Interbase 6 definen esta estructura para los BLOBs(pag. 91).
Código:
typedef struct blob {
void (*blob_get_segment) ();
int *blob_handle;
long number_segments;
long max_seglen;
long total_size;
void (*blob_put_segment) ();
} *Blob;

En la UDF rFunc( unas udfs rusas usan esto otro, aunque lo tenian comentado ):
Código:
typedef struct blob {
   ISC_STATUS (*blob_get_segment) (
      isc_blob_handle *,
      char *,
      unsigned short,
      unsigned short *);
   isc_blob_handle *blob_handle;
   ISC_LONG blob_number_segments;
   ISC_LONG blob_max_segment;
   ISC_LONG blob_total_length;
   ISC_STATUS (*blob_put_segment) (
      isc_blob_handle *,
      char *,
      unsigned short);
} *BLOB;

Revisando en el codigo fuente del interbase 6 encontre esto:
Código:
static SSHORT   blob_get_segment (BLB, UCHAR *, USHORT, USHORT *);
static void   blob_put_segment (BLB, UCHAR *, USHORT);
static SLONG   blob_lseek (BLB, USHORT, SLONG);

Ahora revisando los fuentes de esta UDF FreeAdhocUDF ( del año 2004) define esto otro:
Código:
ypedef struct blob {
    short   (*get_segment)(
             isc_blob_handle *blob_handle,
         void *buffer,
         long bytes_to_read,
         long *bytes_read);
    isc_blob_handle *blob_handle;
    long   blob_number_segments;
    long   blob_max_segment;
    long   blob_total_length;
    void   (*put_segment)(
             isc_blob_handle *blob_handle,
         void *buffer,
         long bytes_to_write);
    long   (*seek)();
};

Revisando las blobudflib ( en pascal) lo definen asi:
Código:
 TISC_BlobGetSegment = function(BlobHandle: PInt;
                                 Buffer: PChar;
                                 BufferSize: Long;
                                 var ResultLength: Long): Short; cdecl;
  TISC_BlobPutSegment = procedure(BlobHandle: PInt;
                                  Buffer: PChar;
                                  BufferLength: Short); cdecl;
  TBlob = record
    GetSegment         : TISC_BlobGetSegment;
    BlobHandle         : PInt;
    SegmentCount       : Long;
    MaxSegmentLength   : Long;
    TotalSize          : Long;
    PutSegment         : TISC_BlobPutSegment;
  end;
  PBlob = ^TBlob;

Al revisar todo esto uno ve que no se tiene claro el tipo del último parámetro de la función "get_segment" ya que es un puntero, que algunos lo definen con short o unsigned short ( 16 bits) y otros como long(32 bits) creo que es aqui donde podria darnos error.

A ver si nos echan una mano y encontramos la correcta definición de estos dos punteros a función:
- get_segment
- put_segment

Ahora contestando tus preguntas:
1) Hice el proyecto como C por que un documento que encontre me enseño a crear una udf simple con estas indicaciones, no lo he probado como C++ pero supongo que debe funcionar.

2) Revisando algunas UDFS, vi que usaban de forma arbitraria 8Kb otros 16KB y decidi probar con 32KB realmente no he usado ninguna informacion tecnica específica para colocar este número Laughing

Ahora me encuentro viendo la posibilidad de implementarla en linux, a ver como ve va Rolling Eyes

Sigo investigando, nos vemos mas rato... Laughing
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Me he puesto a revisar el código fuente del Firebird 1.5 y tambien la libreria "iBase.h" que incluimos en el proyecto y descubri esto:
Código:
/* Blob passing structure */

enum lseek_mode {blb_seek_relative = 1, blb_seek_from_tail = 2};

typedef struct blobcallback {
    short ( *blob_get_segment)
      (void * hnd, unsigned char* buffer, ISC_USHORT buf_size, ISC_USHORT* result_len);
    void         *blob_handle;
    ISC_LONG   blob_number_segments;
    ISC_LONG   blob_max_segment;
    ISC_LONG   blob_total_length;
    void ( *blob_put_segment)
      (void * hnd, unsigned char* buffer, ISC_USHORT buf_size);
    ISC_LONG ( *blob_lseek)
      (void * hnd, ISC_USHORT mode, ISC_LONG offset);
}  *BLOBCALLBACK;
#endif /* !defined(JRD_VAL_H) && !defined(REQUESTER) */


Por lo que se ve aquí se encuentra ya definida la estructura con todos los parámetros, para probarla en el proyecto comente la estructura que se habia puesto y agregue esta línea para que no se tenga que hacer muchas modificaciones en el código:
Código:
typedef BLOBCALLBACK TBLOB;
y compila perfectamente. Asi que ya esta solucionado lo de los tipos de parámetros que se deben pasar( era "unsigned short *" o "USHORT*").

Bueno sigo investigando. Laughing
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Cuidado con almacenar en disco Responder citando

Hola, hoy acabo de llegar exactamente a los 21844 archivos guardados dentro de una carpeta de Windows.

La forma en que almacenaba y recuperaba los datos los estaba por reemplazar por esta udf.

Pero hoy la máquina se taro y mi programa comenzó a comportarse de forma extraña. Despues de un largo rato sin descifrar que era me di cuanta que Windows 98 no me permitia seguir guardando archivos en el disco Mad

Por supuesto al disco le sobra lugar. y la maquina es un P4, asi que esto no debía ser limitante.

Por lo que me estoy replanteando la forma de guardar las imágenes y parece que van a terminar dentro de la DB, algo que no quería porque en antes el servidor funcionaba en una maquina muy chica Pentium 100MHz con poca RAM, y las fotos supuestamente solo permanecerían un tiempo limitado.

Muy loco.
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mensaje    Asunto: Responder citando

Hola Crandel, ya estaba considerando la posibilidad de que no se pueda grabar muchos archivos en una carpeta y tú me lo acabas de confirmar. Habia leido que en una carpeta y con formato FAT32 puede, en teoría, almacenar 65.534 archivos o subcarpetas, pero esto es cierto solamente si los nombres de archivo usan el formato de DOS de 8.3 caracteres, que es más corto. El número total de archivos por carpeta se reduce drásticamente cuando los archivos usan nombres más largos.

Ahora esto va ha ser un problema, uhmmm, dejame idear una forma para que la UDF grabe los archivos en subcarpetas dentro de nuestra carpeta principal y los pueda recuperar de ellas, todo de esto de forma transparente para nosotros, se me ocurre aplicar la busqueda HASH pero con las subcarpetas..

Tal vez se te ocurra otra forma más elegante de salvar este problema, me la indicas para trabajarla juntos.

Estaremos en contacto. Very Happy
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Hola Crandel indicastes antes que habias grabado "21844 archivos" podrias indicarse si has usado nombres de 8 letras para los archivos o has usado nombres mas grandes.
Volver arriba
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

Todos los archivos tenian 18 caracteres (14 del nombre + punto + extención).
_________________
Crandel

"hay 10 tipos de personas, las que ven en binario y las que no"

Angel Zeitoune - Artículo: Generación de eventos en C++Builder
Volver arriba
Ver perfil de usuario Enviar mensaje privado Visitar sitio web del autor MSN Messenger
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.