Las vistas y el sistema de reglas.

Implementaci�n de las vistas en Postgres

Las vistas en Postgres se implementan utilizando el sistema de reglas. De hecho, no hay diferencia entre

    CREATE VIEW myview AS SELECT * FROM mytab;
y la secuencia:
    CREATE TABLE myview 
    (la misma lista de atributos de mytab);
    CREATE RULE "_RETmyview" AS ON SELECT TO myview DO INSTEAD
        SELECT * FROM mytab;
Porque esto es exactamente lo que hace internamente el comando CREATE VIEW. Esto tiene algunos efectos colaterales. Uno de ellos es que la informaci�n sobre una vista en el sistema de cat�logos de Postgres es exactamente el mismo que para una tabla. De este modo, para los traductores de queries, no hay diferencia entre una tabla y una vista, son lo mismo: relaciones. Esto es lo m�s importante por ahora.

C�mo trabajan las reglas de SELECT

Las reglas ON SELECT se aplican a todas las queries como el �ltimo paso, incluso si el comando dado es INSERT, UPDATE o DELETE. Y tienen diferentes semanticas de las otras en las que modifican el arbol de traducci�n en lugar de crear uno nuevo. Por ello, las reglas SELECT se describen las primeras.

Actualmente, debe haber s�lo una acci�n y debe ser una acci�n SELECT que es una INSTEAD. Esta restricci�n se requer�a para hacer las reglas seguras contra la apertura por usuarios ordinarios, y restringe las reglas ON SELECT a reglas para vistas reales.

El ejemplo para este documento son dos vistas unidas que hacen algunos c�lculos y algunas otras vistas utilizadas para ello. Una de estas dos primeras vistas se personaliza m�s tarde a�adiendo reglas para operaciones de INSERT, UPDATE y DELETE de modo que el resultado final ser� una vista que se comporta como una tabla real con algunas funcionalidades m�gicas. No es un ejemplo f�cil para empezar, y quiz� sea demasiado duro. Pero es mejor tener un ejemplo que cubra todos los puntos discutidos paso a paso que tener muchos ejemplos diferentes que tener que mezclar despu�s.

La base de datos necesitada para ejecutar los ejemplos se llama al_bundy. Ver� pronto el porqu� de este nombre. Y necesita tener instalado el lenguaje procedural PL/pgSQL, ya que necesitaremos una peque�a funci�n min() que devuelva el menor de dos valores enteros. Creamos esta funci�n como:

    CREATE FUNCTION min(integer, integer) RETURNS integer AS
        'BEGIN
            IF $1 < $2 THEN
                RETURN $1;
            END IF;
            RETURN $2;
        END;'
    LANGUAGE 'plpgsql';

Las tablas reales que necesitaremos en las dos primeras descripciones del sistema de reglas son estas:

    CREATE TABLE shoe_data (      -- datos de zapatos
        shoename   char(10),      -- clave primaria (primary key)
        sh_avail   integer,       -- n�mero de pares utilizables
        slcolor    char(10),      -- color de cord�n preferido
        slminlen   float,         -- longitud m�nima de cord�n
        slmaxlen   float,         -- longitud m�xima del cord�n
        slunit     char(8)        -- unidad de longitud
    );

    CREATE TABLE shoelace_data (  -- datos de cordones de zapatos
        sl_name    char(10),      -- clave primaria (primary key)
        sl_avail   integer,       -- n�mero de pares utilizables
        sl_color   char(10),      -- color del cord�n
        sl_len     float,         -- longitud del cord�n
        sl_unit    char(8)        -- unidad de longitud
    );

    CREATE TABLE unit (           -- unidades de longitud
        un_name    char(8),       -- clave primaria (primary key)
        un_fact    float          -- factor de transformaci�n a cm
    );
Pienso que la mayor�a de nosotros lleva zapatos, y puede entender que este es un ejemplo de datos realmente utilizables. Bien es cierto que hay zapatos en el mundo que no necesitan cordones, pero nos har� m�s facil la vida ignorarlos.

