Firebird 3: software de 32 bits y de 64 bits

8 comentarios

Si nuestro Servidor es Firebird 3, debemos recordar lo siguiente:

  1. Si la aplicación que deseamos ejecutar fue compilada en 32 bits (nuestra propia aplicación, IBExpert, FlameRobin, etc.) entonces se requiere el archivo FBCLIENT.DLL de 32 bits, aún cuando el Servidor del Firebird 3 sea de 64 bits. Si es nuestra aplicación la que fue compilada en 32 bits entonces lo aconsejable es que el archivo FBCLIENT.DLL de 32 bits se encuentre en la misma carpeta en la cual se encuentra nuestro .EXE, así evitamos confusiones con otros archivos FBCLIENT.DLL que pudieran encontrarse en la misma computadora.
  2. Un Servidor Firebird 3 de 64 bits puede aceptar conexiones de un FBCLIENT.DLL de 32 bits o de 64 bits, indistintamente. Un Servidor Firebird 3 de 32 bits solamente puede aceptar conexiones de un FBCLIENT.DLL de 32 bits.
  3. La ODS (On Disk Structure) de una Base de Datos creada con Firebird 3 es exactamente la misma, sea que esa Base de Datos haya sido creada con la versión de 32 bits o con la versión de 64 bits.
  4. No se debe permitir la conexión a una Base de Datos con el Servidor de 32 bits y con el Servidor de 64 bits al mismo tiempo. O con el uno, o con el otro, pero no con ambos a la vez porque eso corromperá a la Base de Datos.

Artículos relacionados:

¿Qué es la versión de ODS?

Firebird 3: usando bases de datos anteriores

El índice del blog Firebird21

El foro del blog Firebird21

 

 

 

Solamente llamar a vistas y a stored procedures

4 comentarios

Una característica que siempre se ve en el código fuente de las aplicaciones bien escritas es que solamente llaman a vistas y a stored procedures.

Y a fuer de ser sinceros, tales aplicaciones son escasas, muy escasas.

Muchos programadores escriben en el código fuente de sus aplicaciones los comandos INSERT, UPDATE, DELETE, y SELECT a columnas de tablas.

Y eso está mal, muy mal.

¿Por qué?

Bueno, hay varios motivos. El autor de este blog varias veces ha evaluado aplicaciones y códigos fuentes escritos por otras personas y al finalizar la evaluación ha elevado un informe detallando lo bueno y lo malo que encontró. Y en el capítulo “Comunicación con la Base de Datos” estos son algunos problemas:

  1. El código fuente es desprolijo. Si alguien escribe los comandos mencionados más arriba en general lo hace de forma desordenada, calculando valores de variables, o realizando otras tareas no relacionadas, y eso además de no ser eficiente queda “feo”.
  2. No permite el trabajo en equipo. Cuando se trabaja en equipo lo ideal es modularizar al máximo para que cada función o cada rutina sea escrita una sola vez y utilizada por muchos programadores. De esa manera si hay algún error solamente puede estar en un lugar y será fácil encontrarlo y corregirlo. Pero si cada quien escribe los comandos en su propio código fuente entonces los errores pueden estar en muchos lugares y encontrarlos y corregirlos demorará mucho más tiempo. Y cualquier cambio a cualquiera de los códigos fuente puede introducir un nuevo error. Y esto inclusive puede ocurrir aunque se trate de un solo programador pero que tiene por ejemplo el INSERT a una sola tabla en dos o más programas.
  3. No hay un responsable de la Base de Datos. Cuando se trabaja en equipo una persona debe ser la encargada de verificar el correcto diseño y funcionamiento de la Base de Datos. Si cada programador escribe lo que se le ocurre en su propio código fuente, tales verificaciones serán imposibles de realizar y los errores posibles, muchísimos.
  4. No se puede verificar que el comando finalizará sin error hasta el momento de ser ejecutado. Por ejemplo, mirando un INSERT en el código fuente no se puede tener la seguridad de que esa fila será insertada o que ocurrirá una excepción de “table unknown”, “column unknown” o alguna otra.
  5. No se puede comprobar la eficiencia del comando. Este es el punto más importante. Los programas de administración gráfica, como el EMS SQL Manager, nos muestran la cantidad de filas leídas, la cantidad de filas extraídas, y en forma gráfica los índices usados. También podemos ver el PLAN utilizado. Así es fácil descubrir que no se está usando un índice cuando sí debería usarse, o que las filas leídas son demasiadas, o que se está usando el índice incorrecto, etc. Y es muy fácil y muy rápido cambiar la vista o el stored procedure con la intención de hacerlo más eficiente. Sin embargo, si escribimos los comandos dentro del código fuente de una aplicación es imposible saber si es eficiente o no lo es. Podemos “creer” que es eficiente y que usa los índices correctos, cuando en realidad no es así. Y hay además otro problema: aunque hoy una vista o un stored procedure sean muy eficientes, podrían dejar de serlo dentro de unos meses cuando las tablas tengan más filas o se hayan cambiado o borrado algunas filas. Escribiendo los comandos INSERT, UPDATE, DELETE, y SELECT a columnas de tablas dentro del código fuente de nuestras aplicaciones jamás podremos estar seguros de que son los más eficientes que podemos tener, en cambio si dichos comandos están dentro de una vista o dentro de un stored procedure sí que podremos tener esa seguridad.

VISTAS-STORED-1

Captura 1. Si haces clic en la imagen la verás más grande

VISTAS-STORED-2

Captura 2. Si haces clic en la imagen la verás más grande

