Averiguando la carpeta donde se instaló el Firebird

Deja un comentario

A veces te puede interesar saber, desde el programa que estás escribiendo en Visual FoxPro, Visual Basic, C, C++, Delphi, Java, etc., cual es la carpeta donde está instalado el Firebird.

Si conoces el password del usuario SYSDBA, puedes obtener esa información ejecutando el programa FBSVCMGR.EXE

Los pasos que debes seguir son los siguientes:

  1. En la carpeta donde se encuentra el .EXE de tu aplicación copia el archivo FBSVCMGR.EXE
  2. En la carpeta donde se encuentra el .EXE de tu aplicación copia el archivo FBCLIENT.DLL
  3. Desde tu aplicación ejecuta el comando: FBSVCMGR service_mgr USER SYSDBA PASSWORD masterkey INFO_GET_ENV > SERVIDORES.TXT
  4. Extrae del archivo SERVIDORES.TXT todas las líneas que empiezan con “Server root:”. Recuerda que en una computadora puede haber más de una instancia del Firebird instaladas

Ejemplo:

FB1

 

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

FB2

 

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

Como puedes ver en la Captura 2 el nombre de la carpeta donde está instalado el Firebird se muestra a continuación de las palabras “Server root:”

Recuerda que si hay varias instancias del Firebird instaladas entonces habrá varias líneas empezando con las palabras “Server root”.

Artículo relacionado:

El índice del blog Firebird21

Anuncios

Ejemplo Nº 052 – Comparando strings

Deja un comentario

Cuando comparamos strings el resultado puede no ser el que esperábamos si es que no lo hacemos bien.

Ejemplo:

SELECT
   1
FROM
   RDB$DATABASE
WHERE
   'A' = 'A      '

Este SELECT devolverá 1 aunque los strings son diferentes. ¿Es eso correcto o incorrecto? Pues es lo correcto según el estándar SQL el cual dice lo siguiente: “cuando se comparan strings de distinta longitud, la comparación debe ser hecha como si al string más corto se le agregaran espacios en blanco hasta la longitud del string más largo”.

¿Y si queremos que la condición no se cumpla cuándo las longitudes son diferentes?

En ese caso deberemos utilizar LIKE, como vemos a continuación:

SELECT
   1
FROM
   RDB$DATABASE
WHERE
   'A' LIKE 'A   '

Aquí el resultado de la consulta será un conjunto vacío porque la condición no se cumple.

Conclusión:

Si quieres que la comparación entre dos strings sea estricta (o sea que sean idénticos y que tengan la misma longitud) debes usar el operador LIKE, no el símbolo =

Artículo relacionado:

El índice del blog Firebird21

Obteniendo los nombres de todos los usuarios

2 comentarios

Alguna vez podrías necesitar conocer los nombres de todos los usuarios que tiene admitidos el Firebird, estos son los usuarios que pueden conectarse a cualquier Base de Datos, siempre y cuando se les otorguen los derechos correspondientes, por supuesto.

No conozco algún SELECT que nos provea esa información. Los nombres de los usuarios se encuentran en el archivo SECURITY2.FDB y el acceso a ese archivo está restringido por razones obvias. Entonces, ¿cómo hacemos para obtener los nombres de todos los usuarios?

Aquí se muestra una solución.

Si creamos un archivo batch similar al siguiente tendremos en el archivo USUARIOS.TXT los nombres de todos los usuarios de bases de datos de Firebird.

USUARIOS

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

Como puedes ver, el archivo batch se llama USUARIOS.BAT y lo que hace es ejecutar al programa GSEC pidiéndole que muestre los nombres de los usuarios (la opción -display hace eso). No cualquier usuario puede listar los nombres de los demás usuarios, solamente SYSDBA puede hacerlo. La salida se redirige a un archivo llamado USUARIOS.TXT, o sea que en lugar de mostrar los nombres de los usuarios en la pantalla guarda esos nombres en el archivo USUARIOS.TXT