Las vistas las crearemos como:

    CREATE VIEW shoe AS
        SELECT sh.shoename,
               sh.sh_avail,
               sh.slcolor,
               sh.slminlen,
               sh.slminlen * un.un_fact AS slminlen_cm,
               sh.slmaxlen,
               sh.slmaxlen * un.un_fact AS slmaxlen_cm,
               sh.slunit
          FROM shoe_data sh, unit un
         WHERE sh.slunit = un.un_name;

    CREATE VIEW shoelace AS
        SELECT s.sl_name,
               s.sl_avail,
               s.sl_color,
               s.sl_len,
               s.sl_unit,
               s.sl_len * u.un_fact AS sl_len_cm
          FROM shoelace_data s, unit u
         WHERE s.sl_unit = u.un_name;

    CREATE VIEW shoe_ready AS
        SELECT rsh.shoename,
               rsh.sh_avail,
               rsl.sl_name,
               rsl.sl_avail,
               min(rsh.sh_avail, rsl.sl_avail) AS total_avail
          FROM shoe rsh, shoelace rsl
         WHERE rsl.sl_color = rsh.slcolor
           AND rsl.sl_len_cm >= rsh.slminlen_cm
           AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
El comando CREATE VIEW para la vista shoelace (que es la m�s simple que tenemos) crear� una relaci�n shoelace y una entrada en pg_rewrite que dice que hay una regla de reescritura que debe ser aplicada siempre que la relaci�n shoelace sea referida en la tabla de rango de una query. La regla no tiene cualificaci�n de regla (discutidas en las reglas no SELECT, puesto que las reglas SELECT no pueden tenerlas) y es de tipo INSTEAD (en vez de). �N�tese que la cualificaci�n de las reglas no son lo mismo que las cualificaci�n de las queries! La acci�n de las reglas tiene una cualificaci�n.

La acci�n de las reglas es un �rbol de query que es una copia exacta de la instrucci�n SELECT en el comando de creaci�n de la vista.

NotaNota:
 

Las dos tablas de rango extra para NEW y OLD (llamadas *NEW* y *CURRENT* por razones hist�ricas en el �rbol de query escrito) que se pueden ver en la entrada pg_rewrite no son de interes para las reglas de SELECT.

Ahora publicamos unit, shoe_data y shoelace_data y Al (el propietario de al_bundy) teclea su primera SELECT en esta vida.
    al_bundy=> INSERT INTO unit VALUES ('cm', 1.0);
    al_bundy=> INSERT INTO unit VALUES ('m', 100.0);
    al_bundy=> INSERT INTO unit VALUES ('inch', 2.54);
    al_bundy=> 
    al_bundy=> INSERT INTO shoe_data VALUES 
    al_bundy->     ('sh1', 2, 'black', 70.0, 90.0, 'cm');
    al_bundy=> INSERT INTO shoe_data VALUES 
    al_bundy->     ('sh2', 0, 'black', 30.0, 40.0, 'inch');
    al_bundy=> INSERT INTO shoe_data VALUES 
    al_bundy->     ('sh3', 4, 'brown', 50.0, 65.0, 'cm');
    al_bundy=> INSERT INTO shoe_data VALUES 
    al_bundy->     ('sh4', 3, 'brown', 40.0, 50.0, 'inch');
    al_bundy=> 
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl1', 5, 'black', 80.0, 'cm');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl2', 6, 'black', 100.0, 'cm');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl3', 0, 'black', 35.0 , 'inch');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl4', 8, 'black', 40.0 , 'inch');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl5', 4, 'brown', 1.0 , 'm');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl6', 0, 'brown', 0.9 , 'm');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl7', 7, 'brown', 60 , 'cm');
    al_bundy=> INSERT INTO shoelace_data VALUES 
    al_bundy->     ('sl8', 1, 'brown', 40 , 'inch');
    al_bundy=> 
    al_bundy=> SELECT * FROM shoelace;
    sl_name   |sl_avail|sl_color  |sl_len|sl_unit |sl_len_cm
    ----------+--------+----------+------+--------+---------
    sl1       |       5|black     |    80|cm      |       80
    sl2       |       6|black     |   100|cm      |      100
    sl7       |       7|brown     |    60|cm      |       60
    sl3       |       0|black     |    35|inch    |     88.9
    sl4       |       8|black     |    40|inch    |    101.6
    sl8       |       1|brown     |    40|inch    |    101.6
    sl5       |       4|brown     |     1|m       |      100
    sl6       |       0|brown     |   0.9|m       |       90
    (8 rows)
