Tutoriales

Tutorial de SQL. Introducción

Introducción

SQL son las siglas de Structured Query Language, que traducido significa Lenguaje de consulta estructurado y que es el estandar de facto para acceso a base de datos.

En lenguaje SQL surgió a raiz de la creación en IBM durante la decada de los 70 de un sistema de base de datos llamado "System R". Para manipular y recuperar datos de dicho sistema se diseño un lenguaje llamado SEQUEL (Standard English Query Language) que finalmente se convertiría en SQL (la historia del cambio de nombre es curiosa y se debió a que el nombre SEQUEL ya estaba registrado por otra compañía, aún así hoy en día una de las pronunciaciones para SQL es, precisamente SEQUEL).

Este no pretende ser un tutorial de base de datos sino una pequeña introducción a SQL de forma que es recomendable saber algo de bases de datos antes de meterse en SQL. Es conveniente saber lo que es una base de datos, su estructura y cuanto menos algunos conceptos básicos (como el hecho de que está organizada en tablas, campos y registros). Si no lo has hecho ya y no tienes esos conceptos sería mejor que comenzaras por la Introducción a Bases de Datos. Además esto es, como se indica, solo una introducción, en posteriores entregas iremos viendo métodos más complejos, especialmente en lo que a los operadores de selección se refiere e iremos entrando con más profundidad en cada uno de ellos.

Safeguards en Delphi.

Introducción

Los safeguards son el nombre que recibe un ingenioso mecanismo que nos permite, en cierto sentido, olvidarnos de los problemas asociados a liberar memoria en Delphi y que simulan de alguna forma el funcionamiento de un recolector de basura. En C++, para aquellos que han trabajado alguna vez con él, este mecanismo se conoce como Smart Pointers.

El truco

El truco para "olvidarnos" de liberar los objetos cuando terminamos con ellos consiste en el uso de interfaces. En delphi los interfaces incorporan un mecanismo de conteo referencial automático. Esto significa que cuando no se van a usar más (por ejemplo cuando salen de ámbito o cuando se "sobreescriben" y no quedan referencias al objeto que implementa dicho interface) se destruyen automáticamente.

Utilizando esto podemos utilizar el mecanismo de Safeguards para encapsular cualquier objeto dentro de un interface de forma que cuando dicho interface se destruya (porque cualquiera de los motivos expuestos antes) nuestro objeto se libere automáticamente sin que tengamos que preocuparnos nosotros de ello.

Aplicaciones Multihilo en Delphi. Multihilo y el BDE

Introducción

Uno de los problemas del multihilo en Delphi se da a la hora de acceder a la base de datos. En Delphi no podemos sencillamente ejecutar el siguiente código desde una tarea por que, probablemente, nos de un error en tiempo de ejecución

procedure MiAccesoABD;
var
  qry : TQuery;
begin
  qry.DatabaseName := 'MiBaseDeDatos';
  qry.Sql.Add('SELECT * FROM Productos');
  qry.Open;
  .
  .  // Más código
  .
end;

El mundo del runtime en delphi.

Tiempo de diseño y tiempo de ejecución

En Delphi existen dos conceptos que suelen surgir bastante a menudo, tiempo de diseño (design time) y tiempo de ejecución (run time).

El concepto de tiempo de diseño se refiere, de alguna forma, al sistema de diseño del IDE de Delphi, es decir, la parte en la que arrastramos forms, botones, campos de texto, etc ... y los situamos en las posiciones que queremos, es decir, realizamos el diseño de nuestra aplicación.

El tiempo de ejecución se refiere al tiempo durante el cual el programa esta ejecutando, es decir, el tiempo de vida de la aplicación.

Tiempo de diseño vs Tiempo de ejecución

Cuando estamos creando nuestra aplicación, la forma más natural de definir el aspecto de esta ir creando los forms que necesitemos e ir añadiendo botones, campos de texto y otros y situandolos en pantalla hasta encontrar el diseño que buscamos.

Aplicaciones Multihilo en Delphi. Primitivas de sincronización de Windows

Introducción

En las anteriores partes, en los dos primeros articulos, hemos visto como crear y sincronizar hilos usando las clases predefinidas de Delphi. Estas clases son en realidad un encapsulamiento de las primitivas que nos proporciona windows para el control de hilos de ejecución pero hay determinadas cosas que no se pueden hacer con ellas y debemos recurrir directamente a los servicios que nos proporciona el sistema operativo.

Tipos de datos. Tabla Hash

Introducción

Una tabla hash es una estructura de datos que permite asociar claves con valores y cuya principal ventaja es una complejidad de inserción y busqueda de O(1) (O(n) en el peor de los casos).

Cuando tenemos la necesidad de almacenar datos en memoria tenemos una serie de opciones (listas enlazadas, arrays, arboles...) cada una de las cuales tienes sus ventajas y sus inconvenientes que normalmente consisten en establecer un compromiso entre espacio en memoria y velocidad.