Mirando la Captura 1. sabemos que la vista involucra a 3 tablas y que las 3 tablas usan índices (e inclusive sabemos los nombres de esos índices), y que la cantidad de filas parece estar correcta, sin embargo … ese SORT en la Captura 2. nos llama poderosamente la atención porque los SORT son muy lentos, ya que deben ordenar las filas de las tablas; ese ordenamiento se realiza en la memoria del Servidor (cuando tal cosa es posible) o en el disco duro (cuando no puede ordenarse en la memoria). En general, debemos evitar a los SORT como a la peste, porque indican que la tabla, la vista, el stored procedure seleccionable, o los resultados deberán ser ordenados, y eso puede demorar muchísimo tiempo en tablas grandes.

Si en lugar de escribir una vista, como en el ejemplo de arriba, hubiéramos escrito un SELECT en el código fuente de nuestro lenguaje de programación, ¡¡¡jamás nos habríamos percatado de ese SORT malévolo!!!. Y claro, cuando las tablas tuvieran muchas filas los usuarios se quejarían de la lentitud, pero mientras tanto les hicimos perder mucho tiempo innecesariamente porque nuestra consulta no estaba optimizada.

Conclusión:

Si quieres programar correctamente y eficientemente y profesionalmente, en el código fuente de tus aplicaciones solamente debes llamar a vistas y a stored procedures. Nunca, jamás, y por ningún motivo, ejecutar un INSERT, un UPDATE, un DELETE, o un SELECT a columnas de una tabla.

Los SELECT solamente a vistas.

Los INSERT, UPDATE, DELETE, y algunos SELECT, solamente dentro de un stored procedure.

Cuando se programan aplicaciones siempre se van encontrando errores y problemas aquí y allá. Para disminuir esa cantidad de errores y de problemas, y para optimizar las consultas y los procesamientos, siempre lo mejor es desde el código fuente de nuestras aplicaciones llamar a vistas y a stored procedures, y a nada más.

Artículos relacionados:

Optimizando las consultas

Optimizando las subconsultas

Optimizando los JOIN

Evitando que el optimizador … optimice

¿Por qué usar stored procedures?

Usando un stored procedure como una función

Escribiendo un stored procedure

Usando un PLAN

Algo más sobre PLAN

Entendiendo el contenido de un PLAN

El índice del blog Firebird21

El foro del blog Firebird21

Backups locales y backups remotos

Deja un comentario

El programa GBAK nos permite realizar backups locales y backups remotos.

  • En un backup local, la Base de Datos que está en el Servidor copiamos a nuestro disco duro local
  • En un backup remoto, la Base de Datos que está en el Servidor copiamos en el Servidor

NOTA: En todos los ejemplos de abajo el comando se ve en 3 líneas para que sea más fácil visualizarlo, pero debe escribirse en 1 sola línea.

Caso 1. Backup local

Ejemplo 1. El backup lo realiza el usuario SYSDBA o el creador de la Base de Datos

GBAK -backup -user NombreUsuario -password Contraseña 
\\SERVIDOR-PC\C:\SISTEMAS\BASESDATOS\MiBaseDatos.FDB 
C:\SISTEMAS\BACKUPS\MiBackup.FBK

Ejemplo 2. El backup lo realiza un usuario que tiene el rol RDB$ADMIN

GBAK -backup -user NombreUsuario -password Contraseña -role RDB$ADMIN
\\SERVIDOR-PC\C:\SISTEMAS\BASESDATOS\MiBaseDatos.FDB 
C:\SISTEMAS\BACKUPS\MiBackup.FBK

Ejemplo 3. El backup se hace mediante conexión por TCP/IP

GBAK -backup -user NombreUsuario -password Contraseña 
192.168.1.1:C:\SISTEMAS\BASESDATOS\MiBaseDatos.FDB 
C:\SISTEMAS\BACKUPS\MiBackup.FBK

Si el usuario que quiere realizar el backup no es SYSDBA ni el creador de la Base de Datos entonces sí o sí debe tener el rol RDB$ADMIN y además deberá especificarlo para que el backup pueda realizarse con éxito.

La Base de Datos que se encuentra en la computadora cuyo nombre es SERVIDOR-PC o cuya dirección IP es 192.168.1.1 será copiada al disco duro local del usuario. Desde luego que estos son ejemplos, en tu caso tanto el nombre de la computadora o la dirección IP pueden ser distintos. El programa GBAK puede encontrarse en el disco duro local o en cualquier otra computadora. Si se encuentra en otra computadora debe estar en una carpeta compartida o no se lo podrá ejecutar.

Caso 2. Backup remoto

Ejemplo 4. Un backup remoto usando el nombre de la computadora

GBAK -backup -service \\SERVIDOR-PC\service_mgr -user NombreUsuario -password Contraseña 
C:\SISTEMAS\BASESDATOS\MiBaseDatos.FDB 
C:\SISTEMAS\BACKUPS\MiBackup.FBK

Ejemplo 5. Un backup remoto usando la dirección IP de la computadora

GBAK -backup -service 192.168.1.1:service_mgr -user NombreUsuario -password Contraseña 
C:\SISTEMAS\BASESDATOS\MiBaseDatos.FDB 
C:\SISTEMAS\BACKUPS\MiBackup.FBK

Para que el backup remoto pueda realizarse se debe llamar al administrador de servicios o service manager de una computadora que tenga instalado al Servidor del Firebird.

Cuando se usa el service manager el backup termina más rápido, eso significa que los backups remotos son más rápidos que los backups locales.