Esta es la SELECT m�s sencilla que Al puede hacer en sus vistas, de modo que nosotros la tomaremos para explicar la base de las reglas de las vistas. 'SELECT * FROM shoelace' fue interpretado por el traductor y produjo un �rbol de traducci�n.
    SELECT shoelace.sl_name, shoelace.sl_avail,
           shoelace.sl_color, shoelace.sl_len,
           shoelace.sl_unit, shoelace.sl_len_cm
      FROM shoelace shoelace;
y este se le d� al sistema de reglas. El sistema de reglas viaja a trav�s de la tabla de rango, y comprueba si hay reglas en pg_rewrite para alguna relaci�n. Cuando se procesa las entradas en la tabla de rango para shoelace (el �nico hasta ahora) encuentra la regla '_RETshoelace' con el �rbol de traducci�n
    SELECT s.sl_name, s.sl_avail,
           s.sl_color, s.sl_len, s.sl_unit,
           float8mul(s.sl_len, u.un_fact) AS sl_len_cm
      FROM shoelace *OLD*, shoelace *NEW*,
           shoelace_data s, unit u
     WHERE bpchareq(s.sl_unit, u.un_name);
N�tese que el traductor cambi� el calculo y la cualificaci�n en llamadas a las funciones apropiadas. Pero de hecho esto no cambia nada. El primer paso en la reescritura es mezclar las dos tablas de rango. El �rbol de traducci�n entonces lee
    SELECT shoelace.sl_name, shoelace.sl_avail,
           shoelace.sl_color, shoelace.sl_len,
           shoelace.sl_unit, shoelace.sl_len_cm
      FROM shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, 
	   shoelace_data s,
           unit u;
En el paso 2, a�ade la cualificaci�n de la acci�n de las reglas al �rbol de traducci�n resultante en
    SELECT shoelace.sl_name, shoelace.sl_avail,
           shoelace.sl_color, shoelace.sl_len,
           shoelace.sl_unit, shoelace.sl_len_cm
      FROM shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, shoelace_data s,
           unit u
     WHERE bpchareq(s.sl_unit, u.un_name);
Y en el paso 3, reemplaza todas las variables en el arbol de traducci�n, que se refieren a entradas de la tabla de rango (la �nica que se est� procesando en este momento para shoelace) por las correspondientes expresiones de la lista objetivo correspondiente a la acci�n de las reglas. El resultado es la query final:
    SELECT s.sl_name, s.sl_avail,
           s.sl_color, s.sl_len, 
           s.sl_unit, 
	   float8mul(s.sl_len, u.un_fact) AS sl_len_cm
      FROM shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, shoelace_data s,
           unit u
     WHERE bpchareq(s.sl_unit, u.un_name);
Para realizar esta salida en una instrucci�n SQL real, un usuario humano deber�a teclear:
    SELECT s.sl_name, s.sl_avail,
           s.sl_color, s.sl_len,
           s.sl_unit, s.sl_len * u.un_fact AS sl_len_cm
      FROM shoelace_data s, unit u
     WHERE s.sl_unit = u.un_name;