Una lista enlazada aprovecha completamente el espacio de memoria pero la velocidad de busqueda es lineal, para encontrar un elemento debemos ir recorriendo la lista hasta encontrarlo, en un array reservamos toda la memoria que podríamos por adelantado pero por contra obtenemos un rendimiento de busqueda constante O(1). Los arboles constituyen una variación de las listas enlazadas en las cuales se mejora el rendimiento de busqueda (O(log(n))) a cambio de empeorar el rendimiento de inserción.

Las tablas hash constituyen una forma de obtener un rendimiento (casi) constante controlando la cantidad de memoria que deseamos compromenter, cuanto más pequeña sea la tabla mayor será el impacto sobre el rendimiento de la tabla debido al numero de colisiones.

Aplicaciones Multihilo en Delphi: Metodos de sincronización de Delphi

Introducción

Probablemente la parte más compleja al programar una aplicación con varios hilos es la sincronización entre estos tanto en el acceso a los datos compartidos como en el correcto orden de ejecución que deben seguir.

Uno de los problemas de desarrollar una aplicación multihilo es que son bastante dificiles de depurar puesto que los hilos van entrando y saliendo de ejecución conforme se va acabando su tiempo de ejecución de forma que, al depurar, el depurador va saltando de una linea de código a otra dependiendo de la tarea que vaya estando en la CPU así que siempre hay que tener mucho cuidado al escribir el código por que, si vas a tener que depurarlo, vas a pasarte un buen rato en ello (por no hablar del hecho de que los hilos no tienen porqué, y probablemente no lo haga, ejecutar en el mismo orden y con los mismos tiempos en dos ejecuciones consecutivas).

En esta parte trataremos los objetos de sincronismo más importante que proporciona Delphi mientras que en el siguiente nos centraremos en las primitivas de sincronización que proporciona la API de windows.

Clases abstractas e interfaces

Metodos y clases abstractas

En general entendemos por clase totalmente abstracta cualquier clase en la que todos sus metodos son abstractos.

La abstracción de metodos es una técnica muy util para definir patrones de comportamiento de aquellas clases que hereden de la clase que estamos definiendo.

Un metodo abstracto es un metodo de una clase para el cual no se va a proporcionar implementación sino que se espera que que las clases que heredan de ella implementen dicho metodo. En delphi, si se intenta ejecutar un metodo abstracto obtendremos una excepción puesto que realmente no hay un código definido para ese metodo. El ejemplo más clasico de metodo abstracto es algo así:

Delegados en Delphi. Pasando metodos y funciones como parametros.

Que es un delegado

Un delegado (de la palabra inglesa delegate) es un prototipo de función es decir, un esquema que debemos seguir al declarar una función. La palabra delegado proviene (o mejor dicho yo la escuche por primera vez) de C# y probablemente en delphi sería más conveniente referirse a ellas como tipos de funciones.

Los delegados se utilizan fundamentalmente para proporcionar tipado al paso de funciones como parametros a otras funciones o metodos.

Para que sirve un delegado

Si alguien ha programado alguna vez en C sabrá que pasar funciones como parametros esta a la orden del día, estas funciones suelen conocerse con el nombre de funciones de CallBack (algo así como "devuelveme la llamada") e implican que tu estás pasando una función como parametro que quieres que sea invocada cuando dicha función tenga unos ciertos datos preparados.

Una buena parte de las funciones de la API de windows funcionan de esta forma, por ejemplo si observamos la ayuda de la función EnumWindows de la API de windows (kernel32.dll):

La funcion EnumWindows enumera todas las ventans de alto nivel de la pantalla pasando el manejador de cada ventana a una funcion de callback definida por la aplicación. EnumWindows ejecuta hasta que la última ventana sea enumerada o hasta que la función de callback devuelva falso.

    BOOL EnumWindows(

    WNDENUMPROC lpEnumFunc,     // pointer to callback function
    LPARAM lParam       // application-defined value
   );

Uso de memoria en Delphi

Introducción

Hace poco me he encontrado en el trabajo con un programa que estaba haciendo estaba teniendo pérdidas de memoria, no demasiada cada vez pero si lo suficiente como para convertirse en un problema a medio plazo.

Cuando te encuentras un problema de consumo de memoria lo más habitual es mirar el código de la zona en la que piensas que puede estar el problema intentando encontrar el lugar donde consumes memoria que luego no vas a liberar, o bien recurrir a algún programa de monitorización de memoria que te ayude a encontrar dichos problemas (yo no he tenido suerte con ellos).

Puesto que el programa tiene demasiadas lineas de código para hacer una revisión al azar sin saber concretamente donde se producían las perdidas de memoria se me ocurrió que la forma más sencilla de acotar el problema sería ir monitorizando el uso de memoria del programa (esto así dicho suena muy facil pero en realidad no lo es tanto).