PDA

Ver la Versión Completa : charset ASCII a UTF8 Firebird


novato_erick
13-09-2022, 00:08:24
Hola Chicos que tal?

Hace apenas 22 días he notado un comportamiento despues de usar las versiones de Firebird 2.x sin ningún problema despues de casi 10 años :) no habia tenido la necesidad de migrar pero ultimamente con 22 conexiones simultaneas me ah estado bloqueando las transacciones y buscando el mensaje de error en los log de Firebird aparece la sugerencia que ese problema se da en las versiones 2.5.x


SERVERFERRE (Client) Thu Sep 01 12:38:45 2022
REMOTE INTERFACE/gds__detach: Unsuccesful detach from database.
Uncommitted work may have been lost

SERVERFERRE (Server) Thu Sep 01 12:39:35 2022
Shutting down the server with 22 active connection(s) to 1 database(s), 1 active service(s)


SERVERFERRE (Client) Thu Sep 01 12:39:42 2022
Guardian starting: "C:\Program Files (x86)\Firebird\Firebird_2_5\bin\fbserver.exe"


A la hora de realizar respaldo para luego actualizar usando GBAK a 3.0
manda estos errores:

gbak:restore failed for record in table PROVEEDORES
Error: gbak: ERROR:Malformed string
gbak:Invalid data detected. Use -FIX_FSS_DATA option.

trate de corregirlo usando: -FIX_FSS_DATA ASCII -FIX_FSS_METADATA ASCII pues en teoría está la Base de datos en ASCII.

C:\Program Files (x86)\Firebird\Firebird_3_0>gbak -r o -v -p 16384 -user SYSDBA -password masterkey -FIX_FSS_DATA ASCII -FIX_FSS_METADATA ASCII "C:\EDD MIPROGRAMA\BDASCII.FBK" "C:\EDD MIPROGRAMA\BDASCII.FDB"


en fin mi programa obvianmente la estructura de la DB está hace 15 años más o menos casi nunca toco la DB pero a estas altura en base a la experiencia de ustedes me recomendaría pasar a UTF8 y ¿cual sería el mejor medio?

Saludos;

novato_erick

novato_erick
13-09-2022, 00:15:07
Bueno leyendo las ayuda que aquí mismo la comunidad del Club encontré este post por el amigo Casimiro de hace buen tiempo: https://clubdelphi.com/foros/showthread.php?t=90783
la cual creo que dejaría a un lado el UTF8.

aún mi pregunta de la recomendación está en pié para que alguien me responda.

Saludos nuevamente;

novato_erick

duilioisola
13-09-2022, 08:36:17
Yo hace un tiempo migré la base de datos a UNICODE.
La base de datos tenía el charset NONE, por lo que admitía cualquier cosa que le pusieras y no hacía ninguna transformación.
Cuando empecé a entrar y leer datos desde diferentes sistemas empezaron a generarse muchos conflictos:
Desde la web se metía texto en formato UTF-8 y desde Windows se leia como WIN-1252. Lo mismo sucedía cuando se escribía en windows y se leia en la web.

La solución:
Poner los campos texto (CHAR, VARCHAR, BLOB tipo texto) a charset UNICODE.
Luego en la conexión a la base de datos le dices qué charset utilizas y entre el cliente y el servidor hacen la transformación necesaria.

Nota:
Yo trabajo con un Delphi viejo (Delphi 6) por lo que no adminte UTF8 como Charset.

Ejemplo:

-- Definicion de campo de texto con CHARST UNICODE
CREATE DOMAIN DESCRIPCIONES AS VARCHAR(256) CHARACTER SET UNICODE_FSS
DEFAULT ''
NOT NULL
COLLATE UNICODE_FSS


// Conexión a la base de datos indicando el Charset con el que quiero leer los datos
with DataBase do
begin
try
// Probamos conexion
if not TestConnected then
begin
DBName := Entorno.BaseDeDatos;
DBParams.Clear;
DBParams.Values['user_name'] := Entorno.UsuarioBD;
DBParams.Values['password'] := Entorno.ClaveBD;

// El charset de la conexion: Normalmente en Windows en castellano WIN1252
if (Entorno.CharsetBD <> '') then
DBParams.Values['lc_ctype'] := Entorno.CharsetBD;