Esta ha sido la primera regla aplicada. Mientras se iba haciendo esto, la tabla de rango iba creciendo. De modo que el sistema de reglas contin�a comprobando las entradas de la tabla de rango. Lo siguiente es el el n�mero 2 (shoelace *OLD*). La Relaci�n shoelace tiene una regla, pero su entrada en la tabla de rangos no est� referenciada en ninguna de las variables del �rbol de traducci�n, de modo que se ingnora. Puesto que todas las entradas restantes en la tabla de rango, o bien no tienen reglas en pg_rewrite o bien no han sido referenciadas, se alcanza el final de la tabla de rango. La reescritura est� completa y el resultado final dado se pasa al optimizador. El optimizador ignora las entradas extra en la tabla de rango que no est�n referenciadas por variables en el �rbol de traducci�n, y el plan producido por el planificador/optimizador deber�a ser exactamente el mismo que si Al hubiese tecleado la SELECT anterior en lugar de la selecci�n de la vista.

Ahora enfrentamos a Al al problema de que los Blues Brothers aparecen en su tienda y quieren comprarse zapatos nuevos, y como son los Blues Brothers, quieren llevar los mismos zapatos. Y los quieren llevar inmediatamente, de modo que necesitan tambi�n cordones.

Al necesita conocer los zapatos para los que tiene en el almac�n cordones en este momento (en color y en tama�o), y adem�s para los que tenga un n�mero igual o superior a 2. Nosotros le ense�amos a realizar la consulta a su base de datos:

    al_bundy=> SELECT * FROM shoe_ready WHERE total_avail >= 2;
    shoename  |sh_avail|sl_name   |sl_avail|total_avail
    ----------+--------+----------+--------+-----------
    sh1       |       2|sl1       |       5|          2
    sh3       |       4|sl7       |       7|          4
    (2 rows)
Al es un guru de los zapatos, y sabe que s�lo los zapatos de tipo sh1 le sirven (los cordones sl7 son marrones, y los zapatos que necesitan cordones marrones no son los m�s adecuados para los Blues Brothers).

La salida del traductor es esta vez el arbol de traducci�n.

    SELECT shoe_ready.shoename, shoe_ready.sh_avail,
           shoe_ready.sl_name, shoe_ready.sl_avail,
           shoe_ready.total_avail
      FROM shoe_ready shoe_ready
     WHERE int4ge(shoe_ready.total_avail, 2);
Esa ser� la primera regla aplicada para la relaci�n shoe_ready y da como resultado el �rbol de traducci�n
    SELECT rsh.shoename, 
           rsh.sh_avail,
           rsl.sl_name, 
	   rsl.sl_avail,
           min(rsh.sh_avail, rsl.sl_avail) AS 
	           total_avail
      FROM shoe_ready shoe_ready, shoe_ready *OLD*,
           shoe_ready *NEW*, 
	   shoe rsh,
           shoelace rsl
     WHERE int4ge(min(rsh.sh_avail, rsl.sl_avail), 2)
       AND (bpchareq(rsl.sl_color, rsh.slcolor)
            AND float8ge(rsl.sl_len_cm, rsh.slminlen_cm)
            AND float8le(rsl.sl_len_cm, rsh.slmaxlen_cm)
           );
En realidad, la clausula AND en la cualificaci�n ser� un nodo de operadores de tipo AND, con una expresi�n a la izquierda y otra a la derecha. Pero eso la hace menos legible de lo que ya es, y hay m�s reglas para aplicar. De modo que s�lo las mostramos entre par�ntesis para agruparlos en unidades l�gicas en el orden en que se a�aden, y continuamos con las reglas para la relaci�n shoe como est� en la entrada de la tabla de rango a la que se refiere, y tiene una regla. El resultado de aplicarlo es
    SELECT sh.shoename, 
           sh.sh_avail,
           rsl.sl_name, rsl.sl_avail,
           min(sh.sh_avail, rsl.sl_avail) 
	           AS total_avail,
      FROM shoe_ready shoe_ready, shoe_ready *OLD*,
           shoe_ready *NEW*, shoe rsh,
           shoelace rsl, shoe *OLD*,
           shoe *NEW*, 
	   shoe_data sh,
           unit un
     WHERE (int4ge(min(sh.sh_avail, rsl.sl_avail), 2)
            AND (bpchareq(rsl.sl_color, sh.slcolor)
                 AND float8ge(rsl.sl_len_cm, 
                    float8mul(sh.slminlen, un.un_fact))
                 AND float8le(rsl.sl_len_cm, 
                    float8mul(sh.slmaxlen, un.un_fact))
                )
           )
       AND bpchareq(sh.slunit, un.un_name);