Comentarios:

  1. El programa GBAK debe poder acceder a la Base de Datos. Para ello se puede usar la ubicación de la Base de Datos  (como en los ejemplos anteriores) o un alias que se haya especificado en el archivo ALIASES.CONF (que es lo recomendable)
  2. Como el programa GBAK copiará todo el contenido de la Base de Datos entonces solamente podrá finalizar con éxito si es ejecutado por el usuario SYSDBA, por el creador de la Base de Datos, o por un usuario que se conecte con el rol RDB$ADMIN. Eso es muy lógico, si un usuario tiene acceso restringido a una Base de Datos no se le puede permitir copiar todo el contenido de ella.
  3. La conexión a la Base de Datos puede realizarse mediante named-pipes (o sea, especificando el nombre de la computadora, como en el Ejemplo 1.) o mediante su dirección IP (como en el Ejemplo 3.)
  4. Si se quiere realizar un backup remoto entonces hay que usar la opción -service. Esta opción puede recibir un solo parámetro, el cual se llama service_mgr. El service_mgr solamente existe en las computadoras que tienen al Servidor del Firebird instalado. Por ese motivo, si la computadora desde donde se realiza el backup no tiene instalado al Servidor del Firebird hay que llamarlo al service_mgr desde una computadora que sí lo tenga instalado. Se lo puede llamar usando el nombre de la computadora (como en el Ejemplo 4.) o la dirección IP de la computadora (como en el Ejemplo 5.). Desde luego que si la computadora desde donde se ejecuta al programa GBAK tiene instalado al Servidor del Firebird entonces no será necesario escribir esos prefijos.
  5. Cuando se hace un backup remoto, la carpeta en donde se copiará el backup debe estar compartida. El programa GBAK es un programa más, para el Sistema Operativo no tiene algo de especial, es uno más del montón. Por lo tanto, para que pueda copiar el backup en una carpeta debe tener derecho de escritura en esa carpeta. Si la carpeta está en otra computadora, entonces debe estar compartida, sí o sí.
  6. Cuando se quiere realizar un backup hay que diferenciar dos cosas: 1) El programa GBAK debe poder conectarse a la Base de Datos, como si se tratara de un usuario humano más. Es por eso que debe especificarse el usuario, la contraseña, y quizás el rol. 2) El programa GBAK debe poder crear un archivo en una carpeta de un disco duro. Es por eso que debe tener permiso de escritura en esa carpeta.
  7. Cuando se realiza un backup remoto, hay que ver a la carpeta destino desde el punto de vista del Servidor. En los ejemplos 4. y 5. la carpeta C:\SISTEMAS\BACKUPS\ es una carpeta que se encuentra en la misma computadora donde se encuentra el Servidor. No es una carpeta local, es una carpeta remota, y se la ve como local, pero es local para el Servidor.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Usando Servidor y embedded en la misma aplicación (2)

Deja un comentario

En un artículo anterior ya habíamos visto las ventajas de usar Servidor y embedded en la misma aplicación. Ahora veremos otro caso donde tal aprovechamiento puede resultar muy útil.

Escenario:

En un supermercado grande hay 40 cajas, de las cuales por lo menos 15 están constantemente trabajando. Normalmente esas cajas están conectadas a una Base de Datos mediante Cliente/Servidor y si todo funciona bien entonces es lo correcto porque todas las operaciones se realizan con rapidez.

Cada vez que se realiza una venta, se registran los datos de esa venta en una de las cajas y se insertan filas a las tablas respectivas de la Base de Datos. Todo bien hasta allí.

Sin embargo, ¿qué sucedería si por alguna razón se interrumpe la conexión de una (o varias, o todas) caja/s con el Servidor?

Escribir con papel y lápiz los datos de las ventas porque la conexión con el Servidor se cortó no es una opción en un supermercado que tiene mucha clientela.

¿Y entonces, qué hacemos?

Solución:

La solución es que si la aplicación detecta que se ha interrumpido la conexión con el Servidor entonces guarde los datos de las siguientes ventas en una Base de Datos local a la cual se conectará mediante embedded.

Así, ninguna venta se perderá, las cajas seguirán trabajando normalmente, y al final del turno, al final del día, o cuando se restablezca la conexión, los datos de las ventas que se habían insertado en la Base de Datos local serán transferidos a la Base de Datos remota.

Conclusión:

Que se corte la conexión entre una computadora y la Base de Datos que se encuentra en el Servidor no es frecuente pero puede ocurrir. Nuestra aplicación debe ser lo suficientemente inteligente como para prever esa posibilidad y actuar en consecuencia, de tal manera que esa interrupción de la conexión no cause trastornos a los usuarios.

La gran mayoría de los usuarios quizás ni se entere de que en cierto momento se interrumpió la conexión de su computadora con el Servidor porque siguieron trabajando normalmente, como si tal interrupción nunca hubiera ocurrido. Para ellos, todo fue normal.

Sin embargo, nuestra aplicación sí detectó que se interrumpió la conexión y entonces en la computadora de ese usuario automáticamente empezó a utilizar una Base de Datos alternativa, o auxiliar.

Cuando la conexión se restableció, o al final del turno del cajero, o al final del día, o cuando se decidió, todo lo que estaba en la Base de Datos alternativa se copió a la Base de Datos normal, la que se encuentra en el Servidor.

De esta manera, ninguna venta se perdió, y tampoco ningún dato se perdió.

Artículos relacionados:

Usando Servidor y embedded en la misma aplicación

El índice del blog Firebird21

El foro del blog Firebird21

¿Es seguro usar Servidor y embedded al mismo tiempo?

Deja un comentario

Sí, … pero con algunas condiciones.

En ocasiones podrías querer conectarte usando Servidor (es decir: Classic, SuperClassic, o SuperServer) a una Base de Datos y en ocasiones podrías querer conectarte usando embedded. Entonces … ¿puedes hacer algo así?

Sí, pero no puedes realizar la conexión al mismo tiempo.

