50.3. Этап разбора#

50.3. Этап разбора

50.3. Этап разбора

Этап разбора состоит из двух частей:

  • Парсер parser, определенный в gram.y и scan.l. построен с помощью Unix-инструментов bison и flex.

  • Процесс трансформации вносит изменения и дополнения в структуры данных, возвращаемые парсером.

50.3.1. Парсер

Парсер должен проверить строку запроса (которая поступает в виде обычного текста) на наличие корректного синтаксиса. Если синтаксис правильный, строится и возвращается дерево разбора; в противном случае возвращается ошибка. Парсер и лексер реализованы с использованием известных инструментов Unix bison и flex.

Лексер определен в файле scan.l и отвечает за распознавание идентификаторов, ключевых слов SQL и т.д. Для каждого найденного ключевого слова или идентификатора генерируется токен и передается парсеру.

Парсер определен в файле gram.y и состоит из набора правил грамматики и действий, которые выполняются каждый раз, когда срабатывает правило. Код действий (который на самом деле является кодом на языке C) используется для построения дерева разбора.

Файл scan.l преобразуется в исходный файл на языке C scan.c с помощью программы flex, а файл gram.y преобразуется в gram.c с использованием bison. После выполнения этих преобразований можно использовать обычный компилятор C для создания парсера. Никогда не вносите изменения в сгенерированные файлы на языке C, так как они будут перезаписаны при следующем вызове flex или bison.

Примечание

Упомянутые преобразования и компиляции обычно выполняются автоматически с использованием makefiles, поставляемых в дистрибутиве исходного кода Tantor SE.

Подробное описание bison или грамматические правила, указанные в gram.y, выходят за рамки данного руководства. Существует множество книг и документов, посвященных flex и bison. Необходимо ознакомиться с bison, прежде чем начать изучать грамматику, указанную в gram.y, иначе вы не поймете, что там происходит.

50.3.2. Процесс преобразования

Этап разбора создает дерево разбора, используя только фиксированные правила о синтаксической структуре SQL. Он не выполняет поиск в системных каталогах, поэтому нет возможности понять детальную семантику запрашиваемых операций. После завершения разбора процесс трансформации берет дерево, возвращенное парсером, в качестве входных данных и выполняет семантическую интерпретацию, необходимую для понимания, на какие таблицы, функции и операторы ссылается запрос. Структура данных, которая строится для представления этой информации, называется деревом запроса.

Причина разделения сырого разбора от семантического анализа заключается в том, что поиск в системном каталоге может быть выполнен только в рамках транзакции, и мы не хотим начинать транзакцию сразу после получения строки запроса. Стадия сырого разбора достаточна для идентификации команд управления транзакцией (BEGIN, ROLLBACK и т. д.), и эти команды могут быть правильно выполнены без дополнительного анализа. Когда мы узнаем, что имеем дело с фактическим запросом (например, SELECT или UPDATE), можно начать транзакцию, если мы еще не находимся в ней. Только после этого может быть вызван процесс преобразования.

Дерево запроса, созданное процессом преобразования, структурно похоже на исходное дерево разбора в большинстве случаев, но имеет много отличий в деталях. Например, узел FuncCall в дереве разбора представляет что-то, что выглядит синтаксически как вызов функции. Это может быть преобразовано в узел FuncExpr или Aggref в зависимости от того, является ли ссылочное имя обычной функцией или агрегатной функцией. Также в дерево запроса добавляется информация о фактических типах данных столбцов и результатов выражений.