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:
Este é um valor simples, dizendo qual comando
(SELECT, INSERT,
UPDATE, DELETE)
produziu a árvore de consulta.
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.
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 é 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 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 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.
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.