La etapa del analizador (parser stage) consta de dos partes:
El analizador (parser) definido en
gram.y y scan.l se
construye utilizando las herramientas de Unix bison
y flex.
El proceso de transformación realiza modificaciones y ampliaciones a las estructuras de datos devueltas por el analizador.
El analizador tiene que comprobar que la sintaxis de la cadena de consulta (que llega como texto plano) sea válida. Si la sintaxis es correcta, se construye un árbol de análisis (parse tree) y se devuelve; de lo contrario, se devuelve un error. El analizador y el analizador léxico (lexer) se implementan utilizando las conocidas herramientas de Unix bison y flex.
El analizador léxico (lexer) está definido en el archivo
scan.l y es responsable
de reconocer identificadores,
las palabras clave de SQL, etc. Por cada
palabra clave o identificador que se encuentra, se genera un token
y se entrega al analizador.
El analizador está definido en el archivo gram.y y
consta de un conjunto de reglas gramaticales y
acciones que se ejecutan cada vez que se
activa una regla. El código de las acciones (que en realidad es
código C) se utiliza para construir el árbol de análisis.
El archivo scan.l se transforma en el archivo
fuente C scan.c utilizando el programa
flex y gram.y se
transforma en gram.c utilizando
bison. Después de que estas transformaciones
hayan tenido lugar, se puede utilizar un compilador de C normal para crear el
analizador. Nunca realices cambios en los archivos C generados, ya que se
sobrescribirán la próxima vez que se llame a flex
o bison.
Las transformaciones y compilaciones mencionadas se realizan normalmente de forma automática utilizando los archivos makefile incluidos con la distribución de código fuente de PostgreSQL.
Una descripción detallada de bison o de las
reglas gramaticales dadas en gram.y estaría
fuera del alcance de este manual. Hay muchos libros y
documentos que tratan sobre flex y
bison. Deberías estar familiarizado con
bison antes de comenzar a estudiar la
gramática dada en gram.y, de lo contrario no
entenderás lo que sucede allí.
La etapa del analizador crea un árbol de análisis utilizando únicamente reglas fijas sobre la estructura sintáctica de SQL. No realiza ninguna búsqueda en los catálogos del sistema, por lo que no hay posibilidad de comprender la semántica detallada de las operaciones solicitadas. Después de que el analizador finaliza, el proceso de transformación toma el árbol devuelto por el analizador como entrada y realiza la interpretación semántica necesaria para comprender qué tablas, funciones y operadores son referenciados por la consulta. La estructura de datos que se construye para representar esta información se denomina el árbol de consulta (query tree).
La razón para separar el análisis bruto del análisis semántico es que las
búsquedas en el catálogo del sistema solo se pueden hacer dentro de una
transacción, y no deseamos iniciar una transacción inmediatamente después de
recibir una cadena de consulta. La etapa de análisis bruto es suficiente para
identificar los comandos de control de transacciones (BEGIN,
ROLLBACK, etc.), y estos pueden ejecutarse correctamente sin
más análisis. Una vez que sabemos que estamos tratando con una consulta real
(como SELECT o UPDATE), está bien
iniciar una transacción si no estamos ya en una. Solo entonces se puede
invocar el proceso de transformación.
El árbol de consulta creado por el proceso de transformación es estructuralmente
similar al árbol de análisis bruto en la mayoría de los lugares, pero tiene muchas
diferencias en los detalles. Por ejemplo, un nodo FuncCall
en el árbol de análisis representa algo que parece sintácticamente una llamada a
una función. Esto podría transformarse en un nodo FuncExpr
o Aggref dependiendo de si el nombre referenciado resulta
ser una función ordinaria o una función de agregación. Además, se añade al
árbol de consulta información sobre los tipos de datos reales de las columnas y
los resultados de las expresiones.