Y finalmente aplicamos la regla para shoelace que ya conocemos bien (esta vez en un arbol de traducci�n que es un poco m�s complicado) y obtenemos
    SELECT sh.shoename, sh.sh_avail,
           s.sl_name, s.sl_avail,
           min(sh.sh_avail, s.sl_avail) AS total_avail
      FROM shoe_ready shoe_ready, shoe_ready *OLD*,
           shoe_ready *NEW*, shoe rsh,
           shoelace rsl, shoe *OLD*,
           shoe *NEW*, shoe_data sh,
           unit un, shoelace *OLD*,
           shoelace *NEW*, 
	   shoelace_data s,
           unit u
     WHERE (  (int4ge(min(sh.sh_avail, s.sl_avail), 2)
       AND (bpchareq(s.sl_color, sh.slcolor)
           AND float8ge(float8mul(s.sl_len, u.un_fact), 
                                   float8mul(sh.slminlen, un.un_fact))
           AND float8le(float8mul(s.sl_len, u.un_fact), 
                                   float8mul(sh.slmaxlen, un.un_fact))
                     )
                )
            AND bpchareq(sh.slunit, un.un_name)
           )
       AND bpchareq(s.sl_unit, u.un_name);
Lo reducimos otra vez a una instrucci�n SQL real que sea equivalente en la salida final del sistema de reglas:
    SELECT sh.shoename, sh.sh_avail,
           s.sl_name, s.sl_avail,
           min(sh.sh_avail, s.sl_avail) AS total_avail
      FROM shoe_data sh, shoelace_data s, unit u, unit un
     WHERE min(sh.sh_avail, s.sl_avail) >= 2
       AND s.sl_color = sh.slcolor
       AND s.sl_len * u.un_fact >= sh.slminlen * un.un_fact
       AND s.sl_len * u.un_fact <= sh.slmaxlen * un.un_fact
       AND sh.sl_unit = un.un_name
       AND s.sl_unit = u.un_name;
El procesado recursivo del sistema de reglas reescribi� una SELECT de una vista en un �rbol de traducci�n que es equivalente a exactamente lo que Al hubiese tecleado de no tener vistas.

NotaNota
 

Actualmente no hay mecanismos de parar la recursi�n para las reglas de las vistas en el sistema de reglas (s�lo para las otras reglas). Esto no es muy grave, ya que la �nica forma de meterlo en un bucle sin fin (bloqueando al cliente hasta que lea el limite de memoria) es crear tablas y luego crearles reglas a mano con CREATE RULE de forma que una lea a la otra y la otra a la una. Esto no puede ocurrir con el comando CREATE VIEW, porque en la primera creaci�n de una vista la segunda a�n no existe, de modo que la primera vista no puede seleccionar desde la segunda.

Reglas de vistas en instrucciones diferentes a SELECT

Dos detalles del arbol de traducci�n no se han tocado en la descripci�n de las reglas de vistas hasta ahora. Estos son el tipo de comando (commandtype) y la relaci�n resultado (resultrelation). De hecho, las reglas de vistas no necesitan estas informaciones.

Hay s�lo unas pocas diferencias entre un �rbol de traducci�n para una SELECT y uno para cualquier otro comando. Obviamente, tienen otros tipos de comandos, y esta vez la relaci�n resultado apunta a la entrada de la tabla de rango donde ir� el resultado. Cualquier otra cosa es absolutamente igual. Por ello, teniendo dos tablas t1 y t2, con atributos a y b, los �rboles de traducci�n para las dos instrucciones:

    SELECT t2.b FROM t1, t2 WHERE t1.a = t2.a;

    UPDATE t1 SET b = t2.b WHERE t1.a = t2.a;