Veamos:

  1. Conectarse a la Base de Datos A con Servidor y a la Base de Datos A con embedded. NO PERMITIDO
  2. Conectarse a la Base de Datos A con embedded y a la Base de Datos A con Servidor. NO PERMITIDO
  3. Conectarse a la Base de Datos A con Servidor y a la Base de Datos B con embedded. PERMITIDO
  4. Conectarse a la Base de Datos A con embedded y a la Base de Datos A con embedded. NO PERMITIDO

La diferencia entre el caso 1. y el caso 2. está en quien se conectó primero a la Base de Datos A, pero sin importar quien lo haya hecho, la segunda conexión no es permitida.

Como habrás notado al mirar los casos anteriores, si te conectas por embedded, lo haces de forma exclusiva. Ninguna otra conexión a esa misma Base de Datos es permitida.

Resumiendo:

Se puede conectar usando Servidor y usando embedded en la misma computadora, pero la condición es que se haga a bases de datos distintas.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Acelerando los SORT

1 comentario

Ya sabemos que en ocasiones el Firebird necesita ordenar las filas creando archivos temporales, a esa operación se la llama SORT (ordenar, en inglés) y puede ser lenta en tablas grandes. Entonces ¿qué podemos hacer para acelerar los SORT?

  1. Pedirle que los realice en un disco rápido
  2. Pedirle que los realice en un disco RAM
  3. Asegurándonos que el espacio libre en el disco temporario sea más grande que la Base de Datos
  4. Creando los archivos temporales en un disco distinto al de la Base de Datos

Los discos tienen distintas velocidades de lectura/escritura (y distintos precios también, claro). Los más rápidos suelen ser los SSD (Solid State Disk), aunque el problema es que son más caros que los discos duros magnéticos y también tienen una menor vida útil (aunque esto último está cambiando mucho, ya que cada vez duran más tiempo).

Como los SORT requieren crear archivos temporales, y muchos de esos archivos temporales pueden llegar a ser inmensos entonces debemos buscar por todos los medios acelerar el proceso.

Usar un disco RAM es una muy buena alternativa, aunque por supuesto eso requiere que la computadora tenga mucha memoria disponible. Para saber como crear un disco RAM y que programa usar para ello, puedes leer este artículo:

Usando un disco RAM para aumentar la velocidad

 ¿Y cuánto espacio libre debe tener el disco dónde se realizarán los SORT?

Evidentemente, cuanto más, mejor. Como no podemos saber de antemano cuanto será el espacio libre que necesitará el Firebird en general se toma como parámetro el tamaño de la Base de Datos. Es casi seguro que siempre necesitará menos que eso.

Entonces, si nuestra Base de Datos tiene un tamaño de 2 Gb, con tener 2 Gb en el disco donde se crearán los archivos temporales será suficiente. Pero no olvides que las bases de datos siempre crecen entonces hay que prever más, en ese caso un disco (duro o RAM) con 4 Gb sería muy bueno.

¿Y cómo se especifica dónde se crearán los archivos temporales?

En la carpeta donde instalaste el Firebird encontrarás un archivo cuyo nombre es FIREBIRD.CONF, dentro de ese archivo hay una entrada llamada “TempDirectories”. Debes borrar el símbolo de numeral que está a la izquierda y escribir los nombres de las carpetas donde se crearán los archivos temporales. Si usarás más de una carpeta deberás separarlas con punto y coma, por ejemplo:

TempDirectories=G:\TEMP
TempDirectories=G:\TEMP;F:\FIREBIRDTEMPS

¿Qué significan esas entradas?

La primera, que todos los archivos temporales se crearán en la carpeta G:\TEMP

La segunda, que los archivos temporales se crearán en G:\TEMP y que si alguna vez no hay espacio suficiente entonces se los continuará creando en F:\FIREBIRDTEMPS

Es decir, la segunda carpeta solamente se usa si la primera carpeta se quedó sin espacio.

¿Cómo se deben especificar los nombres de las carpetas en TempDirectories?

Como el Firebird primero usará la primera carpeta, y si se queda sin espacio allí usará la segunda carpeta, entonces en primer lugar deberías escribir el nombre de la carpeta que se encuentra en el disco más rápido. Si tienes un disco RAM entonces esa primera carpeta evidentemente será la del disco RAM.

En el ejemplo de arriba si el disco G: es un disco RAM y el disco F: es un disco SSD, entonces estará perfecto, porque primero especificamos el disco más rápido.

Desde luego que puedes tener más de dos carpetas, aunque en este ejemplo se mostraron 2 carpetas tú podrías tener 3, 4, 5, las que necesites. Solamente recuerda que siempre los discos más rápidos deben ser escritos primero.

¿Por qué los discos donde se encuentran las bases de datos y los archivos temporales debe ser distinto?

Si una sola persona está usando la Base de Datos, no hay problema, porque o está creando archivos temporales o no los está creando. En ambos casos estará trabajando a la máxima velocidad posible. Pero lo normal es que a una Base de Datos estén conectadas varias personas al mismo tiempo, cada una de ellas realizando alguna operación y ahí sí el tema se complica y mucho.

¿Por qué se complica?

Tenemos dos posibilidades:

  1. Están en un disco duro magnético
  2. Están en un disco no magnético (por ejemplo, un disco SSD)

