Tema 11. Modelo en red Juan Ignacio Rodrı́guez de León Resumen Conceptos básicos. Diagramas de estructura de datos. El modelo CODASYL DBTG Índice 1. Introducción 1.1. Registros, tipos de registros y datos . . . . . . . 1.2. Conjuntos, Tipos de Conjuntos e Instancias . . 1.3. Restricciones de los miembros de un conjunto 1.4. Tipos especiales de conjuntos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 2 3 4 5 2. Base de datos de ejemplo 6 3. Facilidades para la recuperación de datos 3.1. Área de trabajo de programa . . . . . . . . . . . . . . . . . . 8 8 4. Ordenes de recuperación (get) y navegación (find) 4.1. Acceso a registros individuales . . . . . . . . . 4.2. Acceso a registros dentro de un conjunto . . . 4.3. Predicados . . . . . . . . . . . . . . . . . . . . . 4.4. Inserción y modificación . . . . . . . . . . . . . 4.5. Ordenación . . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 9 10 11 11 11 1 INTRODUCCIÓN 1. 2 Introducción El modelo de red es, actualmente, una de las tres formas de organizar la información más utilizada en los sistemas comerciales de bases de datos. Históricamente, las estructuras y el lenguaje del modelo fueron definidas por el comité CODASYL por lo que, en mucha de la bibliografı́a existente, al modelo en red se le denomina CODASYL. Posteriormente, el ANSI (American National Standards Institute) realizó algunas modificaciones y recomendaciones sobre el lenguaje. Como se verá a lo largo del desarrollo de este capı́tulo,el lenguaje de un sistema en red no es como SQL, un lenguaje autónomo en sı́, sino que se compone de una serie de funciones que habrá que usar de manera inmersa dentro de un lenguaje anfitrión. Para este propósito, y debido a que es uno de los lenguajes más difundidos, se utilizará PASCAL como lenguaje anfitrión, (aunque, en función del lenguaje comercial en cuestión, el lenguaje puede ser otro, como C, COBOL, etc...) El nombre de las funciones de un sistema de red también varı́a en función del producto comercial con que se trabaje, aunque la función en si sea la misma. Por ello, en este capı́tulo se nombrarán estas funciones de una manera general y sin particularizar en un sistema concreto, pero teniendo bien claro que cualquiera de las funciones utilizadas aquı́ tendrá una homólogo en el sistema comercial utilizado. Visto esto, la idea que debe sacarse en claro es que lo importante de este capı́tulo es asimilar el funcionamiento y la manera de trabajar de un sistema en red. Antes de pasar a describir y utilizar el lenguaje en sı́, se definirán de manera muy breve las estructuras básicas de datos que componen un sistema en red. 1.1. Registros, tipos de registros y datos En el modelo relacional, los datos y las relaciones entre ellos se representan mediante una colección de tablas. En el modelo en red, los datos se representan como colecciones de registros, y las relaciones entre los datos se representan mediante enlaces. Un registro es un conjunto de valores de datos relacionados. Se clasifican en tipos de registros, donde cada tipo describe la estructura de un grupo de registros que almacenan la misma información. Por ejemplo, un Tipo de registro ESTUDIANTE podrı́a ser: DNI ESTUDIANTE NOMBRE APELLIDOS DIRECCION Mientras que una instancia de este tipo de Registro podrı́a ser la siguiente: 1 INTRODUCCIÓN 81211871 3 Antonio Garcı́a Castellana, 2 A diferencia de las base de datos relacionales, cuyos registros se engloban dentro de la estructura de la tabla relacional, los sistemas en red presentan un nuevo tipo de estructura denominada conjunto, que, como se verá posteriormente, permite enlazar unos registros con otros. 1.2. Conjuntos, Tipos de Conjuntos e Instancias Un tipo de conjunto es una descripción de 1 : n relaciones entre dos tipos de registros, Este tipo de estructuras se representan habitualmente por un diagrama de Bachman, el cual se compone generalmente de: Un nombre para el tipo de conjunto Un tipo de registro propietario Un tipo de registro miembro Un ejemplo de un conjunto que representa la relación ente las asignaturas en las cuales está matriculado un alumno podrı́a representarse de la siguiente manera: DNI ESTUDIANTE NOMBRE APELLIDOS DIRECCION ↓ ESTUDIA REG-ASIG ASIGNATURA NOMBRE CARRERA CURSO Donde el tipo de registro ESTUDIANTE es el tipo de registro propietario, ASIGNATURA es el tipo de registro miembro y ESTUDIA, el tipo de conjunto. Los tipos de conjunto, al igual que los tipos de registros, presentan también instancias de conjuntos o, como aparece en gran parte de la bibliografı́a, ocurrencias de conjuntos. Una ocurrencia de conjunto está compuesta por: Una instancia de registro propietario Un número cualquiera de ocurrencias de un registro miembro Una estructura de datos, generalmente del tipo de lista doblemente enlazada 1 INTRODUCCIÓN 4 Una ocurrencia de conjunto podrı́a ser, por ejemplo, la representada en la figura 1, en la que, como puede verse, aparece un registro propietario (ESTUDIANTE) enlazado con tres registros miembros. Este tipo de estructura de datos suele implementarse mediante listas enlazadas o doblemente enlazadas, de manera que desde el registro propietario es posible acceder a cualquiera de las instancias de registro que pertenecen a esa ocurrencia de conjunto. Una base de datos, planteada según este modelo, consistirá en una serie de tipos de conjuntos entrelazados entre si de manera que un tipo de registro que en una ocurrencia de conjunto funciona como propietario, en otra ocurrencia de otro tipo de conjunto funciona como miembro. Figura 1: Ocurrencia de conjunto 1.3. Restricciones de los miembros de un conjunto En el modelo de red, existen ciertas restricciones que pueden especificarse sobre los miembros de un conjunto. Estas restricciones pueden ser de dos tipos: Restricciones de inserción Restricciones de mantenimiento Las restricciones de inserción especifican de que manera se deben insertar los miembros de un conjunto. A diferencia de otro tipo de base de datos, aquı́ es posible especificar, cuando se definen los conjuntos, como queremos que los nuevos registros se añadan a los existentes. Existen dos opciones: Automática La ocurrencia del registro que se añade a la base de datos queda conectada automáticamente a una ocurrencia del conjunto. 1 INTRODUCCIÓN 5 Manual Cuando se añade una ocurrencia nueva de registro a la base de datos,esta no se conecta a ninguna ocurrencia de conjunto sino que, mediante ciertas funciones que se verán posteriormente, el usuario lo debe conectar de manera manual. Las restricciones de mantenimiento especifican como deben existir los registros miembros dentro de una base de datos, es decir, si pueden existir sin un propietario o si, por el contrario, no tiene cabida en la base de datos si no están ligados a una ocurrencia de conjunto. Existen entonces tres opciones: Opcional Un registro miembro puede existir en la base de datos sin estar conectado a ninguna ocurrencia de conjunto. Estos tipos de registro pueden conectarse y desconectarse de una ocurrencia de conjunto a voluntad. Obligatoria Un registro miembro no puede existir en la base de datos sin un propietario, es decir, debe ser siempre miembro de una ocurrencia de conjunto. Pueden ser reconectado de una ocurrencia de conjunto a otra en un solo paso, utilizando para ello el comando RECONNECT. Fija Un registro miembro no puede existir sin un propietario y, además, una vez conectado por primera vez ya no puede reconectarse a ninguna otra ocurrencia de conjunto. 1.4. Tipos especiales de conjuntos Existen tres tipos especiales de conjuntos en CODASYL. Conjuntos sistema-propietario: son aquellos en los que no existe un tipo de registro propietario como tal, sino que es el propio sistema el que actúa como propietario del mismo. Este tipo de conjuntos tiene dos funciones muy importantes dentro de un sistema de red: • Proporciona un punto de entrada a la base de datos, mediante la especificación de alguno de sus registros miembros. • Pueden ser utilizados para ordenar las ocurrencias de un determinado tipo de registro usando las debidas condiciones de ordenación. Conjuntos multi-miembros: son aquellos en los que los tipos de registros miembro pueden ser más de uno. Conjuntos recursivos: Son aquellos en los que el mismo tipo de registro representa un papel de miembro y propietario a la vez, como en la figura 2: 2 BASE DE DATOS DE EJEMPLO 6 Figura 2: Conjuntos recursivos 2. Base de datos de ejemplo Figura 3: Base de datos de ejemplo Para los problemas del libro, y cuando ha salido este tema en el examen, se ha usado la base de datos cuya representación gráfica es la de la figura 3, que explicaremos a continuación: La base de datos guarda información sobre los EMPLEADOS de una empresa. Un empleado puede tener, mediante el subconjunto SUBORDINADOS, a un grupo de empleados a su cargo. También se almacena información sobre los DEPARTAMENTOS de la empresa, donde cada departamento tiene asociando a un conjunto de empleados mediante el conjunto ESTA-EN. A su vez, mediante en conjunto CONTROL, cada departamento se encontrará trabajando en unos determinados PROYECTOS, los cuales a través de los conjuntos TRAB-PROY y TRABAJA-EN tendrán asignados un grupo de empleados. 2 BASE DE DATOS DE EJEMPLO 7 Por último, existe un tipo de registro denominado SUPERVISOR, en el cual se encuentran los DNI de los directores de la empresa. Este tipo de registro está asociado a dos conjuntos distintos: Por una parte es propietario del conjunto SUPERVISA, lo cual significa que cada SUPERVISOR llevará asociado una lista enlazada de EMPLEADOS a sus ordenes. Además, el tipo de registro SUPERVISOR es miembro del conjunto ES-SUPERV, lo que significa que cada empleado llevará asociado una lista enlazada de SUPERVISORES, los cuales son jefes suyos. A la base de datos se entra mediante el conjunto DEPARTAMENTOS, que es propiedad del sistema. Un ejemplo de consulta a esta base de datos podrı́a ser: Encontrar e imprimir el salario de todos los empleados que trabajan en el departamento de nombre “ventas”. departmento.nombre := ’ventas’; find any departamento using nombre; if DB-Status = 0 then begin find first empleado within trabaje-en; while DB-Status = 0 do begin get empleado; writeln(empleado.salario); find next empleado within trabaja-en; end; end; Mediante la función find any se encuentra el primer departamento cuyo nombre sea “ventas” (Se supone que sólo habrá uno). Si el resultado es satisfactorio (DB-Status=0), habremos localizado correctamente el departamento de ventas. Lo que se hace a continuación es avanzar por la lista enlazada, de la cual el es propietario ese departamento según el conjunto trabaja-en, obteniendo por tanto todos los registros de empleados asignados al departamento. Mientras vaya encontrado registros imprime los salarios correspondientes. Cuando DB-Status sea distinto de cero significa que hemos terminado, y salimos del bucle. Veremos con más detalle las particularidades de las ordenes find y get en la siguiente sección. 3 FACILIDADES PARA LA RECUPERACIÓN DE DATOS 3. 3.1. 8 Facilidades para la recuperación de datos Área de trabajo de programa Todo programa que se ejecute en un sistema consta de una secuencia de ordenes; algunas son propias del lenguaje anfitrión utilizado, mientras que otras serán sentencias de órdenes DBTG. Cada programa en ejecución se denomina unidad de ejecución (run unit). Para cada programa, el sistema mantiene un área de trabajo (Denominada en el modelo DBTG como área de trabajo de usuario, user work area) que contiene las siguientes variables: Plantillas de registro: Un registro (entendido como registro en el lenguaje anfitrión, por ejemplo, un registro Pascal) para cada tipo de registro utilizado por la aplicación. Punteros de actualidad (Currency pointers): Un conjunto de punteros a diversos registros de la base de datos que apuntan al registro accedido más recientemente por el programa. Los punteros de actualidad pueden ser de varios tipos: • Punteros actual al tipo de registro: Un puntero para cada tipo de registro T referenciado por el programa; cada puntero contiene la dirección (localización en disco) del tipo de registro T accedido más recientemente. • Punteros actual al tipo de conjunto: Un puntero que, para cada tipo de conjunto definido en el esquema de la base de datos, especifica la última ocurrencia a la que se ha accedido. Como cuando se accede a una ocurrencia de conjunto, a lo que se accede de verdad es a un registro, este puntero señalará al registro accedido de esa ocurrencia de conjunto. • Puntero actual de unidad de ejecución: Un único puntero, que contiene la dirección del último registro (independientemente de su tipo) accedido por la aplicación. Indicadores de estado, que son un conjunto de variables que utiliza el sistema para comunicar a la aplicación el resultado de la última operación aplicada a la base de datos. La más usado con diferencia es la variable DB-status, que valdrá 0 si la operación tuvo éxito o un código de error en caso contrario. Por ejemplo, el resultado de una operación puede ser la excepción FIN-DE-CONJUNTO (EOS, Endof-set), que indicarı́a que no existen más registros miembros dentro de una ocurrencia de conjunto. Esta situación se produce cuando cuando una orden DML que intenta encontrar el siguiente o el anterior miembro de una ocurrencia de conjunto, encuentra que no existe 4 ORDENES DE RECUPERACIÓN (GET) Y NAVEGACIÓN (FIND) 9 ninguno más. Por lo tanto, es habitual comprobar esta variable como condición de salida de un bucle. Las demás variables (DB-set-name, DB-record-name, y DBdata-name) se utilizan en caso de fallo, para obtener información adicional del mismo. 4. Ordenes de recuperación (get) y navegación (find) Las dos ordenes más usadas en este tipo de sistemas son get y find. find Localiza un registro en la base de datos, y actualiza los punteros correspondientes. get copia el registro al que apunta el puntero de la unidad de ejecución en el área de trabajo, en el registro patrón correspondiente. 4.1. Acceso a registros individuales La orden find se puede usar de diferentes formas, sólo se verán algunas de ellas. Hay dos maneras diferentes de localizar un registro individual. La forma más simple serı́a: find any [record type] using [record-field] Este mandato localiza un registro de tipo record type cuyo valor en record-field sea el mismo que el valor de record-field que hubiera en el registro patrón en el área de trabajo. Una vez que el sistema localiza el registro buscado, ajusta los punteros de forma que: el puntero de la unidad de ejecución actual apunta al registro buscado. el puntero al tipo de registro actual apunta al tipo del registro buscado (record-type). el puntero de conjunto actual para cualquier conjunto en el que pueda estar incluido dicho record type es actualizado, apuntando o bien a un tipo propietario o bien a un tipo miembro. Puede haber varios registros con el mismo valor especificado. La orden find encuentra el primero, siguiendo una ordenación que ha sido previamente especificada. Para localizar el resto de registros, se usa la orden find duplicate, como en el siguiente ejemplo: find duplicate [record type] using [record-field] 4 ORDENES DE RECUPERACIÓN (GET) Y NAVEGACIÓN (FIND) 10 que localiza el siguiente registro (según la ordenación preasignada) cuyo valor sea igual al especificado en el patrón. Los punteros que se enumeraron antes se ven afectados consecuentemente. Como ejemplo, veamos el siguiente fragmento de programa, que imprime los clientes que viven en la ciudad de Harrison. customer.customer-city := "Harrison"; find any customer using customer-city; while DB-status = 0 do begin get customer; print (customer.customer-name); find duplicate customer using customer-city; end; Se ha englobado parte de la búsqueda en un bucle, porque ignoramos el número de clientes que encontraremos. Salimos del bucle cuando la variable especial DB-status sea distinta de cero. Recuérdese que un valor distinto de cero indica que se ha fallado en la búsqueda del siguiente cliente, lo que significa que ya hemos recorrido todos los clientes de Harrison. 4.2. Acceso a registros dentro de un conjunto La sentencia find vista anteriormente busca cualquier registro del tipo indicado. Veremos ahora como localizar registros dentro de un conjunto. El conjunto en cuestión será el que esté referenciado por el puntero de conjunto actual. Hay tres tipos diferentes de órdenes. La orden de búsqueda básica es: find first [record type] within [set-type] Que localiza al primer registro de tipo record type en el conjunto actual de tipo set-type. para iterar sobre el resto de registros en el conjunto, se ejecuta repetidamente la siguiente orden: find next [record type] within [set-type] Es necesario especificar el tipo de registro porque el conjunto podrı́a contener registros de diferentes tipos. También podemos usar una orden find para encontrar al registro propietario de una determinada ocurrencia de conjunto: find owner within [set-type] 4 ORDENES DE RECUPERACIÓN (GET) Y NAVEGACIÓN (FIND) 4.3. 11 Predicados Para poder realizar una búsqueda que contemple un rango de valores, y no un único valor, debemos obtener todos los registros pertinentes en memoria, y examinar cada uno de ellos separadamente para poder determinar el valor de la condición de búsqueda. Como ejemplo, considérese el siguiente fragmento de código, que obtiene el número total de cuentas en la sucursal de Perryridge con un balance mayor que 10.000$. count := 0; branch.branch-name := "Perryridge"; find any branch using branch-name; find first account within account-branch; while DB-status = 0 do begin get account; if account.balance > 10000 then count := count + 1; find next account within account-branch; end print (count); 4.4. Inserción y modificación La creación y el borrado de nuevos registros se realiza mediante las ordenes store y erase. Las modificaciones se realizan con el mandato modify. Las primitivas connect, disconnect y reconnect permiten insertar o sustraer registros de una instancia de conjunto. Cuando se define un conjunto, se debe especificar la manera en que los registros deben ser insertados, y bajo que condiciones se permite que puedan ser transferidos de una ocurrencia a otra. Un registro recién creado puede ser añadido a una ocurrencia de conjunto bien explı́citamente o implı́citamente. Esta distinción se especifica en el momento de definir el conjunto, mediante la opción insertion is con los valores manual o automatic. 4.5. Ordenación Los registros miembros de un conjunto pueden ser ordenados de diferentes maneras. El tipo de ordenación a utilizar se especifica por el programador mediante la orden: order is [order-mode] Donde order-mode puede ser uno de los siguientes valores: 4 ORDENES DE RECUPERACIÓN (GET) Y NAVEGACIÓN (FIND) 12 first Al añadir un registro a un conjunto, se inserta el primero. El orden, por tanto, es cronológico inverso. last Al añadir un registro a un conjunto, se inserta el último. El orden, por tanto, es cronológico. next Si el puntero actual señala al registro x, el nuevo registro se inserta justo a continuación de x prior Si el puntero actual señala al registro x, el nuevo registro se inserta justo antes de x system default El orden es decidido de forma arbitraria por el sistema. sorted Las inserciones se realizan de forma que el conjunto se mantenga ordenado con respecto a los valores de un determinado campo, especificado por el programado a la hora de definir el conjunto. Se debe indicar si se desea un orden ascendente o descendente.