son pr�cticamente id�nticos.

La consecuencia es que ambos �rboles de traducci�n dan lugar a planes de ejecuci�n similares. En ambas hay joins entre las dos tablas. Para la UPDATE, las columnas que no aparecen de la tabla t1 son a�adidas a la lista objetivo por el optimizador, y el �rbol de traducci�n final se lee como:
    UPDATE t1 SET a = t1.a, b = t2.b WHERE t1.a = t2.a;
Y por ello el ejecutor al correr sobre la join producir� exactamente el mismo juego de resultados que
    SELECT t1.a, t2.b FROM t1, t2 WHERE t1.a = t2.a;
Pero hay un peque�o problema con el UPDATE. El ejecutor no cuidar� de que el resultado de la join sea coherente. El s�lo produce un juego resultante de filas. La diferencia entre un comando SELECT y un comando UPDATE la manipula el llamador (caller) del ejecutor. El llamador s�lo conoce (mirando en el �rbol de traducci�n) que esto es una UPDATE, y sabe que su resultado deber� ir a la tabla t1. Pero �cu�l de las 666 filas que hay debe ser reemplazada por la nueva fila? El plan ejecutado es una join con una cualificaci�n que potencialmente podr�a producir cualquier n�mero de filas entre 0 y 666 en un n�mero desconocido.

Para resolver este problema, se a�ade otra entrada a la lista objetivo en las instrucciones UPDATE y DELETE. Es el identificador de tupla actual (current tuple id, ctid). Este es un atributo de sistema con caracter�sticas especiales. Contiene el bloque y posici�n en el bloque para cada fila. Conociendo la tabla, el ctid puede utilizarse para encontrar una fila espec�fica en una tabla de 1.5 GB que contiene millones de filas atacando un �nico bloque de datos. Tras la adici�n del ctid a la lista objetivo, el juego de resultados final se podr�a definir como

    SELECT t1.a, t2.b, t1.ctid FROM t1, t2 WHERE t1.a = t2.a;
Entra ahora en funcionamiento otro detalle de >Postgres. Las filas de la tabla no son reescritas en este momento, y el por ello por lo que ABORT TRANSACTION es muy r�pido. En una Update, la nueva fila resultante se inserta en la tabla (tras retirarle el ctid) y en la cabecera de la tupla de la fila cuyo ctid apuntaba a las entradas cmax y zmax, se fija el contador de comando actual y el identificador de transaccion actual (ctid). De este modo, la fila anterior se oculta tras el commit de la transacci�n, y el limpiador vacuum puede realmente eliminarla.

Conociendo todo eso, podemos simplemente aplicar las reglas de las vistas exactamente en la misma forma en cualquier comando. No hay diferencia.

El poder de las vistas en Postgres

Todo lo anterior demuestra como el sistema de reglas incorpora las definiciones de las vistas en el �rbol de traducci�n original. En el segundo ejemplo, una simple SELECT de una vista cre� un �rbol de traducci�n final que es una join de cuatro tablas (cada una se utiliza dos veces con diferente nombre).

Beneficios

Los beneficios de implementar las vistas con el sistema de reglas est�n en que el optimizados tiene toda la informaci�n sobre qu� tablas tienen que ser revisadas, m�s las relaciones entre estas tablas, m�s las cualificaciones restrictivas a partir de la definici�n de las vistas, m�s las cualificaciones de la query original, todo en un �nico �rbol de traducci�n. Y esta es tambi�n la situaci�n cuando la query original es ya una join entre vistas. Ahora el optimizador debe decidir cu�l es la mejor ruta para ejecutar la query. Cuanta m�s informaci�n tenga el optimizador, mejor ser� la decisi�n. Y la forma en que se implementa el sistema de reglas en Postgres asegura que toda la informaci�n sobre la query est� utilizable.