Si están en un disco duro magnético, entonces hay un cabezal que debe moverse. Ese es un movimiento mecánico y por lo tanto siempre será lento. Si un usuario hace un SORT el cabezal debe moverse a un sector del disco duro. Otro usuario hace un INSERT, el cabezal debe moverse a otro sector del disco duro. Otro usuario hace un INSERT a otra tabla y nuevamente el cabezal debe moverse. Si los usuarios están ejecutando las operaciones de INSERT, UPDATE, DELETE, SELECT, FETCH, entonces los sectores estarán contiguos o muy cerca unos de otros, porque todos ocurren dentro de la misma Base de Datos. Pero si un usuario está haciendo un SORT esos sectores estarán muy alejados de la Base de Datos y ese constante ir y venir del cabezal hará que tanto las operaciones en la Base de Datos como el SORT sean mucho más lentos de lo que deberían. Si has leído algo sobre el diseño de Sistemas Operativos recordarás que usan semáforos: le dan unos milisegundos a un proceso para que haga lo que quiere hacer, luego otros milisegundos a un segundo proceso, luego otros milisegundos a un tercer proceso, y así sucesivamente hasta regresar al primer proceso. Para los usuarios esto es transparente, creen que cada uno de sus procesos se está ejecutando simultáneamente con los demás procesos pero eso no es así (bueno, salvo que la computadora tenga varios procesadores, claro). De todas maneras, sea la computadora multi-procesador o no, el cabezal del disco duro tendrá un constante ir y venir entre los sectores usados en el SORT y los sectores usados para las otras operaciones. Eso es lento y siempre será lento, podrá aumentarse la velocidad con discos duros más veloces, pero siempre será lento.

Si están en un disco no magnético (por ejemplo, un disco SSD), entonces no hay un cabezal que se mueve, en realidad nada se mueve, pero los discos tienen una vida útil limitada que aunque va aumentando porque la tecnología mejora, siempre tiene un límite. Entonces, si además de realizar las operaciones normales (INSERT, UPDATE, DELETE, SELECT, FETCH) también le pedimos que use a ese mismo disco SSD para los SORT, los backups y los restores, la vida útil de nuestro disco SSD será mucho más corta de lo que debería ser.

Por lo tanto la conclusión es muy sencilla: la Base de Datos debe encontrarse en un disco y los archivos temporales en un disco distinto.

Ese disco debe ser físicamente distinto, no sirve que esté particionado. Si está particionado se trata del mismo disco aunque para el Sistema Operativo sean dos discos diferentes, la realidad es que sigue siendo un mismo disco físico, y eso es justamente lo que no queremos.

Artículos relacionados:

Entendiendo el contenido de un PLAN

Usando un disco RAM para aumentar la velocidad

El índice del blog Firebird21

El foro del blog Firebird21

 

Bases de datos shareware (2)

Deja un comentario

En este artículo ya habíamos visto las ventajas de tener una Base de Datos shareware, las dos formas usuales de hacerla, y los trucos que los usuarios tramposos podrían intentar:

https://firebird21.wordpress.com/2014/01/23/bases-de-datos-shareware/

Ahora explicaremos mejor el funcionamiento de esas dos formas.

Protección por fecha

Se le permite al usuario usar la aplicación hasta que llegue una cierta fecha, después ya no podrá usarla. Por ejemplo si instaló la aplicación el 24 de enero de 2014 podrá usarla hasta el 24 de febrero de 2014. Si quiere usarla después, entonces tendrá que pagar.

Aquí lo que debemos impedir es que si le cambia la fecha a la computadora la aplicación siga funcionando. Por ejemplo, el día 25 de febrero el usuario no puede usar la aplicación, le cambia la fecha a su computadora y le coloca 1 de febrero de 2014. A pesar de haber cambiado la fecha no debería poder usar la aplicación. Debemos detectar ese cambio y actuar en consecuencia.

¿Cómo protegemos por fecha?

Guardamos en una tabla de nuestra Base de Datos o en un archivo externo a ella, tres valores: la fecha inicial, la fecha final, y la fecha última.

La fecha inicial es el primer día que puede usar la aplicación. Por ejemplo el 24 de enero de 2014

La fecha final es el último día que puede usar la aplicación. Por ejemplo el 24 de febrero de 2014

La fecha última, cuando se instala la aplicación es igual a la fecha inicial. Después, cada vez que se ejecuta la aplicación se verifica si la fecha del Servidor es igual o posterior a la fecha última. Si es así, se actualiza la fecha última.

Entonces, si el 25 de febrero el usuario ejecuta la aplicación el valor de fecha última será 25 de febrero. Si le cambia la fecha a su computadora y le pone 1 de febrero, fecha última seguirá siendo 25 de febrero, porque el valor de fecha última jamás puede retroceder. El nuevo valor de fecha última solamente puede ser igual o posterior al valor anterior de fecha última.

En nuestra rutina de validación verificamos:

  1. Que la fecha de la computadora sea mayor o igual que fecha inicial y que también sea menor o igual a fecha final
  2. Que la fecha última sea mayor o igual que fecha inicial y que también sea menor o igual a fecha final

Podemos mejorar el algoritmo si en vez de guardar solamente la fecha guardamos la fecha y la hora. Inclusive lo mejoraríamos aún más si nos aseguramos que cada vez que se ejecuta la aplicación el tiempo aumente por lo menos en 5 minutos.

Primera ejecución del sistema: 24 de enero de 2014, 16:12

Segunda ejecución del sistema, como mínimo debería ser el 24 de enero de 2014 a las 16:17, ó sea 5 minutos después que la ejecución anterior. Fíjate que no importa cuando el usuario realmente ejecutó la aplicación, lo que nos aseguramos es que siempre haya un incremento de por lo menos 5 minutos. Si la segunda ejecución fue el 24 de enero a las 16:50, en fecha última tendremos guardado 24 de enero y 16:50, pero si la segunda ejecución fue el 24 de enero a las 16:13 en fecha última tendremos guardado 24 de enero y 16:17 porque siempre incrementamos como mínimo 5 minutos.

Por supuesto que no es obligatorio sumarle 5 minutos, podrías sumarle 10 minutos, 30 minutos, 60 minutos, los que te parezcan. La idea es que siempre que se ejecuta la aplicación la fecha y hora se incrementen, que jamás puedan mantenerse igual o retroceder.

De esta manera, tarde o temprano, haga el usuario lo que haga, se sobrepasará la fecha última y la aplicación dejará de funcionar.

