SQL error code = -104: Unexpected end of command

1 comentario

El mensaje de error “Unexpected end of command” significa que el comando terminó imprevistamente, antes de lo esperado. O sea que no debería haber terminado, pero terminó.

Ejemplo 1

SELECT
   *
FROM

En el Ejemplo 1 faltó especificar el nombre de la tabla. El Firebird no es adivino y no puede saber cual tabla querías usar.

Ejemplo 2

SELECT
   *
FROM
   PRODUCTOS
WHERE

En el Ejemplo 2 no se especificó la condición (la cual tendría que haberse escrito después de la cláusula WHERE). El Firebird no puede saber cual condición querías escribir.

Ejemplo 3

SELECT
   *
FROM
   PRODUCTOS
WHERE
   PRD_NOMBRE LIKE 'CO

En el Ejemplo 3 faltó escribir un apóstrofo. Se escribió uno después del LIKE, falta el otro.

Ejemplo 4

INSERT INTO PRODUCTOS

En el Ejemplo 4 faltó indicar las columnas de la tabla de PRODUCTOS y los valores que se guardarán en esas columnas.

Conclusión:

Como puedes ver, en todos los casos faltó escribir algo. Si te encuentras con este error, revisa detenidamente el comando que escribiste porque algo le está faltando para estar completo.

Artículo relacionado:

El índice del blog Firebird21

Curso: Introduction to Databases

Deja un comentario

La Universidad de Stanford dictará un curso gratuito (en Inglés) sobre Introducción a las bases de datos, empezará este Martes 7 de enero y aún tienes tiempo para inscribirte si estás interesado.

Introduction to Databases

Artículo relacionado:

El índice del blog Firebird21

 

Eligiendo entre LIKE y CONTAINING en los SELECT

5 comentarios

Cuando en una consulta la condición de búsqueda es alfanumérica podemos usar (entre otras posibilidades)  a LIKE y a CONTAINING.

¿Cuál es preferible?

LIKE distingue entre mayúsculas y minúsculas, en cambio CONTAINING no las distingue.

Ejemplo:

Tenemos una tabla llamada BANCOS con estas filas:

LIKE1

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

SELECT
   *
FROM
   BANCOS
WHERE
   BAN_CODSUC >= 0 AND
   BAN_NOMBRE LIKE '%BAN%'

LIKE2

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

En la Captura 2 podemos ver cuales son las filas que obtuvimos al usar LIKE.

SELECT
   *
FROM
   BANCOS
WHERE
   BAN_CODSUC >= 0 AND
   BAN_NOMBRE CONTAINING 'BAN'

LIKE3

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

Y en la Captura 3 las filas que obtenemos al usar CONTAINING.

Como puedes ver, con CONTAINING obtuvimos más filas porque nos muestra las que están en mayúsculas y también las que están en minúsculas. Por eso en general, cuando los nombres no están estandarizados es preferible usar CONTAINING.

Esto sucede a menudo cuando son varias las personas encargadas de registrar los datos en una tabla. Algunos escriben todo en mayúsculas y algunos mezclan mayúsculas con minúsculas. Entonces, para asegurarnos que encontremos todos los datos buscados, sea que los hayan escrito en mayúsculas o en minúsculas debemos usar CONTAINING.

Artículo relacionado:

El índice del blog Firebird21

PHP: guardando un archivo en un campo BLOB

1 comentario

Si estás programando con PHP y usando una Base de Datos de Firebird puedes encontrarte con la necesidad de guardar un archivo en un campo BLOB, aquí está una forma de hacerlo, colaboración de Jaume.

$f = realpath("factura.pdf");

$stream = fopen($f, "r");

$dpdf = stream_get_contents($stream);

fclose($stream);

$sql = "UPDATE OR INSERT INTO MiTabla (MiColumna1, MiColumna2) VALUES (MiValor1, :foo)";