Puntos delicados a considerar

Hubo un tiempo en el que el sistema de reglas de Postgres se consideraba agotado. El uso de reglas no se recomendaba, y el �nico lugar en el que trabajaban era las reglas de las vistas. E incluso estas reglas de las vistas daban problemas porque el sistema de reglas no era capaz de aplicarse adecuadamente en m�s instrucciones que en SELECT (por ejemplo, no trabajar�a en una UPDATE que utilice datos de una vista).

Durante ese tiempo, el desarrollo se dirigi� hacia muchas caracter�sticas a�adidas al traductor y al optimizador. El sistema de reglas fu� quedando cada vez m�s desactualizado en sus capacidades, y se volvi� cada vez m�s dificil de actualizar. Y por ello, nadie lo hizo.

En 6.4, alguien cerr� la puerta, respir� hondo, y se puso manos a la obra. El resultado fu� el sistema de reglas cuyas capacidades se han descrito en este documento. Sin embargo, hay todav�a algunas construcciones no manejadas, y algunas fallan debido a cosas que no son soportadas por el optimizador de queries de Postgres.

  • Las vistas con columnas agregadas tienen malos problemas. Las expresiones agregadas en las cualificaciones deben utilizarse en subselects. Actualmente no es posible hacer una join de dos vistas en las que cada una de ellas tenga una columna agregada, y comparar los dos valores agregados en a cualificaci�n. Mientras tanto, es posible colocar estas expresiones agregadas en funciones con los argumentos apropiados y utilizarlas en la definici�n de las vistas.

  • Las vistas de uniones no son soportadas. Ciertamente es sencillo reescribir una SELECT simple en una uni�n, pero es un poco m�s dificil si la vista es parte de una join que hace una UPDATE.

  • Las clausulas ORDER BY en las definiciones de las vistas no est�n soportadas.

  • DISTINCT no est� soportada en las definiciones de vistas.

No hay una buena razon por la que el optimizador no debiera manipular construcciones de �rboles de traducci�n que el traductor nunca podr�a producir debido a las limitaciones de la sintaxis de SQL. El autor se alegrar� de que estas limitaciones desaparezcan en el futuro.

Efectos colaterales de la implementaci�n

La utilizaci�n del sistema de reglas descrito para implementar las vistas tiene algunos efectos colaterales divertidos. Lo siguiente no parece trabajar:

    al_bundy=> INSERT INTO shoe (shoename, sh_avail, slcolor)
    al_bundy->     VALUES ('sh5', 0, 'black');
    INSERT 20128 1
    al_bundy=> SELECT shoename, sh_avail, slcolor FROM shoe_data;
    shoename  |sh_avail|slcolor   
    ----------+--------+----------
    sh1       |       2|black     
    sh3       |       4|brown     
    sh2       |       0|black     
    sh4       |       3|brown     
    (4 rows)
Lo interesante es que el c�digo de retorno para la INSERT nos di� una identificaci�n de objeto, y nos dijo que se ha insertado una fila. Sin embargo no aparece en shoe_data. Mirando en el directorio de la base de datos, podemos ver que el fichero de la base de datos para la relaci�n de la vista shoe parece tener ahora un bloque de datos. Y efectivamente es as�.

Podemos tambi�n intentar una DELETE, y si no tiene una cualificaci�n, nos dir� que las filas se han borrado y la siguiente ejecuci�n de vacuum limpiar� el fichero hasta tama�o cero.

La razon para este comportamiento es que el �rbol de la traducci�n para la INSERT no hace referencia a la relaci�n shoe en ninguna variable. La lista objetivo contiene s�lo valores constantes. Por ello no hay reglas que aplicar y se mantiene sin cambiar hasta la ejecuci�n, insertandose la fila. Del mismo modo para la DELETE.

Para cambiar esto, podemos definir reglas que modifiquen el comportamiento de las queries no-SELECT. Este es el tema de la siguiente secci�n.