39.1. El árbol de consulta #

Para entender cómo funciona el sistema de reglas es necesario saber cuándo se invoca y cuáles son sus entradas y resultados.

El sistema de reglas se ubica entre el analizador (parser) y el planificador. Toma la salida del analizador (parser), un árbol de consulta, y las reglas de reescritura definidas por el usuario, que también son árboles de consulta con alguna información adicional, y genera cero o más árboles de consulta como resultado. Por lo tanto, su entrada y salida son siempre cosas que el propio analizador (parser) podría haber producido y, por ende, cualquier cosa que vea es básicamente representable como una sentencia SQL.

Ahora bien, ¿qué es un árbol de consulta? Es una representación interna de una sentencia SQL donde se almacenan por separado las partes individuales que la componen. Estos árboles de consulta se pueden mostrar en el registro del servidor si estableces los parámetros de configuración debug_print_parse, debug_print_rewritten o debug_print_plan. Las acciones de las reglas también se almacenan como árboles de consulta en el catálogo del sistema pg_rewrite. No tienen el mismo formato que la salida del registro, pero contienen exactamente la misma información.

Leer un árbol de consulta sin procesar requiere cierta experiencia. Pero dado que las representaciones SQL de los árboles de consulta son suficientes para entender el sistema de reglas, este capítulo no te enseñará cómo leerlos.

Al leer las representaciones SQL de los árboles de consulta en este capítulo, es necesario poder identificar las partes en las que se divide la sentencia cuando se encuentra en la estructura del árbol de consulta. Las partes de un árbol de consulta son:

el tipo de comando

Este es un valor simple que indica qué comando (SELECT, INSERT, UPDATE, DELETE) produjo el árbol de consulta.

la tabla de rangos

La tabla de rangos es una lista de relaciones que se utilizan en la consulta. En una sentencia SELECT, estas son las relaciones especificadas después de la palabra clave FROM.

Cada entrada de la tabla de rangos identifica una tabla o vista e indica con qué nombre se la llama en las otras partes de la consulta. En el árbol de consulta, las entradas de la tabla de rangos se referencian por número en lugar de por nombre, por lo que aquí no importa si hay nombres duplicados como ocurriría en una sentencia SQL. Esto puede suceder después de haber fusionado las tablas de rangos de las reglas. Los ejemplos de este capítulo no presentarán esta situación.

la relación de resultado

Este es un índice en la tabla de rangos que identifica la relación a donde van los resultados de la consulta.

Las consultas SELECT no tienen una relación de resultado. (El caso especial de SELECT INTO es casi idéntico a CREATE TABLE seguido de INSERT ... SELECT, y no se analiza por separado aquí).

Para los comandos INSERT, UPDATE y DELETE, la relación de resultado es la tabla (¡o vista!) donde surtirán efecto los cambios.

la lista de objetivos

La lista de objetivos es una lista de expresiones que definen el resultado de la consulta. En el caso de un SELECT, estas expresiones son las que construyen la salida final de la consulta. Corresponden a las expresiones entre las palabras clave SELECT y FROM. (* es solo una abreviatura para todos los nombres de columna de una relación. El analizador (parser) la expande en las columnas individuales, por lo que el sistema de reglas nunca la ve).

Los comandos DELETE no necesitan una lista de objetivos normal porque no producen ningún resultado. En su lugar, el planificador añade una entrada CTID especial a la lista de objetivos vacía, para permitir que el ejecutor encuentre la fila a eliminar. (CTID se añade cuando la relación de resultado es una tabla ordinaria. Si es una vista, en su lugar se añade una variable de fila completa por el sistema de reglas, como se describe en Section 39.2.4).

Para los comandos INSERT, la lista de objetivos describe las nuevas filas que deben ir en la relación de resultado. Consiste en las expresiones de la cláusula VALUES o las de la cláusula SELECT en INSERT ... SELECT. El primer paso del proceso de reescritura añade entradas a la lista de objetivos para cualquier columna que no haya sido asignada por el comando original pero que tenga valores predeterminados (defaults). Cualquier columna restante (sin valor dado ni valor predeterminado) será rellenada por el planificador con una expresión constante nula.

Para los comandos UPDATE, la lista de objetivos describe las nuevas filas que deben reemplazar a las antiguas. En el sistema de reglas, contiene simplemente las expresiones de la parte SET columna = expresión del comando. El planificador manejará las columnas faltantes insertando expresiones que copian los valores de la fila antigua en la nueva. Al igual que para DELETE, se añade un CTID o una variable de fila completa para que el ejecutor pueda identificar la fila antigua que se va a actualizar.

Cada entrada en la lista de objetivos contiene una expresión que puede ser un valor constante, una variable que apunta a una columna de una de las relaciones en la tabla de rangos, un parámetro o un árbol de expresiones compuesto por llamadas a funciones, constantes, variables, operadores, etc.

la condición

La condición (qualification) de la consulta es una expresión muy parecida a una de las contenidas en las entradas de la lista de objetivos. El valor del resultado de esta expresión es un booleano que indica si la operación (INSERT, UPDATE, DELETE o SELECT) para la fila del resultado final se debe ejecutar o no. Corresponde a la cláusula WHERE de una sentencia SQL.

el árbol de unión

El árbol de unión (join tree) de la consulta muestra la estructura de la cláusula FROM. Para una consulta simple como SELECT ... FROM a, b, c, el árbol de unión es solo una lista de los elementos de FROM, porque se nos permite unirlos en cualquier orden. Pero cuando se utilizan expresiones JOIN, particularmente uniones externas (outer joins), tenemos que unir en el orden indicado por las uniones. En ese caso, el árbol de unión muestra la estructura de las expresiones JOIN. Las restricciones asociadas con cláusulas JOIN particulares (de expresiones ON o USING expresiones) se almacenan como expresiones de condición adjuntas a esos nodos del árbol de unión. También resulta conveniente almacenar la expresión WHERE de nivel superior como una condición adjunta al elementos del árbol de unión de nivel superior. Así que, en realidad, el árbol de unión representa tanto la cláusula FROM como la WHERE de un SELECT.

los otros

Las otras partes del árbol de consulta, como la cláusula ORDER BY, no son de interés aquí. El sistema de reglas sustituye algunas entradas allí al aplicar las reglas, pero eso no tiene mucho que ver con los fundamentos del sistema de reglas.