try {
   $queri = $co->prepare($sql);
   $queri->bindParam(':foo', $dpdf);
   $queri->execute();
   $queri = NULL;
}
catch (PDOException $e) {
   $ok    = false;
   $queri = NULL;
   $inf   = $e->getMessage();
}

Artículo relacionado:

El índice del blog Firebird21

Manteniendo la Base de Datos en buen estado

2 comentarios

Las bases de datos de Firebird es difícil que se corrompan, pero no imposible. Después de todo se trata de archivos de computadora y no existe una fórmula mágica que las salve de la corrupción.

La corrupción puede deberse a:

  • Problemas de hardware
  • Problemas de software
  • Problemas de mantenimiento

Problemas de hardware

  1. Apagado anormal. Es muy raro pero puede ocurrir, sobre todo si FORCED WRITES está en OFF. En Windows siempre debería estar en ON porque el Windows puede tardar mucho tiempo en guardar físicamente en el disco lo que se le pidió que guarde físicamente en el disco. Ese “mucho tiempo” puede ser minutos, horas, e incluso días.
  2. Disco duro levemente dañado. Ocurre cuando solamente algunos clusters se dañan y tuviste la mala suerte de que tu Base de Datos esté usando algunos de esos clusters. El sistema operativo los marca como dañados y no lee el contenido. Esto provoca que algunas partes de la Base de Datos no puedan ser leídas. Por ejemplo, se pueden leer algunas filas de una tabla, pero no todas las filas.
  3. Disco duro fuertemente dañado. Quizás a causa de una fuerte caída, un incendio, cosas así. En estos casos puedes utilizar un programa como R-Studio que encontrarás en: http://www.data-recovery-software.net/ o llevar el disco duro a alguna empresa que se especializa en recuperar discos duros dañados, pero el problema con esta última opción es que puede ser muy cara, nunca cobran por debajo de los 1.000 dólares por su servicio.
  4. Memoria RAM dañada. Esta es la peor de todas las posibilidades, porque es aleatoria. Un día todo puede funcionar perfecto (porque la Base de Datos no se alojó en la parte de la RAM que está dañada) y otro día tienes problemas a cada rato (porque la Base de Datos se alojó justo en la parte de la RAM que está dañada) para que al siguiente día todo parezca estar normal nuevamente. Además, cuando el problema está en el disco duro es toda una página la que se torna inaccesible pero en el caso de la RAM puede ser solamente un bit que cambió de 0 a 1 ó viceversa. Eso hace que pueda pasar muchísimo tiempo hasta que detectes que algo está mal. ¿Qué implica esto? que en general solamente descubres el problema cuando el daño ya es demasiado grande, cuando ya se volvió crítico.
  5. Insuficiente espacio en el disco duro para la Base de Datos. Esto ya es total responsabilidad del Administrador de la Base de Datos, no puede jamás permitir que tal cosa ocurra. El problema aparece cuando el Servidor quiere agregarle más páginas a la Base de Datos pero no hay suficiente espacio libre en el disco duro o en la partición. La situación más peligrosa sucede cuando la falta de espacio en el disco duro es combinada con un caché muy grande y con FORCED WRITES en OFF porque el sistema operativo trata de guardar muchos datos en el disco duro y falla porque no le alcanza el espacio libre.
  6. Insuficiente espacio en el disco duro para los archivos temporales. Nuevamente, esto es total responsabilidad del Administrador de la Base de Datos. Firebird utiliza archivos temporales para ordenar los resultados de las consultas, esos archivos temporales solamente existen mientras se está ordenando y luego desaparecen pero si el ordenamiento envuelve a millones de filas, pueden requerir de mucho espacio en el disco duro.
  7. Insuficiente espacio en el disco duro para el archivo FIREBIRD.LOG. En este archivo se guardan los mensajes relacionados con el funcionamiento de Firebird, puede tener miles y miles de filas y si la Base de Datos tiene algún problema esas filas con mensajes se multiplican.

Problemas de software

  1. Creando y borrando tablas mientras la Base de Datos está siendo usada. Esta es la forma más fácil de corromper una Base de Datos porque el Firebird puede confundirse y escribir en las páginas del sistema (usadas para crear y borrar tablas) lo que debería escribir en las páginas de datos. O viceversa.