Protección por cantidad de ejecuciones

Esto es mucho más fácil de programar que la protección por fechas. Simplemente guardamos en una tabla de nuestra Base de Datos o en un archivo externo la cantidad de veces que el usuario ejecutó nuestra aplicación. Cada vez que la ejecuta incrementamos esa cantidad en 1.

Cuando instala la aplicación, el contador es 0. La primera vez que la ejecuta, el contador es 1. La segunda vez el contador es 2. Y así sucesivamente. Cuando se llegue a la cantidad predeterminada (por ejemplo: 25), la aplicación dejará de funcionar.

Usando ambas protecciones

Para que nuestra aplicación esté más protegida lo mejor es protegerla con ambos métodos: fecha y cantidad.

Siguiendo con nuestro ejemplo, la aplicación dejará de funcionar el 25 de febrero de 2014 ó cuando haya sido ejecutada 25 veces, lo que ocurra primero.

Encriptando los valores

Evidentemente ninguna protección será efectiva si el usuario puede ver y cambiar las fechas o las cantidades de ejecución. Esos valores deben encontrarse encriptados (es decir, ilegibles para quienes no conozcan la clave) y cuanto más ocultos, mejor.

Un lugar donde tradicionalmente se guardan esos valores es en el Registro del Windows. Muy pocos usuarios conocen el Registro del Windows, menos aún han entrado a curiosearlo y muchos menos aún se atreven a cambiar algo por su propia cuenta.

Otro lugar es en la propia Base de Datos. Si tienes una tabla de un solo registro donde guardas la configuración o algo similar entonces puedes aprovechar y agregarle una columna a esa tabla. En esa nueva columna guardas (convenientemente encriptadas, por supuesto) la fecha inicial, la fecha final, la fecha última y la cantidad de ejecuciones.

Recuperando los valores

Así como has guardado las fechas y la cantidad de ejecuciones encriptadas, debes poder desencriptarlas para realizar las verificaciones y determinar si la aplicación puede seguir usándose o no.

Esto puedes realizarlo en dos lugares:

  1. En tu aplicación. Es decir en el programa que escribiste con Visual FoxPro, Visual Basic, C, C++, Delphi, Java, etc.
  2. En un trigger de tu Base de Datos. El usuario debe tener solamente la versión compilada de ese trigger, no debe tener el código fuente o de nada te servirán las protecciones.

Lo ideal y lo correcto por lo tanto es que verifiques que tu aplicación puede ejecutarse, en ambos lugares: en tu aplicación y en un trigger. De esa manera aunque el usuario llegara a descubrir y evitar la protección que se encuentra en un lugar aún le faltaría descubrir y evitar la protección que se encuentra en el otro. Y si debe trabajar más para conseguirlo es más probable que desista de su intención. Y entonces la protección habrá cumplido su misión.

En el siguiente artículo ya veremos como implementar lo expuesto hasta acá.

Artículos relacionados:

Bases de datos shareware

El índice del blog Firebird21

Conociendo la aplicación que insertó filas a una tabla

2 comentarios

Cuando una Base de Datos puede ser accedida desde varias aplicaciones es muy importante saber cual aplicación insertó las filas que tiene cada tabla.

¿Por qué?

Porque solamente la aplicación que insertó la fila debería tener el derecho de modificar o de borrar esa fila. Si otra aplicación pudiera hacerlo, eso solamente acarreará problemas. Imagínate que la aplicación de VENTAS registró una venta y cuando se la quiere consultar no se la encuentra por ningún lado porque CONTABILIDAD borró esa venta. Eso es inadmisible.

¿Qué necesitaremos?

  1. Una tabla APLICACIONES, para guardar los nombres de las aplicaciones que pueden usarse
  2. Una tabla GTT, para guardar los datos de la conexión actual, incluyendo el Identificador de la aplicación usada para el acceso
  3. Un trigger de Base de Datos que le inserte una fila a la tabla GTT
  4. Desde nuestra aplicación actualizar la tabla GTT para que tenga el Identificador de aplicación correcto
  5. Agregarle una columna a todas las tablas que pueden usarse por más de una aplicación
  6. Dos excepciones, para mostrar los mensajes de error
  7. Agregarle un trigger a cada tabla que puede usarse por más de una aplicación, para decidir si la fila puede ser modificada o eliminada

Tabla APLICACIONES

APLICACIÓN1

Captura 1. Si haces clic en la imagen la verás más grande

CREATE TABLE APLICACIONES (
   APL_IDENTI D_IDENTIFICADOR NOT NULL,
   APL_NOMBRE D_NOMBRE40);

   ALTER TABLE APLICACIONES ADD CONSTRAINT PK_APLICACIONES PRIMARY KEY (APL_IDENTI);

   ALTER TABLE APLICACIONES ADD CONSTRAINT UQ_APLICACIONES UNIQUE (APL_NOMBRE);

SET TERM ^ ;

CREATE TRIGGER BI_APLICACIONES_APL_IDENTI FOR APLICACIONES
   ACTIVE BEFORE INSERT
   POSITION 0
AS
BEGIN
   IF (NEW.APL_IDENTI IS NULL OR NEW.APL_IDENTI = 0) THEN
      NEW.APL_IDENTI = GEN_ID(APLICACIONES_APL_IDENTI_GEN, 1);
END^

SET TERM ; ^

El contenido de esta tabla podría ser algo así:

APLICACIÓN2

Captura 2. Si haces clic en la imagen la verás más grande

Tabla GTT: CONEXION_ACTUAL

En una tabla GTT guardamos los datos que necesitamos conocer de la conexión que actualmente está usando el usuario.

APLICACIÓN5

Captura 3. Si haces clic en la imagen la verás más grande

