Koenma's Laboratory




SQL inmerso en C/C++ (Parte V)

11 de julio de 2007

Programación con cursores

Los cursores son estructuras con las que Oracle nos permite recorrer resultados de consultas t-upla a t-upla. Un ejemplo para la creación de un cursor sobre el resultado de una consulta se realiza de la siguiente forma:
    EXEC SQL DECLARE (nombre_del_cursor) CURSOR FOR
    SELECT (atributo)
    FROM (tabla);
Para el acceso a los datos del cursor, usamos la sentencia FETCH. Una forma común de acceder a los resultados de la consulta es aprovechando la generación de un error cuando no se pueden obtener más datos del cursor:
    EXEC SQL WHENEVER NOT FOUND DO break;

      For ( ; ; ) {
      EXEC SQL FETCH dato TO <:variable_huesped>
      (... acciones ...)
      }
A la instrucción FETCH se la puede acompañar de una posición:

  • Next: siguiente elemento al actual.
  • Last: último elemento del cursor.
  • Prior: anterior elemento al actual.
  • First: primer elemento del cursor.
Un cursor no evalúa la consulta a la que se ha asociado hasta que no se ejecuta la sentencia:
    EXEC SQL OPEN (nombre_cursor);
Para finalizar los cambios realizados sobre las t-uplas asociadas a la consulta, usamos:
    EXEC SQL CLOSE (nombre_cursor);
Si a parte de consultarlas, queremos modificar las t-uplas, en la declaración debemos añadir la cláusula “FOR UPDATE (lista de columnas)”. Para el borrado de las t-uplas usando un cursor, usamos:
    EXEC SQL DELETE FROM (nombre_tabla) WHERE CURRENT OF (cursor)
Eliminaría el elemento actualmente seleccionado por el cursor indicado en la tabla dada.

SQL estático y SQL dinámico

Dentro del SQL podemos encontrar dos variantes de éste: el SQL estático y el dinámico.

El SQL estático es aquella parte del mismo que se encarga de consultar, modificar, etc,una base de datos. En esta variante se da por conocidas las instrucciones SQL completas en el momento de escribir el programa, lo cual lleva a crear una serie de pasos comunes a seguir. Simplemente, se incorpora en el archivo fuente del lenguaje principal y el precompilador maneja la conversión necesaria a las llamadas a API de servicio de tiempo de ejecución del gestor de bases de datos que puede procesar el compilador del lenguaje principal.

Por lo tanto, si en algún momento el propio programa fuese el que tuviera que tomar una decisión (en tiempo de ejecución decidir las sentencias a usar o las tablas a referenciar), esta variante no nos resultaría útil.

Para ello, se emplea la otra variante conocida como SQL dinámico, que facilita la generación y ejecución automática de las declaraciones del programa. Esto puede ser útil cuando es necesario escribir código que puede modificar las bases de datos, condiciones o servidores. Esto también hace más fácil automatizar tareas que se repiten varias veces.

Las declaraciones de SQL dinámico están guardadas como cadenas de caracteres que son introducidas cuando el programa se ejecuta. Estas declaraciones pueden ser introducidas por el programador o generadas por el mismo programa, pero a diferencia de las declaraciones de SQL estático, no están inmersas en el código fuente. En contraste con las declaraciones del SQL estático, las de SQL dinámico pueden cambiar de una ejecución a otra.

A continuación se muestra un ejemplo de una sentencia ejecutada dinámicamente en C:
    /* Actualizar columna de tabla mediante DYNAMIC SQL*/
    strcpy(hostVarStmtDyn, "UPDATE staff SET salary = salary + 1000 WHERE dept = ?");
    EXEC SQL PREPARE StmtDyn FROM :hostVarStmtDyn;
    EXEC SQL EXECUTE StmtDyn USING :dept
