39.1. A árvore de consulta #

Para entender como o sistema de regras funciona, é necessário saber quando é chamado, e quais são suas entradas e resultados.

O sistema de regras fica localizado entre o analisador e o planejador. Ele pega a saída do analisador, uma árvore de consulta, e as regras de reescrita definidas pelo usuário, que também são árvores de consulta com algumas informações extras, e cria zero ou mais árvores de consulta como resultado. Portanto, sua entrada e saída são sempre coisas que o próprio analisador poderia ter produzido, assim, qualquer coisa que ele vê é basicamente representável como uma instrução SQL.

Agora, o que é uma árvore de consulta? É uma representação interna de uma instrução SQL, onde as partes únicas de que é composto são armazenadas separadamente. Estas árvores de consulta podem ser mostradas no registro de transações (log) do servidor, se forem definidos os parâmetros de configuração debug_print_parse, debug_print_rewritten, ou debug_print_plan. As ações da regra também são armazenadas como árvores de consulta, no catálogo do sistema pg_rewrite. Elas não são formatadas como a saída de registro de transações, mas contêm exatamente as mesmas informações.

A leitura de uma árvore de consulta bruta requer alguma experiência. Mas como as representações SQL das árvores de consulta são suficientes para entender o sistema de regras, este capítulo não ensinará como lê-las.

Ao ler as representações SQL das árvores de consulta neste capítulo, é necessário ser capaz de identificar as partes em que a instrução é dividida quando está na estrutura da árvore de consulta. As partes de uma árvore de consulta são:

o tipo de comando

Este é um valor simples, dizendo qual comando (SELECT, INSERT, UPDATE, DELETE) produziu a árvore de consulta.

a tabela de intervalos

A tabela de intervalos é a lista das relações usadas na consulta. Em uma instrução SELECT, são as relações fornecidas após a palavra-chave FROM.

Cada entrada da tabela de intervalos identifica uma tabela ou visão, e informa por qual nome ela é chamada nas outras partes da consulta. Na árvore de consulta, as entradas da tabela de intervalos são referenciadas por número, e não por nome, portanto, aqui não importa se há nomes duplicados, como seria o caso em uma instrução SQL. Isto pode acontecer depois que as tabelas de intervalos de regras forem mescladas. Os exemplos neste capítulo não contemplam esta situação.

a relação de resultado

Este é um índice na tabela de intervalos que identifica a relação para onde vão os resultados da consulta.

As consultas SELECT não possuem uma relação de resultado. (O caso especial de SELECT INTO é quase idêntico a CREATE TABLE seguido por INSERT ... SELECT, não sendo discutido separadamente aqui.)

Para os comandos INSERT, UPDATE, e DELETE, a relação de resultado é a tabela (ou visão!) onde as alterações devem produzir efeito.

a lista de destinos

A lista de destinos é uma lista de expressões que definem o resultado da consulta. No caso do SELECT, estas expressões são as que constroem a saída final da consulta. Correspondem às expressões entre as palavras-chave SELECT e FROM. (O * é apenas uma forma abreviada para todos os nomes de colunas de uma relação, sendo expandido pelo analisador em colunas individuais, portanto, o sistema de regras nunca o vê.)

Os comandos DELETE não precisam de uma lista de destinos normal, porque não produzem nenhum resultado. Em vez disso, o planejador adiciona a entrada especial CTID à lista de destinos vazia, para permitir que o executor localize a linha a ser excluída. (O CTID é adicionado quando a relação de resultados é uma tabela comum. Se for uma visão, uma variável de linha inteira é adicionada pelo sistema de regras, conforme descrito em Atualização de visão.)

Para os comandos INSERT, a lista de destinos descreve as novas linhas que devem entrar na relação de resultado. Consiste nas expressões na cláusula VALUES, ou os da cláusula SELECT em INSERT ... SELECT. A primeira etapa do processo de reescrita adiciona entradas na lista de destinos para quaisquer colunas que não foram atribuídas pelo comando original, mas possuem valores padrão. Quaisquer colunas restantes (sem um valor determinado ou padrão) serão preenchidas pelo planejador com uma expressão NULL constante.

Para os comandos UPDATE, a lista de destinos descreve as novas linhas que devem substituir as antigas. No sistema de regras, contém apenas as expressões da parte SET coluna = expressão do comando. O planejador trata as colunas ausentes inserindo expressões que copiam os valores da linha antiga para a nova. Assim como para o DELETE, é adicionado o CTID, ou variável de linha inteira, para que o executor possa identificar a linha antiga a ser atualizada.

Cada entrada na lista de destinos contém uma expressão que pode ser um valor constante, uma variável apontando para uma coluna de uma das relações na tabela de intervalos, um parâmetro, ou uma árvore de expressão feita de chamadas de função, constantes, variáveis, operadores, etc.

a qualificação

A qualificação da consulta é uma expressão muito parecida com uma das contidas nas entradas da lista de destinos. O resultado dessa expressão é um valor booleano que informa se a operação (INSERT, UPDATE, DELETE, ou SELECT) para a linha de resultado final deve ser executada ou não. Corresponde à cláusula WHERE de uma instrução SQL.

a árvore de junção

A árvore de junção da consulta mostra a estrutura da cláusula FROM. Para uma consulta simples, como SELECT ... FROM a, b, c, a árvore de junção é apenas a lista dos itens FROM, porque pode-se juntá-los em qualquer ordem. Mas quando são usadas expressões JOIN, particularmente junções externas, é necessário juntar na ordem mostrada pelas junções. Neste caso, a árvore de junção mostra a estrutura das expressões JOIN. As restrições associadas a cláusulas JOIN específicas (das expressões ON ou USING) são armazenadas como expressões de qualificação anexadas a estes nós da árvore de junção. Também é conveniente armazenar a expressão WHERE de nível superior como uma qualificação anexada ao item da árvore de junção de nível superior. Então, na verdade, a árvore de junção representa as cláusulas FROM e WHERE da instrução SELECT.

o restante

As outras partes da árvore de consulta, como a cláusula ORDER BY, não são de interesse aqui. O sistema de regras substitui algumas entradas ao aplicar as regras, mas isto não tem muito a ver com os fundamentos do sistema de regras.