


Amplía un compilador SQL multidialecto sin cambiar lo que significan las consultas
Úsalo al cambiar un compilador SQL que convierte SQL en un AST y lo genera para otras bases de datos. Busca primero la capa responsable, mantiene el significado entre dialectos, arma el SQL con funciones auxiliares del AST en vez de cadenas y prueba la ejecución real y la velocidad.
Para usar estas reglas de IA
## Encuentra la capa del compilador responsable del comportamiento antes de editar
Trata el sistema como un compilador cuyas capas tienen responsabilidades distintas:
- el tokenizador convierte texto SQL en tokens tipados y permite que los dialectos sobrescriban las correspondencias léxicas;
- el analizador sintáctico usa descenso recursivo para construir un árbol de sintaxis abstracta (AST), con funciones auxiliares específicas para coincidencias, cursores, listas y envoltorios;
- las clases de expresiones representan conceptos semánticos de SQL y permiten su recorrido y transformación;
- el generador convierte recursivamente las expresiones de nuevo en SQL mediante correspondencias de transformación sencillas o métodos de generación específicos;
- los módulos de dialectos amplían una base común mediante indicadores de funciones, conjuntos de tokens y correspondencias de análisis y generación;
- las reglas de optimización normalizan y reescriben el AST en un orden deliberado;
- la información de esquema y de tipos sustenta la optimización, la transpilación y el linaje;
- el linaje conecta las columnas de salida con las expresiones y tablas de origen.
Identifica la capa responsable antes de cambiar un comportamiento. Mantén separadas la tokenización, el análisis sintáctico, la representación semántica, la optimización y la generación, en vez de reparar una capa filtrando lógica hacia otra.
Conserva la simetría entre el analizador sintáctico y el generador: el análisis asigna tokens a expresiones, mientras que la generación asigna expresiones a SQL. Si el analizador recurre deliberadamente a un nodo de comando genérico para texto no reconocido, no conviertas silenciosamente ese mecanismo de conservación en un análisis parcial.
## Usa los comandos de prueba y verificación del repositorio para la versión pura y la nativa
Lee las guías de contribución y arquitectura del repositorio antes de editar. Usa sus objetivos documentados para la instalación básica, la instalación de desarrollo, la instalación opcional de extensiones nativas, la configuración previa a las confirmaciones, las pruebas completas, las pruebas unitarias, las comprobaciones de estilo y tipos, y los análisis comparativos de rendimiento.
Distingue la implementación pura de cualquier extensión compilada opcional. Ejecuta primero el modo directamente pertinente y luego las comprobaciones más amplias que exija el cambio. Cuando se vea afectada la aceleración nativa, prueba tanto la implementación pura como la ruta compilada en lugar de suponer que se comportan de forma idéntica.
Durante la iteración, localiza los fallos con precisión ejecutando un archivo, una clase o un método de prueba concretos. Antes de enviar el cambio, ejecuta el objetivo completo de comprobación exigido por el repositorio, incluidos el formateo, las comprobaciones estáticas, las pruebas del entorno de ejecución puro y, cuando corresponda, las pruebas de la extensión nativa.
Para trabajos sensibles al rendimiento, usa análisis comparativos del análisis sintáctico y la optimización. Compara configuraciones equivalentes y no sacrifiques la corrección semántica para obtener un microanálisis favorable.
## Mantén el mismo significado al pasar SQL a otro dialecto
Trata el AST como la fuente de referencia semántica. Analiza el SQL de origen para convertirlo en expresiones semánticas y genera el dialecto de destino a partir de ellas; conserva el significado, no la escritura original. Los comentarios pueden conservarse en la medida de lo posible, pero la equivalencia semántica tiene prioridad.
Añade a la base común las funciones compartidas por varios dialectos cuando su semántica coincida realmente. Añade sintaxis o comportamientos específicos de un dialecto únicamente al dialecto correspondiente. Usa indicadores de funciones explícitos, conjuntos de tokens reservados y correspondencias de funciones, instrucciones y expresiones a SQL, en lugar de dispersar comprobaciones de nombres.
Mantén las reglas del optimizador en su secuencia deliberada. La cualificación, la anotación de tipos, el descenso de predicados o proyecciones y la simplificación pueden depender de pasos anteriores y de información de esquema. Trata el optimizador como un sistema de reescritura lógica, no como un planificador físico de consultas.
Cuando una función dependa de la estructura de la base de datos, proporciona explícitamente la información de esquema. No afirmes que la cualificación, la inferencia de tipos, la optimización o el linaje de columnas son fiables cuando falten los metadatos necesarios de tablas y columnas.
## Arma el SQL con funciones auxiliares del AST y plantillas, no pegando cadenas
Antes de crear una expresión de función genérica, busca en el catálogo de expresiones una clase específica existente. Usa una expresión anónima genérica solo cuando no exista una clase semántica específica.
Da preferencia al mecanismo de generación admitido más sencillo:
1. Para un único tipo de expresión compleja, implementa el método del generador `<lowercase_expression_name>_sql`, que se detecta automáticamente.
2. Reserva las correspondencias de transformación para cambios de nombre sencillos de una sola línea, funciones lambda o funciones que tengan intencionadamente varios puntos de entrada.
3. Dentro de los métodos del generador, usa su función auxiliar para funciones en lugar de construir un nodo de función solo para serializarlo.
4. Usa constructores de expresiones y operadores para matrices, expresiones booleanas, casos, conversiones de tipo, columnas, valores nulos, aritmética, indexación y comparaciones.
5. Para resultados complejos, analiza una plantilla SQL y sustituye los marcadores de posición en una copia del AST.
No montes fragmentos SQL mediante interpolación de cadenas. Los constructores y las plantillas de AST conservan las comillas, el escape, el anidamiento y el comportamiento de los dialectos que las cadenas construidas manualmente suelen romper.
## Comprueba los tipos tras la anotación de tipos y trata NULL en tiempo de ejecución
Distingue las comprobaciones de tipos sintácticas de las semánticas. Usa un predicado de literal como `is_string` solo para comprobar si un nodo es literalmente una cadena y extraer su valor literal. Usa `is_type()` para comprobar el tipo semántico inferido de una columna, el resultado de una función u otra expresión.
Si el comportamiento semántico depende de los tipos, ejecuta la anotación de tipos antes de llamar a `is_type()`. Las pruebas de transpilación dependientes de tipos deben anotar el AST; de lo contrario, una comprobación semántica correcta puede parecer fallida porque el tipo nunca se rellenó.
Usa el método de conversión de la expresión, como `to_py()`, para extraer el valor de un literal numérico después de verificar que el nodo lo es. No elimines manualmente las comillas del texto interno sin procesar para convertir su tipo.
No resuelvas el comportamiento de `NULL` en SQL durante la transpilación comprobando únicamente si existe un nodo nulo literal. Genera SQL con lógica `IS NULL` en tiempo de ejecución para que las columnas, los parámetros, las expresiones y los nulos literales sigan la misma semántica.
Al buscar ancestros, incluye los límites del ámbito de la consulta para que la búsqueda no escape hacia una consulta superior. Usa el mecanismo del framework para declarar argumentos no admitidos cuando un dialecto de destino no pueda representar argumentos concretos.
## Prueba cada dialecto y ejecuta las pruebas en bases de datos reales
Añade pruebas a la batería responsable del dialecto o la capa del compilador afectados. Usa aserciones de ida y vuelta para la sintaxis que deba permanecer idéntica y aserciones entre dialectos cuando una expresión semántica deba generar SQL de destino diferente.
No dupliques una cobertura que ya demuestre el mismo comportamiento. Añade casos específicos para la nueva distinción semántica, como nulabilidad, tipos, comillas, ámbito, argumentos no admitidos o diferencias entre dialectos cuando sean pertinentes.
Asegúrate de que las pruebas situadas en baterías específicas de una base de datos se ejecuten realmente contra las bases de datos correspondientes o motores compatibles. Una cadena generada por sí sola no es una prueba cuando la regla depende del comportamiento en tiempo de ejecución.
Para resultados sensibles a los tipos, prueba tanto literales como expresiones tipadas que no sean literales. Para la aceleración nativa, confirma la paridad con la implementación pura. Para cambios del optimizador, incluye casos que tengan en cuenta el esquema y verifica que el orden de las reglas no altere el significado.
## Limita cada cambio a un solo propósito y hazlo fácil de revisar
Limita cada cambio a un propósito bien definido. Añade pruebas para comportamientos no triviales, actualiza las cadenas de documentación públicas cuando cambien las API, sigue las convenciones del repositorio para solicitudes de incorporación y confirmaciones, y ejecuta todas las comprobaciones exigidas antes del envío.
Elimina importaciones y variables sin usar, además del código muerto. Evita añadir adaptadores de compatibilidad para código eliminado deliberadamente. Prefiere una expresión en línea legible a una variable temporal innecesaria, pero no comprimas la lógica hasta volver confusas sus fases semánticas.
Usa comentarios solo para lógica que no resulte evidente y añade cadenas de documentación únicamente para comportamientos complejos o API públicas. No modifiques archivos de licencia ni su configuración salvo que la tarea trate explícitamente sobre licencias.
Revisa el cambio en busca de acoplamientos accidentales entre dialectos, tipos de expresión duplicados, SQL construido manualmente, anotaciones de tipos ausentes, tratamiento de nulos limitado al tiempo de compilación, fugas de ámbito y comportamientos nativos o específicos de bases de datos sin probar.
## Conserva la aceleración nativa y el diseño del analizador al optimizar
Trata el rendimiento como una función del producto aunque la implementación principal use un lenguaje de alto nivel. Conserva las rutas opcionales de aceleración nativa y somete a análisis comparativos los cambios que afecten a la tokenización, el análisis sintáctico, la generación o la optimización.
No sustituyas un analizador sintáctico de descenso recursivo adoptado deliberadamente por un análisis Pratt como supuesta optimización. La estrategia de análisis es una decisión arquitectónica, no un ajuste de velocidad intercambiable.
Evita las abstracciones que se sepa que interfieren con la ruta compilada cuando el código documente una alternativa preferida, como elegir tipos de unión sencillos y tipado pato estructural en lugar de una abstracción de protocolo no admitida.
Optimiza solo después de conservar la corrección del análisis sintáctico, la construcción del AST, la generación, el comportamiento de los dialectos y las pruebas. Una implementación más rápida que cambie la semántica, pierda las comillas, gestione mal `NULL` o diverja entre los modos puro y compilado constituye una regresión.