¿Por qué redirigimos la salida del programa GSEC al archivo USUARIOS.TXT?

Para más tarde poder procesar el archivo USUARIOS.TXT y extraer de él los nombres de los usuarios, pues eso es lo que estamos intentando conseguir. Queremos tener los nombres de los usuarios para mostrarlos en un ComboBox o en un Grid, etc.

El siguiente código en Visual FoxPro nos muestra como podemos obtener los nombres de todos los usuarios:

Local lcComando, llComandoOK, loShell, lnRetorno, lcUsuarios, lnMemoWidth, lnTotalLineas, lnI, lcLinea

   *--- Nombre del archivo donde se guardarán los nombres de los usuarios
   lcArchivo = "USUARIOS.TXT"

   *--- Contenido que tendrá el archivo batch USUARIOS.BAT
   lcComando = ["C:\ARCHIVOS DE PROGRAMA\FIREBIRD\FIREBIRD_2_5\BIN\GSEC" -user SYSDBA -password masterkey -display > ] + lcArchivo

   *--- Se crea el archivo batch USUARIOS.BAT
   =StrToFile(lcComando, "USUARIOS.BAT")

   *--- Se supone que el archivo batch se ejecutará exitosamente
   llComandoOK = .T.

   *--- Se crea un objeto shell para ejecutar el archivo batch
   loShell = CreateObject("WScript.Shell")

   *--- Se intenta ejecutar el archivo batch, la bandera llComandoOK nos dirá si se ejecutó exitosamente o no
   TRY
      lnRetorno = loShell.Run("USUARIOS.BAT", 0, .T.)
   CATCH
      llComandoOK = .F.
   ENDTRY

   if llComandoOK     && Si la ejecución del archivo batch tuvo éxito
      *--- En la variable lcUsuarios se guarda el contenido del archivo que tiene los nombres de los usuarios
      lcUsuarios = FileToStr(lcArchivo)
      *--- Se obtiene la cantidad de caracteres que se usan en los campos memo
      lnMemoWidth = Set("MEMOWIDTH")
      *--- Se cambia la cantidad de caracteres a 96
      SET MEMOWIDTH TO 96
      *--- Se obtiene la cantidad de líneas que tiene el archivo donde están los nombres de los usuarios
      lnTotalLineas = MemLines(lcUsuarios)
      *--- Se guarda en la variable lcLinea el nombre de cada usuario
      For lnI = 3 to lnTotalLineas
         lcLinea = AllTrim(Left(MLine(lcUsuarios, lnI), 28))
         if !Empty(lcLinea)
            =MessageBox(lcLinea)     && Se muestra en la pantalla el nombre del usuario
         endif
      EndFor
      *--- Se pone la cantidad de caracteres original en los campos memo
      SET MEMOWIDTH to lnMemoWidth
   else     && Si ocurrió algún problema al ejecutar el archivo batch
      =MessageBox("No pude obtener los nombres de los usuarios")
   endif

   *--- Se borra el archivo USUARIOS.BAT porque ya no es necesario
   DELETE FILE USUARIOS.BAT

   *--- Se libera el objeto loShell

   loShell = NULL

   Release loShell

Return
*
*

Dentro del código fuente hay muchos comentarios, los cuales te ayudarán a entender que es lo que hace. Si tienes bastante experiencia con Visual FoxPro te resultará muy fácil entenderlo, aún sin los comentarios.

Conclusión:

Aunque no existe (que yo sepa, claro) un SELECT que nos devuelva los nombres de los usuarios escribir un programita que nos de esa información es muy fácil como se puede ver en este artículo.

Artículos relacionados:

Agregando, modificando y borrando usuarios

El índice del blog Firebird21

Usando UNION para reemplazar condiciones complejas

Deja un comentario

