Para ilustrar las ideas que estamos explicando, a lo largo de este libro usaremos el lenguaje Tu-
torial D (o, más bien, una ligera variante del mismo), el cual fue mencionado por primera vez
en el capítulo 3. El Tutorial D podría ser caracterizado, a grandes rasgos, como un lenguaje al estilo de Pascal. Presentaremos cada una de sus características sobre la marcha. Obviamente, lo primero que necesitamos es una forma para que los usuarios definan sus propios tipos:
TYPE <nombre de tipo> <representación posible> ... ;
A manera de ejemplo, presentamos las definiciones de tipos (retomadas de la figura 3.9) para la base de datos de proveedores y partes:
TYPE V# POSSREP ( CHAR ) ; TYPE NOMBRE POSSREP ( CHAR ) ; TYPE P# POSSREP ( CHAR ) ; TYPE COLOR POSSREP ( CHAR ) ; TYPE PESO POSSREP ( RATIONAL ) ; TYPE CANT POSSREP ( INTEGER ) ;
116 Parte II / El modelo relational
Explicación:
1. Primero recuerde (del capítulo 3) que el atributo STATUS de proveedor y los atributos CIU- DAD de proveedor y de parte están definidos en términos de tipos integrados, en lugar de estar definidos por el usuario; de manera que no se muestran definiciones correspondientes a estos atributos.
2. Como ya hemos visto, las representaciones físicas están ocultas para el usuario. Por lo tanto, las definiciones de tipos no dicen nada acerca de esas representaciones físicas. En vez de ello, dichas representaciones deben ser especificadas como parte de la transformación con ceptual/interna (vea el capítulo 2, sección 2.6).
Sin embargo, por razones que explicaré en la siguiente subsección, sí requerimos que cada tipo tenga asociada por lo menos una representación posible. En el ejemplo, los valo- res de tipo V#, NOMBRE, P# y COLOR tal vez podrían ser representados como caden de caracteres (de cualquier longitud necesaria); los valores de tipo CANT podrían ser re-presentados como enteros, y los valores de tipo PESO como números racionales. Nota: i lo largo de este libro (siguiendo la referencia [3.3]), preferimos el término más preciso RATIONAL en lugar del más familiar REAL.
3. Adoptamos las convenciones obvias de sintaxis en donde (a) las representaciones ] sin nombre heredan el nombre del tipo relevante; (b) los componentes de las represe ciones posibles sin nombre heredan el nombre de la representación relevante posible. 1 ahí que, por ejemplo, la única representación posible definida para el tipo CANT se llame también CANT, así como el único componente de esa representación posible.
4. La definición de un nuevo tipo ocasiona que el sistema cree una entrada en el catálogo paral describirlo (si necesita recordar algo con respecto al catálogo, consulte el capítulo 3, sec-j ción 3.6). Observaciones similares se aplican también a las definiciones de operadores (vea las siguientes dos subsecciones).
5. Quizás haya notado que algo que no hacen las definiciones TYPE anteriores es especificar los valores reales que conforman los tipos en cuestión. Esa función la realizan las ¡ ciones asociadas al tipo (que en la sintaxis anterior se indican mediante puntos suspensivos "..."), las cuales explicaremos en el capítulo 8.
Por supuesto, también debe ser posible deshacerse de un tipo si ya no tenemos un uso adi- cional para él.
DROP TYPE <nombre de tipo> ;
El <nombre de tipo> debe identificar un tipo definido por el usuario, no uno integrado. La j operación ocasiona que la entrada del catálogo que describe al tipo sea eliminada, lo que sig-J nifica que el tipo en cuestión ya no es conocido por el sistema. Nota: Por razones de simplici- dad, asumimos que DROP TYPE fallará si el tipo en cuestión está en uso en cualquier otra parte; en particular, si algún atributo de alguna relación, en alguna parte, está definido sobre él.
Representaciones posibles
Con el fin de ilustrar la importancia del concepto de "representación posible", consideramos un ejemplo un poco más complicado:
T Y P E P U N T O / * p u n t o s g e o m é t r i c o s * /
POSSREP CARTESIANO ( X RATIONAL, Y RATIONAL ) POSSREP POLAR ( R RATIONAL, THETA RATIONAL ) ;
Primero, observe que el tipo PUNTO tiene dos representaciones posibles distintas, CARTE- SIANO y POLAR, lo que refleja el hecho de que los puntos geométricos pueden en efecto ser representados mediante coordenadas cartesianas o polares. (Por supuesto, la representación física en el sistema particular en uso podría ser con coordenadas cartesianas o coordenadas po- lares o algo enteramente distinto). Cada representación posible tiene a su vez dos componentes. Observe en particular que este ejemplo difiere de los anteriores en que, en esta ocasión, a las re- presentaciones posibles y a sus componentes se les han dado nombres explícitos.
Toda declaración de representación posible provoca la definición automática* de los si- guientes operadores, que son más o menos fáciles de entender:
■ Un operador selector (con el mismo nombre que la representación posible) que permite al usuario especificar o seleccionar un valor del tipo en cuestión, suministrando un valor para cada componente de la representación posible;
■ Un conjunto de operadores THE_ (uno para cada componente de la representación posi ble) que permiten al usuario acceder a los valores de los componentes correspondientes a la representación posible del tipo en cuestión.
Por ejemplo, aquí tenemos algunas muestras de invocaciones al selector y al operador THE_ para el tipo PUNTO:
CARTESIANO ( 5.0, 2.5 )
/* denota el punto con x = 5.0 , y = 2.5 */
CARTESIANO ( XXX, YYY )
/* denota el punto con x = XXX , y = YYY — */ /• XXX y YYY son variables de tipo RATIONAL */
POLAR ( 2.7, 1.0 )
/* denota el punto con r = 2.7 , theta = 1.0 */
THE_X ( P )
/* regresa la coordenada x del punto P */ /* — P es una variable de tipo PUNTO */
THE_R ( P )
/ * r e g r e s a l a c o o r d e n a d a r d e l p u n t o P * /
Nota: Como puede ver, los selectores (o más bien, las invocaciones a selectores) son una ge- neralización del concepto de literal ya conocido.
Para ver cómo funcionaría lo anterior en la práctica, suponga que la representación física de los puntos está de hecho en coordenadas cartesianas (aunque en general no hay necesidad de que una representación física sea idéntica a cualquiera de las representaciones posibles especi-
* Aquí, por "automático" queremos decir que (a) cualquiera que sea la agencia —probablemente el sis- tema, probablemente algún usuario humano—, es la responsable de definir la representación posible en cuestión, también es responsable de definir los operadores correspondientes; y queremos decir que (b) hasta que dichos operadores hayan sido definidos, no está terminado el proceso de definición de esa re- presentación posible.
118 Parte II / El modelo relational
ficadas). Entonces, el sistema proporcionará ciertos operadores altamente protegidos —deno- minados desde este momento como seudocódigo en cursivas— que expongan efectivamente la representación física y el definidor del tipo usará entonces dichos operadores para implementar los selectores CARTESIANO y POLAR necesarios.* Por ejemplo:
OPERATOR CARTESIANO ( X RATIONAL, Y RATIONAL )
RETURNS ( PUNTO ) ¡ BEGIN ;
VAR P PUNTO ;
componente X de la representación física de P := X ; componente Y de la representación física de P := Y ; RETURN
( P ) ; END ; END OPERATOR ;
OPERATOR POLAR ( R RATIONAL, THETA RATIONAL )
RETURNS ( PUNTO ) ; RETURN ( CARTESIANO ( R * COS ( THETA ),
R * SIN ( THETA ) ) ) J END OPERATOR ;
Observe que la definición de POLAR hace uso del selector CARTESIANO, así como de loa operadores (presuntamente integrados) SIN y COS. De manera alternativa, la definición del POLAR podría expresarse directamente en términos de los operadores protegidos, como sigue: 1
OPERATOR POLAR ( R RATIONAL, THETA RATIONAL )
RETURNS ( PUNTO ) ; BEGIN ;
VAR P PUNTO ;
componente X de la representación física de P
:= R * COS ( THETA ) ; componente Y de la representación física de P
:= R * SIN ( THETA ) ; RETURN (
P ) ; END ; END OPERATOR ;
El definidor de tipos también usará esos operadores protegidos para implementar los ( radores THE_ necesarios, por lo tanto:
OPERATOR THE_X ( P PUNTO ) RETURNS ( RATIONAL ) ;
RETURN ( componente X de la representación física de P ) ; END OPERATOR ;
OPERATOR THE_Y ( P PUNTO ) RETURNS ( RATIONAL ) ;
RETURN ( componente Y de la representación física de P ) ; END OPERATOR ;
OPERATOR THE_R ( P PUNTO ) RETURNS ( RATIONAL ) ; RETURN ( SORT ( THE_X ( P ) **2 + THE_Y ( P ) * * 2 . ) ) ; END OPERATOR ;
OPERATOR THE_THETA ( P PUNTO ) RETURNS ( RATIONAL ) ; RETURN ( ARCTAN ( THE_Y ( P ) / THE_X ( P ) ) ) ; END OPERATOR ;
* Obviamente, el definidor de tipos es —de hecho, debe ser— una excepción a la regla general de que los usuarios no estén al tanto de las representaciones físicas.
Observe que la definición de THE_R y THE_THETA hacen uso de THE_X y THE_Y, así como de los operadores (presuntamente integrados) SQRT y ARCTAN. Como alternativa, THE_R y THE_THETA podrían ser definidos directamente en términos de los operadores pro- tegidos (dejamos los detalles como un ejercicio).
Hasta aquí el ejemplo del PUNTO. Sin embargo, es importante entender que todos los con- ceptos explicados se aplican también a tipos más sencillos; por ejemplo, el tipo CANT. He aquí algunos ejemplos de invocaciones de selector para ese tipo:
CANT ( 100 )
CANT ( C )
CANT ( ( C1 - C2 ) * 2 )
Y aquí algunas muestras de las invocaciones al operador THE_:
THE_CANT ( C )
THE_CANT ( ( C1 - C2 ) * 2 )
Observe en particular que debido a que los valores siempre tienen un tipo, es estrictamente incorrecto decir (por ejemplo) que la cantidad de un cierto envío es 100. Una cantidad es un valor de tipo CANT, ¡no un valor de tipo INTEGER! Por lo tanto, para el envío en cuestión, sería más propio decir que la cantidad es CANT(1OO), no sólo 100. Sin embargo, en contextos informales a menudo no nos molestamos en ser tan precisos y usamos (por ejemplo) 100, como una abre- viatura cómoda de CANT(100).* En particular, hemos usado estas abreviaturas en la figura 3.8 (la base de datos de proveedores y partes) y en la figura 4.5 (la base de datos de proveedores, partes y proyectos).
Damos un último ejemplo de definición de tipo, SEGLIN (segmentos de línea):
TYPE SEGLIN POSSREP ( INICIO PUNTO, FIN PUNTO ) ;
Por supuesto, una determinada representación posible puede estar definida en términos de tipos definidos por el usuario, como aquí, no sólo en términos de tipos definidos por el sistema, como en todos nuestros ejemplos anteriores.