Trigger de Base de Datos para insertarle una fila a la tabla GTT

CREATE TRIGGER NEW_DBTRIGGER_C
   ACTIVE ON CONNECT
      POSITION 0
AS
BEGIN

   INSERT INTO
      CONEXION_ACTUAL
      (CON_IDENTI, CON_USUARI, CON_TIMEST)
   VALUES
      (CURRENT_CONNECTION, CURRENT_USER, CURRENT_TIMESTAMP) ;

END;

El valor de la columna faltante (CON_APLICA) debería ser puesto por la aplicación correspondiente.

Contenido de la tabla CONEXION_ACTUAL

APLICACIÓN6Captura 4. Si haces clic en la imagen la verás más grande

Ejemplo:

A la tabla CLIENTES pueden insertarle filas las aplicaciones de Contabilidad, Facturación, y Ventas. Si la fila fue insertada por Contabilidad entonces Facturación y Ventas no deberían tener el derecho de modificar esa fila ni de borrarla. De la misma manera, si la fila fue insertada por Facturación o por Ventas las otras aplicaciones no deberían poder cambiarla.

Cualquier aplicación puede consultar una fila, pero solamente la aplicación que la insertó puede modificarla o borrarla.

APLICACIÓN3

Captura 5. Si haces clic en la imagen la verás más grande

Y para ver los nombres de las aplicaciones que insertaron las filas podríamos escribir algo como:

SELECT
   C.CLI_IDENTI,
   C.CLI_NOMBRE,
   C.CLI_IDEAPL,
   A.APL_NOMBRE AS CLI_NOMAPL
FROM
   CLIENTES C
JOIN
   APLICACIONES A
      ON C.CLI_IDEAPL = A.APL_IDENTI

que nos dará como resultado algo similar a:

APLICACIÓN4

Captura 6. Si haces clic en la imagen la verás más grande

Aquí como puedes ver las filas de MARCELA, DIANA y MIRTA fueron insertadas por CONTABILIDAD, en cambio la fila de SILVIA fue insertada por FACTURACIÓN. Eso implica que si debemos modificar o borrar las filas de MARCELA, DIANA, o MIRTA deberemos hacerlo desde la CONTABILIDAD y si queremos modificar o borrar la fila de SILVIA deberemos hacerlo desde FACTURACIÓN.

Esto nos asegura que nunca una aplicación modifique o borre las filas que no le corresponden.

Las excepciones para mostrar los mensajes de error

CREATE EXCEPTION E_UPDATE_NO_ADMITIDO 'No puedes modificar el contenido de esta fila';

CREATE EXCEPTION E_DELETE_NO_ADMITIDO 'No tienes permiso para borrar filas de esta tabla';

El trigger para modificar o borrar filas de la tabla CLIENTES

CREATE TRIGGER BUD_CLIENTES1 FOR CLIENTES
   ACTIVE BEFORE UPDATE OR DELETE
      POSITION 0
AS
   DECLARE VARIABLE lnAplicacion SMALLINT;
BEGIN

   lnAplicacion = (SELECT CON_APLICA FROM CONEXION_ACTUAL);

   IF (UPDATING AND NEW.CLI_IDEAPL <> lnAplicacion) THEN
      EXCEPTION E_UPDATE_NO_ADMITIDO;

   IF (DELETING AND OLD.CLI_IDEAPL <> lnAplicacion) THEN
      EXCEPTION E_DELETE_NO_ADMITIDO;

END;

Terminando:

Y listo, eso es todo, ahora solamente la aplicación que insertó una fila podrá modificar o borrar esa fila. Los intentos realizados por las demás aplicaciones serán  rechazados, como tiene que ser.

Conclusión:

Siempre es muy importante delimitar exactamente que puede hacer cada aplicación que se conecta a nuestra Base de Datos, no podemos permitir que una aplicación modifique o borre filas que fueron insertadas por otra aplicación porque eso solamente nos traerá problemas y ningún beneficio.

Artículos relacionados:

Los triggers de la Base de Datos

El índice del blog Firebird21

La problemática de la modificación de datos y del borrado de filas

2 comentarios

Los usuarios siempre quieren tener la posibilidad de modificar los datos que ya se guardaron y de borrar las filas de una tabla si por algún motivo los datos o las filas guardados ya no sirven pero nosotros como profesionales de la Informática ¿debemos otorgarles alegremente esa posibilidad?

Hacerlo así es muy riesgoso en cuanto a la seguridad y la confiabilidad de nuestra Base de Datos, veamos algunos ejemplos:

  • Un cajero registra una venta de 6 productos, totalizando la venta 1.200 dólares. O sea que en su caja ingresaron 1.200 dólares por esa venta. Luego modifica la cantidad vendida a 3 productos y por lo tanto el total ahora registrado es de 600 dólares. Y los restantes 600 dólares se van a su bolsillo.
  • Un alumno se aplazó en Matemática pero como es amigo de la secretaria que registra las calificaciones en la computadora le pide que cambie su calificación en esa materia. Y ahora ya está aprobado.
  • Un moroso consuetudinario no puede hacer compras a crédito porque donde va a pedir un crédito le dicen que no se lo pueden otorgar porque está registrado como moroso en la Base de Datos a la cual acceden todos los comerciantes para saber la situación crediticia de los potenciales clientes. Entonces le paga a un operador de esa Base de Datos para que borre su nombre y sus antecedentes de ella. Y listo, ahora ya tiene crédito libre.
  • El empleado que carga los datos de los sueldos a pagar se auto-asigna un aumento de 200 dólares. Como la empresa tiene cientos de empleados nadie se molesta en controlar uno por uno los sueldos para verificar que sean los correctos. Después de haberse impreso la planilla de pagos de sueldos vuelve a disminuir su sueldo en esos 200 dólares. Así que su “aumento de sueldo” solamente estará registrado un corto tiempo, quizás una hora, durante cada mes. El resto del tiempo cualquier consulta a esa tabla mostrará su sueldo correcto.