En ocasiones tenemos que escribir un SELECT que tiene una cláusula WHERE muy compleja, está llena de condiciones, de AND, de OR, y entender lo que hace nos resulta bastante complicado. Una forma de facilitar la lectura es usando la cláusula UNION.

Usando UNION es similar a usar OR pero:

  1. Se escribe más al usar UNION que al usar OR
  2. Se entiende mejor al usar UNION que al usar OR cuando las condiciones son complejas

Ejemplo:

Tenemos una tabla llamada CLIENTES que tiene estas filas:

UNION1

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

Y queremos una consulta que nos muestre los clientes cuyos nombres empiecen con la letra “M” o con la letra “S”. Podríamos escribir una consulta como esta:

SELECT
   CLI_NOMBRE
FROM
   CLIENTES
WHERE
   CLI_NOMBRE STARTING WITH 'M' OR
   CLI_NOMBRE STARTING WITH 'S'

Y está muy bien, como la consulta es simple esa es la solución adecuada. Pero si queremos podríamos obtener el mismo resultado usando la cláusula UNION.

SELECT
   CLI_NOMBRE
FROM
   CLIENTES
WHERE
   CLI_NOMBRE STARTING WITH 'M'

UNION

SELECT
   CLI_NOMBRE
FROM
   CLIENTES
WHERE
   CLI_NOMBRE STARTING WITH 'S'

Entonces, la primera forma es la adecuada cuando las condiciones son simples. Usamos OR y asunto solucionado. Pero cuando las condiciones son complicadas es preferible usar UNION porque nos facilitará la lectura y nos resultará más fácil comprender que hace nuestro SELECT.

Conclusión:

Se puede usar la cláusula UNION para reemplazar al operador condicional OR pero solamente se justifica usar UNION cuando las condiciones son complicadas de entender, ya que al usar UNION es fácil entender lo que está ocurriendo.

Podemos pensar en UNION como en una suma. Nos devuelve el resultado de la primera consulta MÁS el resultado de la segunda consulta.

En nuestro ejemplo, los nombres de los clientes que empiezan con “M” más los nombres de los clientes que empiezan con “S”.

Artículos relacionados:

Entendiendo a las UNION

El índice del blog Firebird21

Usando FBClone para copiar datos

6 comentarios

Hay un programa llamado FBClone que sirve para copiar el contenido de las tablas de dos bases de datos que tengan la misma estructura.

La Base de Datos destino no debe estar abierta.

Puedes descargar a FBClone desde aquí:

https://code.google.com/p/fbclone/downloads/list

En el archivo .ZIP está incluido el código fuente del programa, por si te interesa mirarlo.

FBClone no necesita ser instalado, lo copias en cualquier carpeta y lo ejecutas desde allí, pero para ejecutarlo debes abrir una ventana “Símbolo del sistema”

FBCLONE1

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

Las opciones que empiezan con -s (source) se refieren a la Base de Datos origen o sea la que enviará las filas. Las opciones que empiezan con -t (target) se refieren a la Base de Datos destino o sea la que recibirá las filas.

La Base de Datos destino no necesita estar en la misma computadora que la Base de Datos origen, pueden estar en computadoras distintas.

FBCLONE2

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

Conclusión:

Usar FBClone para realizar backups tiene las ventajas de que no debemos hacer un ciclo backup/restore y que podemos fácilmente copiar de una versión del Firebird a otra.

Pero no te olvides que las estructuras de las tablas de ambas bases de datos deben ser iguales. Y que nadie debe estar conectado a la Base de Datos destino.

Artículos relacionados:

Backup y Restore a una versión más nueva del Firebird

Los métodos para hacer Backup

El índice del blog Firebird21

Usando IDENTIFICADORES y CÓDIGOS en nuestras tablas

Deja un comentario

Aunque un Identificador es distinto que un Código mucha gente los confunde, inclusive aún teniendo muchos años de experiencia informática siguen tratando a los Códigos como si fueran Identificadores y eso es incorrecto porque deberían usarse para tareas distintas.

