- Introducción
La estrecha integración del acceso a bases de datos es un punto fuerte del lenguaje ABAP. Sin embargo, en muchas situaciones el código Open SQL que se va a ejecutar no se conoce durante el tiempo de codificación. ABAP tiene todas las características necesarias para ejecutar consultas Open SQL dinámicamente.
El lenguaje de programación SAP ABAP proporciona una variedad de formas de acceder a los datos empresariales que residen en una aplicación SAP, desde una capa abstracta orientada a objetos hasta campos de tabla individuales de la base de datos subyacente.
A veces, el código SQL que debe ejecutarse no se conoce durante el tiempo de programación. Puede especificar consultas estáticas para utilizar variables en la cláusula FROM, INTO, WHERE, GROUP BY, ORER BY.
ABAP utiliza la especificación de token dinámico para especificar dinámicamente una cláusula de Open SQL. Para ello se utiliza una variable de tipo carácter entre paréntesis o una tabla interna. La variable entre paréntesis debe contener una cláusula SQL válida, que se analiza en tiempo de ejecución. El token dinámico también puede ser una tabla interna con una columna de tipo string o CHAR. La columna no puede exceder una longitud de 72. La condición no distingue entre mayúsculas y minúsculas. Si se utiliza una tabla, la condición puede abarcar un número arbitrario de líneas siempre y cuando los identificadores, como los nombres de campo, no estén envueltos por palabras. Las reglas en este caso son similares a la forma en que se escribe las sentencias Open SQL estáticas en ABAP.
Una sentencia OPEN SQL siempre necesita una estructura de datos donde pueda poner los resultados de la llamada, como una estructura o una tabla interna. Esta estructura necesita tener campos que tengan tipos de datos compatibles con los campos seleccionados. Si este no es el caso, habrá errores de conversión de datos durante el tiempo de ejecución. En SQL estático, esto no es un problema, ya que los tipos de datos esperados se conocen durante el tiempo de programación. En la mayoría de los casos sólo se seleccionan los campos de una tabla y se puede utilizar una estructura del tipo de estructura de la tabla de base de datos como estructura de destino. Esto ya no funciona si utiliza tablas y campos arbitrarios para especificar dinámicamente la cláusula FROM o la cláusula de INTO, ya que los tipos de conjunto de resultados no se pueden determinar en el tiempo de programación. En este caso, se debe crear una estructura de destino dinámicamente en tiempo de ejecución para que se ajuste a los tipos de datos del conjunto de resultados especificado dinámicamente, como se describe en la siguiente sección.
Esta sección describe cómo crear dinámicamente una estructura de destino en tiempo de ejecución utilizando los servicios de tipo de tiempo de ejecución (RTTS API de ABAP). Todas las consultas SELECT requieren una estructura de fila para almacenar los datos de la fila recuperada. Los tipos de esta estructura de fila deben ser compatibles con los tipos de los campos correspondientes que se seleccionan. Si utiliza la cláusula INTO estándar, la fila se rellena en el orden de los campos seleccionados. Si sólo se seleccionan campos basados en caracteres, puede utilizar una estructura de filas de cadenas que tenga un número suficiente de campos. Esto no funciona para todos los tipos de campo, incluido DATS.
Si es necesario seleccionar campos de tipos arbitrarios y los tipos de campos no se conocen de antemano, debe construir dinámicamente una estructura de filas con campos de los tipos necesarios. Puede hacerlo de varias maneras. Si sólo se seleccionan campos de una tabla de base de datos y se conoce el nombre de tabla en tiempo de ejecución, es posible recuperar una estructura de fila de la tabla de base de datos del diccionario de datos y utilizar la cláusula INTO CORRESPONDING FIELDS. Sin embargo, esto no es posible si las tablas de base de datos se unen con INNER JOIN y se devuelven campos de más de una tabla. En este escenario, una estructura de fila con los campos debe construirse dinámicamente en tiempo de ejecución.
ABAP proporciona una extensa API para el análisis de tiempo de ejecución y la creación de tipos de datos. El núcleo de estos es un conjunto de clases de objetos ABAP que se pueden utilizar para describir tipos, para analizar objetos existentes y para instanciar descripciones de tipos. Éstos forman parte de la biblioteca de clases RTTS (Runtime Type Services). La biblioteca contiene toda la información necesaria para crear un tipo en tiempo de ejecución. Además, la biblioteca proporciona métodos de clase para crear objetos de su tipo de diferentes maneras.
Las clases son las siguientes:
Una clase que define la descripción de tipos de datos ABAP básicos, como c (carácter), i (entero) y f (punto flotante).
Una descripción de tipo para la cual se necesita la clase CL_ABAP_DATADESCR hijo para crear dinámicamente un tipo. CL_ABAP_TYPEDESCR también proporciona métodos auxiliares para crear una descripción del tipo de un objeto existente. La clase también puede crear un tipo de valor de un campo de base de datos, dado el nombre de campo de la tabla de base de datos.
Un análogo a CL_ABAP_TYPEDESCR, CL_ABAP_STRUCTDESCR es la descripción de un tipo de estructura. Por ejemplo, proporciona métodos para crear un tipo de estructura a partir de una lista de objetos CL_ABAP_TYPEDESCR, que definen los tipos de los campos de la estructura.
La descripción de una tabla interna CL_ABAP_TABLEDESCR necesita un CL_ABAP_STRUCTDESCR para definir el tipo de fila de la tabla interna.
Después de crear la tabla ABAP_COMPONENT_TAB que contiene todas las definiciones de componentes, puede utilizar CL_ABAP_STRUCTDESCR=> CREATE para crear la definición de estructura para su objeto. El método crea el objeto de descripción en la memoria y devuelve una referencia al objeto.
El segundo paso es crear una estructura de este tipo utilizando la sentencia CREATE DATA … TYPE HANDLE. La palabra clave HANDLE especifica que se utiliza una referencia a una clase RTTS para instanciar el objeto.
Debido a que la sentencia CREATE DATA crea un objeto en memoria y devuelve una referencia a esto, todavía no puede utilizar este objeto en la cláusula INTO del comando SELECT porque esto requiere un objeto de datos y no una referencia. En su lugar, ABAP proporciona FIELD SYMBOLS de cualquier tipo que toman el lugar de un objeto de datos. Por lo tanto, necesita utilizar la expresión -> * y asignarla a un FILED SYMBOLS de TYPE ANY.
Dynamic Open SQL es una herramienta muy potente para abordar la mayoría de las situaciones de programación que requieren acceso a la base de datos. No es necesario generar el Código fuente ABAP de una subrutina o programa completo, pero sólo las partes de una declaración que contienen
elementos dinámicos. Esto se logra mediante especificación de token. Todas las partes de una sentencia SQL pasa por una comprobación de sintaxis estática en tiempo de compilación.
La mayoría de las cláusulas que se utilizan en una instrucción Open SQL, como pueden ser el nombre de la tabla, la variable utilizada en el FROM, WHERE, GROUP BY, HAVING y ORDER BY pueden especificarse dinámicamente. En la variable de la cláusula INTO se puede especificar dinámicamente un objeto de datos en tiempo de ejecución con un tipo especificado también dinámicamente.
Con ABAP Release 6.10, es posible capturar excepciones del sistema que ocurren durante la ejecución de una sentencia SQL dinámica que causaría el programa para terminar con un error de tiempo de ejecución. Esta libera a los programadores de la necesidad de proporcionar código que verifica la validez de los datos de entrada antes de la ejecución de la declaración. En su lugar, redirige la ejecución al usuario para introducir los datos correctos.
Una sentencia OPEN SQL con componentes dinámicos requiere un poco más de tiempo de ejecución si lo comparamos con la misma sentencia estática. Aunque medible, esta sobrecarga suele ser mucho menor que el tiempo necesario para el acceso a la base de datos, de hecho, es insignificante con el exceso enorme que se requiere para la generación completa del código fuente sin las sentencias dinámicas.