Estos son solamente algunos ejemplos, hay miles más de “transfugueadas” que pueden hacer “los muchachos” si tienen abierta la posibilidad de hacerlas.

Pero tampoco podemos cerrar totalmente la posibilidad de modificar datos o de borrar filas, a veces los usuarios tienen una necesidad legítima de hacer esas operaciones entonces ¿cuál es la solución?

  • No cualquiera puede hacer esas operaciones, se necesita de un permiso especial para ello, solamente algunos usuarios deben estar autorizados. Los usuarios normales solamente tienen el privilegio de INSERT en las filas, pero no tienen el privilegio de UPDATE ni el privilegio de DELETE.
  • Cada modificación de datos o borrado de filas debe ser registrado en una tabla aparte, no en la tabla original sino en otra tabla. En esta otra tabla se guardarán, entre otros: el nombre del usuario que modificó o borró, el IP de la computadora que usó, la fecha y la hora en que ocurrió
  • En el caso de modificación, cuales eran los datos originales y cuales son ahora los nuevos datos
  • En el caso de borrado, una copia de la fila completa que borró. Alternativamente, en lugar de borrar físicamente la fila suele ser mucho mejor colocarle una “marca de borrado”. Esta es una columna que solamente indica el estado de la fila que puede ser: ACTIVO o INACTIVO. El problema con esta alternativa es que en todas las consultas que involucren a esa tabla deberemos poner en el WHERE la condición de que su estado sea ACTIVO (o INACTIVO, si lo queremos es ver a las filas “borradas”).

Conclusión:

Jamás se puede impedir que personas malintencionadas modifiquen el contenido de nuestra Base de Datos para cometer fraudes pero sí es nuestra responsabilidad dificultarles lo máximo esa posibilidad. Se nos paga (entre otras cosas) para que el contenido de la Base de Datos sea seguro y confiable, no para que cualquiera pueda meter sus pezuñas en ella y hacerle lo que se le antoje. Gente con ganas de cometer fraudes puedes encontrar en cualquier organización, por lo tanto las operaciones de UPDATE y de DELETE deben estar altamente restringidas y debe llevarse un registro minucioso de cualquiera de esas operaciones para que cuando se realice una auditoría se pueda ver claramente quien las hizo, cuando y donde.

Artículo relacionado:

El índice del blog Firebird21

Usando scripts para documentar la Base de Datos

Deja un comentario

Si hay una verdad innegable en Informática es que a la grandísima mayoría de los programadores no nos gusta documentar. Sabemos muy bien que eso es lo correcto, que debemos hacerlo … pero no lo hacemos.

Aunque no nos salvaremos de escribir algo, los scripts de Firebird nos ayudarán a escribir poco y sin embargo tener muy bien documentada a nuestra Base de Datos.

La técnica es la siguiente:

  • Cuando creamos una Base de Datos generamos su script. En él escribimos la fecha en que fue creada y algún otro comentario relevante.
  • Cada vez que modificamos los metadatos generamos un script. En él escribimos la fecha de la modificación, cual/es metadato/s cambiamos y algún otro comentario relevante

Si hacemos esto tendremos algo buenísimo: el historial completo de nuestra Base de Datos, con todos los cambios que alguna vez fueron realizados en ella y las fechas de tales cambios.

Entonces si alguien ¿nosotros mismos? por intención o por ignorancia modificó algún metadato podremos regresarlo a su estado original, rápidamente y sin esfuerzo.

¿Cómo se genera un script?

En este artículo se explica como hacerlo:

https://firebird21.wordpress.com/2013/05/22/entendiendo-a-los-scripts/

Ejemplo:

Queremos documentar mediante scripts una Base de Datos que se llama INTEGRAL.FDB entonces cuando terminamos de trabajar con ella el primer día generamos un script, le llamamos INTEGRAL001.SQL y le escribimos la fecha:

SCRIPT01

Captura 1. Si haces clic en la imagen la verás más grande

A partir de ese día cada vez que modificamos los metadatos, cuando terminamos de trabajar con ellos generamos otro script donde indicamos que fue lo que le hicimos. Este se llama INTEGRAL002.SQL:

SCRIPT02

Captura 2. Si haces clic en la imagen la verás más grande

Fíjate que no es necesario especificar cuales fueron los cambios realizados sino solamente qué se cambió. Si queremos saber cuales fueron los cambios (por ejemplo en la tabla CLIENTES) podemos buscar esa tabla en el script y allí los veremos. Desde luego que si quieres escribir cuales fueron los cambios en la cabecera del script también puedes hacerlo aunque en general no es necesario.

Conclusión:

Mantener bien documentados los cambios que le realizamos a nuestra Base de Datos es importantísimo para poder en cualquier momento saber que fue lo que hicimos (o algún otro le hizo, sin nuestra autorización) y en caso necesario retrotraerla a su estado anterior.

Es cierto, documentarla lleva un poco de tiempo y no nos gusta documentar pero los beneficios que obtendremos con esta práctica el día que ocurra algún problema serán inmensos y compensarán con creces el tiempo que empleamos en documentar la Base de Datos.

Es una buena idea que cuando instalas la Base de Datos en la computadora de tu cliente o cuando modificas esa Base de Datos especifiques cual script le corresponde. Por ejemplo: el cliente 1 tiene instalada la Base de Datos que corresponde al script 017, el cliente 2 tiene instalada la Base de Datos que corresponde al script 023, etc.

Artículos relacionados:

Entendiendo a los scripts

El índice del blog Firebird21

Older Entries