Un Identificador como su nombre lo indica sirve para identificar a una fila, de tal forma que no exista confusión posible con alguna otra fila de la misma tabla. En general lo aconsejable es que sea numérico y autoincremental (1, 2, 3, 4, 5, 6, etc.)

Un Código también sirve para identificar a una fila, de tal forma que no exista confusión posible con alguna otra fila de la misma tabla. Puede ser numérico o alfanumérico (AB123, MMK01, SVB68, 575701238, etc.)

Como ves, ambos sirven para identificar a una fila de forma unívoca, o sea que no pueda confundirse con otra fila.

¿Cuál es la diferencia entre un Identificador y un Código?

Que el Identificador se usa de forma interna en la Base de Datos, para identificar unívocamente a cada fila de una tabla y para relacionar a dos (o más) tablas entre sí. Como son de uso interno los usuarios ni siquiera necesitan saber de que existen. Jamás deberías cambiar el valor de un Identificador, por ningún motivo.

El Código, en cambio, no debería usarse para relacionar a dos (o más) tablas entre sí, esa es la tarea de los Identificadores, no es la tarea de los Códigos. Esto implica que un Código:

a) Solamente existe en una tabla

b) Puede ser cambiado, no hay problema si cambia su valor (desde luego que si debe ser único no podrá estar repetido, pero esa es la única restricción)

En las pantallas y en los informes los usuarios no necesitan ver a los identificadores, recuerda que son para uso interno dentro de la Base de Datos. Los códigos sí pueden verlos, justamente para eso sirven, para ser visualizados por los usuarios.

IDENTI1

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

En la Captura 1 vemos las primeras columnas de una tabla llamada PRODUCTOS. En ella tenemos un Identificador llamado PRD_IDENTI y dos Códigos llamados PRD_CODIGO y PRD_CODBAR respectivamente. Este último significa “código de barras”.

También tenemos una tabla llamada MOVIMDET (detalles de los movimientos de los productos) cuyas primeras columnas son las siguientes:

IDENTI2

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

Para relacionar a ambas tablas se usa la columna MOV_IDEPRD (Identificador del producto), no se usa ni el Código del producto ni el Código de barras del producto, lo que se usa es su Identificador.

Si al consultar la tabla MOVIMDET queremos ver el Código o el Código de barras del producto, pues es muy fácil:

SELECT
   P.PRD_CODIGO,
   P.PRD_CODBAR,
   P.PRD_NOMBRE,
   D.MOV_CANTID,
   D.MOV_PRECIO,
   D.MOV_CANTID * D.MOV_PRECIO AS TOTAL
FROM
   MOVIMDET D
JOIN
   PRODUCTOS P
      ON D.MOV_CODSUC = P.PRD_CODSUC AND
         D.MOV_IDEPRD = P.PRD_IDENTI

Y listo, eso es todo, al relacionar a ambas tablas con un JOIN todas las columnas de la tabla PRODUCTOS están disponibles para ser mostradas o utilizadas en el SELECT.

Conclusión:

Aunque puedes usar a un Código como si fuera un Identificador eso no es lo correcto, los identificadores son para uso interno, los códigos son para uso externo. Los usuarios solamente necesitan ver a los códigos, ellos ni siquiera necesitan saber que existen los identificadores. El valor de un Código debería existir en solamente una tabla, en cambio el valor de un Identificador existirá en todas las tablas relacionadas. Jamás y por ningún motivo deberías cambiar el valor de un Identificador, en cambio puedes cambiar sin problemas el valor de un Código, todas las veces que quieras. En las pantallas y en los informes a los usuarios se les pueden mostrar los Códigos, pues para eso sirven, para ser vistos por los usuarios.

Como los identificadores son para uso interno no hay problema si tienen valores salteados (1, 2, 8, 24, 25, 39, etc.). Esto está muy bien, si cumplen con su misión de identificar a cada fila de la tabla de forma unívoca entonces no importa que falten algunos valores.