Problemas de mantenimiento

  1. Se borró la Base de Datos. Si nadie la está usando puede ser borrada, al igual que cualquier otro archivo de la computadora. A veces ocurre lo siguiente: se hace un backup, y se borra la Base de Datos original, confiando en el backup. Pero el backup por alguna razón está corrupto y entonces no sirve y tampoco se puede usar la Base de Datos original porque ya fue borrada.

Detectando problemas

La forma más rápida de detectar problemas es revisando el archivo FIREBIRD.LOG, si allí encontramos cualquier cosa inusual (por ejemplo, errores 10054) entonces hay algo mal en la Base de Datos y debemos solucionarlo lo antes posible.

¿Qué significa esto?

Que todos los días deberíamos echarle un vistazo al archivo FIREBIRD.LOG porque cuanto más rápido detectemos los problemas menos daños causarán.

También podemos utilizar programas especializados, como el IBSurgeon FirstAid

Solucionando problemas

Si encuentras que una Base de Datos está dañada, esto es lo que debes hacer:

  1. Detener el Servidor del Firebird. Porque más accesos y operaciones en la Base de Datos dañada solamente pueden provocar más daños, nunca menos daños
  2. Hacer un backup de la Base de Datos. Haz este backup con programas como 7Zip, WinZip, WinRar, etc.
  3. Utilizar el backup para intentar la recuperación. Siempre debes mantener el archivo original a salvo, trabaja con el backup
  4. Escribe los siguientes comandos para intentar repararla. Estos son los comandos estándar que se usan para reparar bases de datos dañadas.

Para validar la Base de Datos (recuerda que debes usar el archivo de backup, no el archivo original):

gfix –v –full –user SYSDBA -password MiPassword MiBaseDatosCorrupta.FDB

Si el comando de arriba detectó algún problema entonces debemos eliminar esos problemas:

gfix –mend –user SYSDBA –password MiPassword MiBaseDatosCorrupta.FDB

Repetir los dos comandos anteriores hasta que ya no se detecten problemas. Cuando está todo ok hay que hacerle un backup, porque al hacer un backup pueden detectarse otros problemas:

gbak –b –v -ig –user SYSDBA –password MiPassword MiBaseDatosCorrupta.FDB MiBackup.FBK

Si apareció algún error entonces debemos realizar otro backup, pero sin la recolección de basura:

gbak –b –v -ig –g -user SYSDBA –password MiPassword MiBaseDatosCorrupta.FDB MiBackup.FBK

A veces hacer que la Base de Datos sea de solo lectura (o sea: read only) puede ayudar a recuperarla.

gfix –mode read_only  –user SYSDBA -password MiPassword MiBaseDatosCorrupta.FDB

Si el backup finalizó exitosamente, entonces se lo restaura desde la copia:

gbak –c –user SYSDBA –password MiPassword MiBaseDatosCorrupta.FDB MiBaseDatosRestaurada.FDB

Conclusión:

Las bases de datos de Firebird son archivos de computadora y como cualquier otro archivo pueden dañarse. Los causantes pueden ser problemas de hardware, problemas de software o un mantenimiento inadecuado. Sea cual sea la razón, si detectamos que una Base de Datos está dañada debemos intentar repararla lo antes posible porque si se la continúa usando eso solamente ocasionará más daños.

No siempre se puede reparar una Base de Datos. Por lo tanto es importantísimo que al menos una vez por día se haga un backup de la misma para que la pérdida no sea muy grande si se concluye que es imposible repararla.

Artículo relacionado:

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

¡¡¡FELIZ AÑO 2014!!!

13 comentarios

Hoy está empezando un nuevo año, deseo que todos los lectores de este blog lo pasen súper y que aprendan más sobre Firebird y que compartan sus conocimientos con los demás, no sean egoístas en este 2014.

Walter.

 

Newer Entries