


Amplie um compilador SQL com vários dialetos sem mudar o significado das consultas
Use ao alterar um compilador SQL que transforma SQL em uma AST e o gera para outros bancos de dados. Ele acha primeiro a camada responsável, mantém o significado entre dialetos, monta o SQL com auxiliares da AST em vez de strings e testa a execução real e a velocidade.
Para usar estas regras de IA
## Encontre a camada do compilador responsável pelo comportamento antes de editar
Trate o sistema como um compilador cujas camadas têm responsabilidades distintas:
- o tokenizador converte o texto SQL em tokens tipados e permite que os dialetos substituam os mapeamentos lexicais;
- o analisador sintático usa análise descendente recursiva para construir uma árvore sintática abstrata (AST), com funções auxiliares específicas de correspondência, cursor, lista e envoltório;
- as classes de expressões representam conceitos semânticos de SQL e permitem percurso e transformação;
- o gerador converte recursivamente as expressões de volta em SQL, usando mapeamentos de transformação simples ou métodos de geração específicos;
- os módulos de dialeto ampliam uma base comum com sinalizadores de funcionalidades, conjuntos de tokens, mapeamentos de análise e mapeamentos de geração;
- as regras de otimização padronizam e reescrevem a AST em uma ordem deliberada;
- as informações de esquema e de tipos sustentam a otimização, a transpilação e a linhagem;
- a linhagem conecta as colunas de saída às expressões e tabelas anteriores.
Identifique a camada responsável antes de alterar um comportamento. Mantenha separadas a tokenização, a análise sintática, a representação semântica, a otimização e a geração, em vez de corrigir uma camada vazando lógica para outra.
Preserve a simetria entre analisador e gerador: a análise mapeia tokens para expressões, enquanto a geração mapeia expressões para SQL. Se o analisador recorrer intencionalmente a um nó de comando genérico para texto não reconhecido, não transforme silenciosamente esse mecanismo de preservação em uma análise parcial.
## Use os comandos de teste e verificação do repositório para a versão pura e a nativa
Leia as orientações de contribuição e arquitetura do repositório antes de editar. Use os alvos documentados para instalação básica, instalação de desenvolvimento, instalação opcional da extensão nativa, configuração pré-commit, testes completos, testes unitários, verificações de estilo e de tipos e avaliações comparativas.
Distinga a implementação pura de qualquer extensão compilada opcional. Execute primeiro o modo diretamente relevante e depois as verificações mais amplas exigidas pela alteração. Quando a aceleração nativa for afetada, teste tanto a implementação pura quanto o caminho compilado, em vez de presumir que se comportam de forma idêntica.
Durante a iteração, localize as falhas com precisão executando um arquivo, uma classe ou um método de teste específico. Antes do envio, execute o alvo completo de verificação exigido pelo repositório, incluindo formatação, verificações estáticas, testes da execução pura e, quando aplicável, testes da extensão nativa.
Use avaliações comparativas de análise sintática e otimização em trabalhos sensíveis ao desempenho. Compare configurações equivalentes e não troque a correção semântica por um microteste de desempenho favorável.
## Mantenha o mesmo significado ao passar o SQL para outro dialeto
Trate a AST como a fonte normativa da semântica. Analise o SQL de origem para obter expressões semânticas e gere o dialeto de destino a partir delas; preserve o significado, e não a grafia original. Os comentários podem ser preservados na medida do possível, mas a equivalência semântica tem prioridade.
Adicione à base comum as funcionalidades compartilhadas por vários dialetos quando suas semânticas realmente coincidirem. Adicione sintaxe ou comportamento específico de um dialeto somente ao dialeto relevante. Use sinalizadores explícitos de funcionalidades, conjuntos de tokens reservados e mapeamentos de funções, instruções e expressões para SQL, em vez de espalhar verificações de nomes.
Mantenha as regras do otimizador em sua sequência deliberada. A qualificação, a anotação de tipos, o rebaixamento de predicados ou projeções e a simplificação podem depender de etapas anteriores e de informações de esquema. Trate o otimizador como um mecanismo de reescrita lógica, e não como um planejador físico de consultas.
Quando uma funcionalidade depender da estrutura do banco de dados, forneça explicitamente as informações de esquema. Não afirme que a qualificação, a inferência de tipos, a otimização ou a linhagem de colunas são confiáveis quando faltarem os metadados necessários de tabelas e colunas.
## Monte o SQL com auxiliares da AST e modelos, não colando strings
Antes de criar uma expressão de função genérica, procure no catálogo de expressões uma classe específica já existente. Use uma expressão anônima genérica somente quando não houver uma classe semântica específica.
Prefira o mecanismo de geração compatível mais simples:
1. Para um único tipo de expressão complexa, implemente o método de gerador `<lowercase_expression_name>_sql`, descoberto automaticamente.
2. Reserve os mapeamentos de transformação para renomeações simples de uma linha, funções lambda ou funções que tenham intencionalmente vários pontos de entrada.
3. Dentro dos métodos de gerador, use a função auxiliar do gerador para funções, em vez de construir um nó de função apenas para serializá-lo.
4. Use construtores de expressões e operadores para arrays, expressões booleanas, casos, conversões de tipo, colunas, valores nulos, aritmética, indexação e comparações.
5. Para resultados complexos, analise um modelo SQL e substitua os espaços reservados em uma cópia da AST.
Não monte fragmentos SQL com interpolação de strings. Os construtores e modelos de AST preservam aspas, caracteres de escape, aninhamento e comportamentos de dialetos que strings construídas manualmente costumam quebrar.
## Verifique os tipos depois da anotação de tipo e trate NULL em tempo de execução
Distinga verificações sintáticas de tipos das verificações semânticas. Use um predicado de literal como `is_string` somente para verificar se um nó é literalmente uma string e extrair seu valor literal. Use `is_type()` para verificar o tipo semântico inferido de uma coluna, do resultado de uma função ou de outra expressão.
Se o comportamento semântico depender de tipos, execute a anotação de tipos antes de chamar `is_type()`. Os testes de transpilação dependentes de tipos devem anotar a AST; caso contrário, uma verificação semântica correta pode parecer falhar porque o tipo nunca foi preenchido.
Use o método de conversão da expressão, como `to_py()`, para extrair o valor de um literal numérico depois de verificar que o nó é um literal numérico. Não remova manualmente as aspas do texto interno bruto para converter seu tipo.
Não resolva o comportamento de `NULL` em SQL durante a transpilação verificando apenas a existência de um nó nulo literal. Gere SQL com lógica `IS NULL` durante a execução para que colunas, parâmetros, expressões e nulos literais sigam a mesma semântica.
Ao procurar ancestrais, inclua os limites do escopo da consulta para impedir que a busca escape para uma consulta superior. Use o mecanismo do framework para declarar argumentos não compatíveis quando um dialeto de destino não puder representar argumentos específicos.
## Teste cada dialeto e rode os testes em bancos de dados reais
Adicione testes ao conjunto responsável pelo dialeto ou pela camada do compilador afetados. Use asserções de ida e volta para a sintaxe que deve permanecer idêntica e asserções entre dialetos quando uma expressão semântica precisar gerar SQL de destino diferente.
Não duplique uma cobertura que já comprove o mesmo comportamento. Adicione casos específicos para a nova distinção semântica, incluindo nulabilidade, tipos, aspas, escopo, argumentos não compatíveis ou diferenças entre dialetos, quando relevantes.
Garanta que os testes colocados em conjuntos específicos de banco de dados sejam realmente executados nos bancos correspondentes ou em mecanismos compatíveis. Uma string gerada sozinha não é evidência quando a regra depende do comportamento durante a execução.
Para resultados sensíveis a tipos, teste tanto literais quanto expressões tipadas não literais. Para aceleração nativa, confirme a equivalência com a implementação pura. Para alterações no otimizador, inclua casos que considerem o esquema e verifique que a ordem das regras não altera o significado.
## Limite cada mudança a um só objetivo e deixe-a fácil de revisar
Limite cada alteração a um objetivo bem definido. Adicione testes para comportamentos não triviais, atualize as docstrings públicas quando as APIs mudarem, siga as convenções do repositório para solicitações de integração e commits e execute todas as verificações exigidas antes do envio.
Remova importações e variáveis não usadas e código morto. Evite adaptações de compatibilidade para código removido intencionalmente. Prefira uma expressão incorporada legível a uma variável temporária desnecessária, mas não compacte a lógica até tornar obscuras suas fases semânticas.
Use comentários somente para lógica que não seja evidente e adicione docstrings apenas para comportamentos complexos ou APIs públicas. Não altere arquivos de licença nem configurações de licenciamento, a menos que a tarefa trate explicitamente de licenciamento.
Revise a alteração em busca de acoplamento acidental entre dialetos, tipos de expressão duplicados, SQL construído manualmente, ausência de anotação de tipos, tratamento de nulos limitado ao tempo de compilação, vazamento de escopo e comportamentos nativos ou específicos de bancos de dados sem testes.
## Preserve a aceleração nativa e o desenho do analisador ao otimizar
Trate o desempenho como uma funcionalidade do produto, mesmo quando a implementação principal usar uma linguagem de alto nível. Preserve os caminhos opcionais de aceleração nativa e submeta a avaliações comparativas as alterações que afetarem tokenização, análise sintática, geração ou otimização.
Não substitua um analisador descendente recursivo adotado intencionalmente por análise Pratt como uma suposta otimização. A estratégia de análise é uma decisão arquitetônica, e não uma configuração de velocidade intercambiável.
Evite abstrações que sabidamente interfiram no caminho compilado quando a base de código documentar uma alternativa preferencial, como escolher tipos de união simples e tipagem estrutural por comportamento em vez de uma abstração de protocolo não compatível.
Otimize somente depois de preservar a correção na análise sintática, na construção da AST, na geração, no comportamento dos dialetos e nos testes. Uma implementação mais rápida que altere a semântica, perca o tratamento de aspas, trate `NULL` incorretamente ou divirja entre os modos puro e compilado é uma regressão.