Como los códigos son para uso externo entonces quizás los usuarios prefieran verlos en secuencia correlativa (1, 2, 3, 4, 5, 6, 7, 8, etc.). A la Base de Datos no le afecta que estén en secuencia o que falten algunos números, porque dentro de la Base de Datos no se los utiliza, entonces podrías cambiar los códigos para que siempre se muestren en secuencia y jamás haya números faltantes. Pero cuidado con esto, a la Base de Datos no le importará que cambies o no cambies los valores de los códigos, porque nunca los usa. Pero a los usuarios sí que puede importarles porque si un Producto ayer tenía el código 123 y hoy ese mismo producto tiene el código 87, podrías complicarles la vida. Por lo tanto, el hecho de que se pueda cambiar los códigos para que siempre estén en secuencia no implica que se deba hacer eso.

En una Base de Datos bien diseñada jamás hay motivo para cambiar el valor de un Identificador. Aunque sí puede haber motivos para cambiar el valor de un Código (normalmente no debería cambiarse, pero si se cambia no le afecta a la Base de Datos, solamente le afecta a los usuarios).

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Eliminando códigos de control en las cadenas alfanuméricas

4 comentarios

Como seguramente sabes, todos los caracteres que usas para escribir textos con la computadora tienen un código ASCII. Así por ejemplo el código ASCII de la letra A mayúscula es 65, el código ASCII del dígito 0 es 48, etc.

Los códigos ASCII cuyos valores van desde al 0 al 31 en su mayoría no son imprimibles y se llaman “códigos de control”.

Si una columna CHAR o VARCHAR tiene códigos de control entonces el resultado que obtendrás al ejecutar un SELECT o al utilizar funciones alfanuméricas tales como LEFT(), TRIM(), etc. podría no ser el esperado.

Entenderemos mejor el problema con el siguiente ejemplo.

Tenemos una tabla llamada PRODUCTOS la cual tiene las siguientes filas:

ASCII1

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

Ahora, reemplazamos todos los espacios en blanco por el código de control 0 (cero):

UPDATE
   PRODUCTOS
SET
   PRD_NOMBRE = REPLACE(PRD_NOMBRE, ' ', ASCII_CHAR(0))

Volvemos a consultar el contenido de la tabla PRODUCTOS y ahora esto es lo que obtenemos:

ASCII2

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

¿Qué pasó aquí? ¡¡¡Desaparecieron todos los caracteres que se encontraban después del primer espacio en blanco!!!

Pues no, no te asustes, no han desaparecido sino que no son visibles. Cuando el Firebird encuentra un caracter cuyo código ASCII es cero ya no muestra los siguientes caracteres, llega solamente hasta el que tiene código ASCII cero.

Entonces, si ahora actualizamos nuestra tabla PRODUCTOS de forma inversa (o sea, reemplazando los códigos ASCII cero con espacios en blanco):

UPDATE
   PRODUCTOS
SET
   PRD_NOMBRE = REPLACE(PRD_NOMBRE, ASCII_CHAR(0), ' ')

esto será lo que obtendremos:

ASCII1

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

¡¡¡Voilá!!! ¡¡¡Reaparecieron todos los caracteres faltantes!!!

Conclusión:

Si al consultar el contenido de una columna alfanumérica notas que faltan caracteres o que el comportamiento de las funciones alfanuméricas LEFT(), RIGHT(), TRIM(), etc., es extraño entonces es posible que la causa sea que hay caracteres de control en esa columna. Puedes utilizar la función REPLACE() para reemplazar a esos caracteres de control por otros caracteres, típicamente por espacios en blanco, como has visto en los ejemplos anteriores y de esa manera solucionarás el problema.

Artículo relacionado:

El índice del blog Firebird21

Older Entries Newer Entries