Las sentencias más relevantes del SQL dinámico son:

  • EXECUTE IMMEDIATE Prepara y ejecuta una sentencia que no utiliza ninguna variable del lenguaje principal. Se utiliza esta sentencia como alternativa a las sentencias PREPARE y EXECUTE. Por ejemplo:

      strcpy (qstring,"INSERT INTO WORK_TABLE SELECT *
      FROM EMP_ACT WHERE ACTNO >= 100");
      EXEC SQL EXECUTE IMMEDIATE :qstring;

  • PREPARE Convierte el formato de serie de caracteres de la sentencia de SQL en un formato ejecutable de la sentencia, asigna un nombre de sentencia y opcionalmente coloca información sobre la sentencia en una estructura SQLDA.

  • EXECUTE Ejecuta una sentencia de SQL previamente preparada. La sentencia se puede ejecutar repetidamente dentro de una conexión.

Etiquetas:

 
Posteado por Koenma a las 10:06, | 0 comentario(s)                  Ir al Inicio | Ir Arriba

SQL inmerso en C/C++ (Parte IV)


Representación de Valores Nulos

Si los datos a recuperar de una base de datos pueden contener valores nulos, la sentencia SELECT singular debe proporcionar un mecanismo para que el Sistema Gestor de Base de Datos comunique los valores nulos al programa de aplicación.Para ello, el manejo de los valores nulos se realiza mediante la utilización de variables indicadoras en la cláusula INTO.

Cuando se especifica una variable principal en la cláusula INTO, puede ir seguida inmediatamente del nombre de una variable indicadora asociada. De esta forma, una vez ejecutada la sentencia SELECT, el valor de la variable indicadora informa al programa sobre cómo interpretar los datos devueltos:

  • Un valor indicador 0 significa que la variable principal se le ha asignado un valor determinado recuperado por el Sistema Gestor. El programa de aplicación puede utilizar el valor de la variable principal en su procesamiento.

  • Un valor indicador NEGATIVO significa que el valor recuperado fue NULL. El valor de la variable principal es irrelevante y no debe ser utilizado por el programa de aplicación.

  • Un valor indicador POSITIVO indica un aviso de algún tipo tal como un error de redondeo, el truncamiento de alguna cadena, etc.
Puesto que no se puede conocer anticipadamente cuando se va a recuperar un valor nulo, se debería de especificar siempre una variable indicadora en la cláusula INTO para cualquier columna de resultados de consulta que pueda contener un valor nulo.

Si la sentencia SELECT produce una columna que contiene un valor NULL y no se ha especificado una variable indicadora para la columna, el SGBD tratará la sentencia como un error y devolverá un valor negativo para SQLCODE.

Las variables indicadores deben pues ser utilizadas para recuperar con éxito filas que pudieran contener valores NULL.

Manipulación de datos sin usar cursores

En este apartado, se tratan las diferentes manipulaciones de datos sin el empleo de cursores:
  • La operación de consulta se realiza con la siguiente variante de la sentencia SELECT del lenguaje de SQL interactivo:

      EXEC SQL SELECT [ALL | DISTINCT] (lista_elemento_selección) INTO (lista_variables_huéspedes)
      FROM (lista_relación)
      WHERE (condición_búsqueda)
      [GROUP BY (lista_atributo)]
      [HAVING (condición_búsqueda)]

      Bajo este contexto, la sentencia SELECT debe devolver una única tupla. En caso contrario,se producirá un error.
La única variante de la sentencia consiste en que la cláusula INTO especifica la lista de variables del programa que serán utilizadas para recibir los datos seleccionados (tal como habíamos visto en el ejemplo anterior con las variables indicadoras).

Los elementos de las lista de selección y de la lista de variables se corresponden uno a uno en el orden en que aparecen, por ello ambas listas deben tener el mismo número de elementos y ser de tipos de datos compatibles (esto depende de la implementación del SQL que se esté utilizando).

Las operaciones de actualización tienen la misma sintaxis que en el SQL interactivo con la única diferencia que se pueden incluir variables huéspedes. Por ejemplo:

    EXEC SQL UPDATE (nombre_tabla)
    SET (atributo) = :(variable_huesped)
    WHERE (condición)

Etiquetas:

 
Posteado por Koenma a las 10:04, | 0 comentario(s)                  Ir al Inicio | Ir Arriba

SQL inmerso en C/C++ (Parte III)


Variables Huéspedes

Las sentencias SQL pueden incluir referencias a variables huéspedes (o variables anfitrión) mediante la adición de un prefijo de dos puntos a las mismas con el fin de distinguirlas de los nombres de columnas de SQL, ya que ambas pueden tener el mismo nombre. Ejemplo:
    #define USER username
    EXEC SQL CONNECT :USER IDENTIFIED BY :password;
La declaración de las variables huéspedes se realiza dentro del bloque o sección de declaración de SQL incrustado. El tipo de datos de estas variables deben adaptarse al uso final para el que se encuentren declaradas.

Estas variables se emplean para comunicar las sentencias de SQL con las del lenguaje C. Una variable huésped puede ser de cualquier tipo de dato básico de C, además de tipo VARCHAR (importado de SQL). Puede ser también un array de caracteres (cadena de caracteres).

No obstante, so se soportan arrays multidimensionales, salvo que sean arrays de cadena de caracteres, que se interpretan como tal. En las sentencias de SQL deben de aparecer con un prefijo de dos puntos delante de su identificador. Por ejemplo:
    int x
    EXEC SQL SELECT *
    FROM TABLA
    WHERE (CAMPO = :x);

    El uso de punteros también está permitido.
En el caso de los arrays, tras realizar una inserción en una tabla determinada, el tamaño ‘n’ de un array, hará que en la sentencia de SQL, se inserten ‘n’ t-uplas y cada una tenga el contenido de cada casilla de ese mismo array. Es decir, los arrays se tratan como si de una tabla se tratase y se insertarán todas las t-uplas a la vez.

Las estructuras también se pueden utilizar como variables en los campos de una instrucción de SQL. Su uso conviene para agrupar filas de una tabla, siempre que tengan la misma estructura. Por ejemplo:
    struct fila {
      int campo1;
      char campo2[10];

    }

    Hacemos ejecución de la sentencia
    EXEC SQL INSERT INTO TABLA1 VALUES (:fila);
Con esto, insertamos en la tabla TABLA1 los valores correspondientes de la estructura ‘fila’cuyo tipo de dato de los campos contenidos en ella, sean iguales que los campos de la tabla TABLA1 (CAMPO1 VARCHAR(10) y CAMPO2 NUMBER).

Etiquetas:

 
Posteado por Koenma a las 10:03, | 0 comentario(s)                  Ir al Inicio | Ir Arriba

SQL inmerso en C/C++ (Parte II)


Área de Comunicaciones del SQL

El Área de Comunicaciones del SQL (SQLCA) es una estructura de datos que contiene variables de error e indicadores de estado. Gracias a ella, el programa de aplicación puede determinar el éxito o fallo de las sentencias SQL incorporado y actuar de manera correspondiente. En todo programa, la primera sentencia de SQL inmerso debería ser:
    EXEC SQL INCLUDE SQLCA;
Esta sentencia indica al precompilador de SQL que incluya un área de comunicaciones SQL en este programa.

Uno de los campos más importantes del Área de Comunicaciones del SQL es el SQLCODE, indicador de errores, y cuyos posibles valores son:

  • Cero: indica terminación con éxito de la sentencia.
  • Negativo: indica error serio que impidió la ejecución de la sentencia.
  • Positivo: indica condición de aviso, por ejemplo, truncamiento o redondeo.
No obstante, la variable SQLSTATE es la sustituta a la variable SQLCODE por estar estandarizada. Ésta variable consta de dos partes:

  • La clase de error (dos caracteres) que identifica la clasificación general del error.
  • La subclase de error (tres caracteres) que identifica el tipo específico de error dentro de una clase de error general.
La sentencia WHENEVER tiene como fin simplificar el manejo de errores en SQL inmerso. Es una directiva para el precompilador de SQL, no se trata de una sentencia ejecutable.Ésta indica al precompilador que genere automáticamente un código de gestión de errores a continuación de cada sentencia ejecutable del SQL inmerso y especifica lo que el código generado debería hacer.

En un programa, cualquier sentencia de SQL debería de estar seguida por un código que controlase los valores de las variables SQLCODE y SQLSTATE referentes a la ejecución de la instrucción. La simplificación de esta tarea, la realiza la sentencia WHENEVER.

El uso de la sentencia WHENEVER es de la siguiente forma:
    EXEC SQL WHENEVER (condición)(acción)
Las condiciones son:
  • NOT FOUND: se evalúa a ‘true’ si no se encuentran datos que cumplan las condiciones específicas en la instrucción (SQLCODE =+100).
  • SQLWARNING: se evalúa a ‘true’ si se produce algún aviso ‘m’ en la ejecución de la instrucción (SQLCODE > 0).
  • SQLERROR: se evalúa a ‘true’ si ha ocurrido algún error en la ejecución de la instrucción (SQLCODE <>
Las acciones pueden ser:
  • GOTO (etiqueta): significa que el procesador de SQL incluirá detrás de cualquier sentencia SQL del programa la sentencia IF (condición) THEN GO TO (etiqueta)
  • CONTINUE: el procesador de SQL no tomará ninguna acción siendo responsabilidad del programador controlar el flujo del programa.
  • STOP: detiene y aborta el programa.
  • DO: ejecuta una función de gestión de errores.
A continuación, se muestran todos los campos que contiene la estructura SQLCA:

    Struct sqlca {
      unsigned char sqlcaid[8]; /* Cadena “SQLCA”*/
      long sqlcabc; /* Longitud delSQLCA en bytes */
      long sqlcode; /* Código de estado SQL */
      short sqlerrml; /* Longitud del array de datos sqlerrmc */
      unsigned chart sqlerrmp[8]; /* Información de diagnóstico */
      long sqlerrd[6]; /* Varias cuentas y códigos de error */
      unsigned chart sqlwarn[8]; /* Array de indicadores de aviso */
      unsigned chart sqlext[8]; /* Extensión del array sqlwarn */

    }

Etiquetas:

 
Posteado por Koenma a las 9:58, | 0 comentario(s)                  Ir al Inicio | Ir Arriba

SQL inmerso en C/C++ (Parte I)

10 de julio de 2007

Índice
  1. Introducción
  2. Sentencias Ejecutables y No Ejecutables
  3. Área de Comunicación SQL
  4. Variables huéspedes
  5. Representación de valores nulos
  6. Manipulación de Datos sin usar cursores
  7. Programación con cursores
  8. SQL estático y SQL dinámico


Introducción

La mayoría de productos SQL permiten la ejecución de instrucciones SQL de una manera directa. Es decir, de una forma interactiva desde una terminal de línea. Sin embargo, también es posible la ejecución de las mismas como parte de un programa de aplicación. Lo cual, quiere decir, que dichas instrucciones se encuentren entremezcladas con las instrucciones del lenguaje de programación de dicho programa. Esto se conoce como SQL inmerso en un lenguaje de programación.

Este caso de la incrustación del SQL en un lenguaje de programación determinado, tal como el C, nos brinda la capacidad de realizar aplicaciones de acceso a datos eficaces y de gran potencia mediante la posibilidad de ambos lenguajes. En adelante, hablaremos del lenguaje C como el lenguaje anfitrión.

El entorno de SQL incrustado en C, conocido como Pro*C, se asocia a las aplicaciones referentes al conocido gestor de bases de datos Oracle. Dicho gestor proporciona acceso a las bases de datos mediante un programa en C utilizando un preprocesador, el cual transforma las sentencias de Pro*C a sentencias de C. Estas sentencias tendrán acceso a las librerías ofrecidas por el gestor Oracle para la gestión de datos. Esto supone una ventaja por la mayor legibilidad de código a la hora de programar, ya que evitamos una compleja sintaxis que puede tener las llamadas a una determinada biblioteca.

A su vez, aparece también una desventaja. El uso de un preprocesador supone la inserción de sentencias que no tienen relación con el lenguaje. Esto es, el código resultante después del preprocesado complica la tarea de depuración de programas. Lo cual, su uso no favorece en la claridad del código en C.

Sentencias Ejecutables y No Ejecutables

Las sentencias del SQL incrustado en C van precedidas por la sentencia EXEC SQL para distinguirlas de las instrucciones del lenguaje anfitrión y terminan con un punto y coma.

Una sentencia SQL ejecutable puede aparecer en cualquier parte en donde aparezca una instrucción del lenguaje C. No toda sentencia SQL es ejecutable. Hay sentencias que son puramente declarativas, como por ejemplo:

EXEC SQL BEGIN DECLARE SECTION; /* comienzo de declaración de variables */

    short id;
    char name[10];
    short dept;
    double salary;
    char hostVarStmtDyn[50];

EXEC SQL END DECLARE SECTION; /* finalizacion de declaración de variables */

La declaración de las variables a usar es lo primero es la primera tarea en la realización del programa.

Etiquetas:

 
Posteado por Koenma a las 20:06, | 0 comentario(s)                  Ir al Inicio | Ir Arriba