if (Entorno.RolBD <> '') then
DBParams.Values['sql_role_name'] := Entorno.RolBD;
Log(format('Conectando. user_name: %s, password: %s, sql_role_name: %s', [DBParams.Values['user_name'], DBParams.Values['password'], DBParams.Values['sql_role_name']]));
Open;
end;
except
on e: Exception do
begin
try
if (Assigned(FLogo)) then
FLogo.Hide;
except
end;
ShowMessage(Format(_('Imposible abrir %s' + #13#10 + 'user_name: %s, sql_role_name: %s.') + #13#10 + e.Message, [Entorno.BaseDeDatos, Entorno.UsuarioBD, Entorno.RolBD]));
end;
end;
end;

duilioisola
13-09-2022, 09:06:30
Para migrar la base de datos me hice una pequeña aplicación que leia la estructura de la base de datos y crea otra modificando los campos "texto" para agregarles el CHARSET (CHARACTER SET UNICODE_FSS).

UNICODE es el sistema para identificar a cada caracter (cientos de miles en este momento).
UTF-8 es una forma de codificar UNICODE tratando de reducir el espacio necesario.
UTF-16, UTF-32: Lo mismo que UTF-8 pero sacrificando espacio.
WIN1250, WIND1251, WIN1252, ISO8859, etc.: Son mapas de caracteres. Solo contienen algunos. Por ejemplo la Ñ está en algunos juegos de caracteres y en otros, la posición de ese carater representa otro distinto.
ASCII: Es el juego mas limitado de 256 caracteres.
NONE: En Firebird, se refiere a que tomará los bytes que se le pase y los guardará sin interpretar dentro del campo de texto. A quien lea también se le enviarán esos bytes. Esto puede dar lugar a malas interpretaciones.

Por ejemplo:
TEXTO tiene CS=NONE
Conexión CS=NONE
insert into PRUEBA(TEXTO)values('Artículo') <-- Con acento en la I

Conexión CS=WIN1252
select TEXTO from PRUEBA(TEXTO)
Resulta en 'artÃ*culos'


TEXTO tiene CS=UNICODE_FSS
Conexión CS=UTF-8 desde la web
insert into PRUEBA(TEXTO)values('Artículo') <-- Con acento en la I

Conexión CS=WIN1252 desde Windows
select TEXTO from PRUEBA(TEXTO)
Resulta en 'artículos' porque el cliente Firebird transforma de UNICODE_FSS a WIN1252

novato_erick
13-09-2022, 15:28:41
duilioisola:
Desde la web se metía texto en formato UTF-8 y desde Windows se leia como WIN-1252. Lo mismo sucedía cuando se escribía en windows y se leia en la web.


Hola es correcto eso mismo es lo que me pasa igual intente cambiar a nivel de interfaz el tipo de codificación la info que provenia de la base de datos resultando muchas veces frustrada.

Este ejemplo para mi me resulta muy simple y comprensivo, no tengo una gran especialidad en Base de Datos lo que manejo me ah sido útil y funcional Aqui es donde uso la frace de todo programador: Si funciona no lo toques :D.


Por ejemplo:
TEXTO tiene CS=NONE
Conexión CS=NONE
insert into PRUEBA(TEXTO)values('Artículo') <-- Con acento en la I

Conexión CS=WIN1252
select TEXTO from PRUEBA(TEXTO)
Resulta en 'artÃ*culos'


TEXTO tiene CS=UNICODE_FSS
Conexión CS=UTF-8 desde la web
insert into PRUEBA(TEXTO)values('Artículo') <-- Con acento en la I

Conexión CS=WIN1252 desde Windows
select TEXTO from PRUEBA(TEXTO)
Resulta en 'artículos' porque el cliente Firebird transforma de UNICODE_FSS a WIN1252



y realmente este tema suena interesante

Para migrar la base de datos me hice una pequeña aplicación que leia la estructura de la base de datos y crea otra modificando los campos "texto" para agregarles el CHARSET (CHARACTER SET UNICODE_FSS).


Excelente aporte para migrar la DB. En teoría usando UNICODE pasará sin problema?, lo que me das a entender es simplemente pasar la estructura a UNICODE y luego su metadatos a la ultima versión de Firebird eso en teoría me quitará los dolores de cabeza de usar un Backup para luego Restaurar suena simple pero algo de trabajo no estaría mal.

suena interesante lo de tu "Pequeña aplicación" ya que yo utilizo SQL Manager Personal para exportar extructura pero el tuyo extrae y crea otra con la modificación de datos no quiero sonar perezoso pero tendría un costo si es asi escribeme en el privado o por aquí para que los participantes podamos conocer dicho aporte.

Agradezco tu pronta y esperada respuesta;

Saludos;

novato_erick

Casimiro Notevi
13-09-2022, 16:57:33
Creo que con que cambies los campos implicados por utf8 ya irá bien.
Y si estás usando dominios (que siempre es lo más adecuado) será más fácil porque sólo tendrás que cambiar su declaración.
/* create domain domNombre varchar(64) character set ISO8859_1; /* fb < 2.1 */
create domain domNombre varchar(64) character set UTF8 collate ES_ES_CI_AI default ''; /* fb >= 2.1 **/
Eso sí, lo mismo tendrás que "recodificar" los datos que tengas guardados ya, hacer un update leyendo lo que hay y convirtiéndolo al nuevo formato.

duilioisola
13-09-2022, 18:02:43
Dado el interés, os dejo aquí la aplicación para leer una Base de Datos Firebird y crear otra con los campos texto con Charset UNICODE_FSS.

Esta aplicación utiliza los componentes FreeIB y está desarrollada en Delphi 6.
Creo que está todo contenido dentro del ZIP.
Además, está la aplicación compilada, lista para utilizar.

Pedirá una base origen y su CharSet.
En mi caso el CharSet es NONE.

La base destino no debería existir, para que la aplicación la cree antes de traspasar los datos de una a otra.

Los Checks arriba a la derecha son todos los datos que se van a traspasar.
Iniciará traspasando los de la primera columna en orden (Generators, Exceptions, Domains, Tables)
Luego hará el "Data Pump" en donde tratará de leer los datos y escribirlos en la base de datos destino.
En este punto podrían darse problemas de "Transliterate". Esto es problemas donde no puede convertir lo que lee en Unicode válido.

Luego de esto, con las tablas pobladas, pasará a crear el resto de estructura de la base (PK, Unique Indices, FK, ...)

Cuando llega a pasar procedimientos, he hecho un algoritmo para tratar de pasarlos en orden de dependencia. Hace cinco pasadas y reordena los procedimientos lo mejor que puede... Espero que no os falle.

A tener en cuenta:
Ya que es un proyecto para mis bases de datos, hay alguna cosa que podría fallar y vuestras bases.

procedure TFMMain.TraspasarTables;
Si el dominio de un campo de una tabla es IMAGEN, lo crea con el dominio IMAGENES en destino.
Si el dominio de un campo de una tabla es IMAGEN_P, lo crea con el dominio IMAGENES en destino.
Si el dominio de un campo de una tabla es binario (BLOB SUB_TYPE 0), lo crea con el dominio IMAGENES en destino.
Si el dominio de un campo de una tabla es NOTAS_UNICODE, lo crea con el dominio NOTAS en destino.
Si el dominio de un campo de una tabla es PROTECCION, lo crea con el dominio NOTAS en destino.
Si el dominio de un campo de una tabla es APUNTES, lo crea con el dominio NOTAS en destino.
Si el dominio de un campo de una tabla es TEXTO, lo crea con el dominio NOTAS en destino.
Si el dominio de un campo de una tabla es blob tipo texto (BLOB SUB_TYPE 1), lo crea con el dominio NOTAS en destino.

procedure TFMMain.Pump;
Si el campo se llama ARTICULO reemplazo ñ, Ñ por N. (En mi base de datos, esto es el código de un artículo y no permito esos caracteres.)

Si por algún motivo alguien necesita algo un poco más especial o necesita que quite las transformaciones que he hecho, puede modificar el código y recompilarlo.
Si esto no fuera posible, enviarme un mensaje privado y trataré de adaptar el código.
Si tampoco fuera posible, y sigue fallando nos ponemos en contacto y si me pasáis vuestra base de datos. Con esto seguro que podré hacer las modificaciones necesarias.

Saludos,

novato_erick
13-09-2022, 18:50:59
duilioisola

Si el campo se llama ARTICULO reemplazo ñ, Ñ por N. (En mi base de datos, esto es el código de un artículo y no permito esos caracteres.)


Si tienes razón igual ya no lo permito anivel de interfaz aunque unos usuarios me preguntan porque no lo incluyo pero aunque trate de explicar no entenderán a nivel interno de una DB :confused:

Saludos^\||/

novato_erick
13-09-2022, 18:56:20
Creo que con que cambies los campos implicados por utf8 ya irá bien.
Y si estás usando dominios (que siempre es lo más adecuado) será más fácil porque sólo tendrás que cambiar su declaración.
/* create domain domNombre varchar(64) character set ISO8859_1; /* fb < 2.1 */
create domain domNombre varchar(64) character set UTF8 collate ES_ES_CI_AI default ''; /* fb >= 2.1 **/
Eso sí, lo mismo tendrás que "recodificar" los datos que tengas guardados ya, hacer un update leyendo lo que hay y convirtiéndolo al nuevo formato.

Estoy en proceso de buscar la mejor manera de Adaptar mi DB a nuevos requerimientos y lo había contemplado pero esto de migrar no es algo sencillo.

Honestamente eso de Dominio lo lo habia contemplado si no es que lo mencionas pasaría por desapersivido dicha información Casimiro gracias la leí lo útil que es.

en Fin de Ascii a otro dipo de Charset todo incurre por los cambios que maneja Firebird si no hubiera incurrido a la necesidad de actualizar a 4.0 creo que todo estaría de maravillas tal cual ha pasado hasta entonces.

les comentaré más adelante cómo les fue. Les agradezco enormemente sus aportes a
duilioisola y Casimiro v:-)v

Saludos;

Casimiro Notevi
13-09-2022, 19:24:59
... en Fin de Ascii a otro dipo de Charset todo incurre por los cambios que maneja Firebird si no hubiera incurrido a la necesidad de actualizar a 4.0 creo que todo estaría de maravillas tal cual ha pasado hasta entonces.... Creo recordar que está desde la v2.1

novato_erick
13-09-2022, 19:49:40
Creo recordar que está desde la v2.1

Correcto amigo;


Pero hay dolores de migrar desde la versión 2.5x a la 3 o 4 de Firebird con los Charset