Как определить, к какой таблице принадлежит столбец в операторе SQL с учетом информации метаданных и дерева разбора из грамматики SQL? - PullRequest
1 голос
/ 13 мая 2019

У меня есть оператор SQL, дерево синтаксического анализа оператора на основе грамматики T-SQL и информация каталога, которая содержит отображение между каждой таблицей и ее столбцами.Поскольку две таблицы могут иметь одно и то же имя столбца, как я могу определить, к какой таблице принадлежит столбец?Пример показан ниже.

Продукт :

ID uniqueidentifier
Category nvarchar(500)
Manufacturer nvarchar(500)

Счет :

ID uniqueidentifier
Category nvarchar(500)
InvoiceTo nvarchar(100)
ProductID uniqueidentifier

Запрос:

SELECT P.ID, CATEGORY, MANUFACTURER
FROM PRODUCT P
WHERE ID IN (SELECT PRODUCTID FROM INVOICE WHERE CATEGORY = 'TEST')

Как видите, здесь есть два столбца категории: один в Product и один в Invoice.Я могу пройтись по дереву разбора и перечислить все столбцы и таблицы.Я также могу посмотреть приведенное выше отображение, чтобы увидеть, к какой таблице принадлежит столбец.Но для столбца Category я не могу разрешить его таблицу.

Ожидается :

Таблицы:

Product  
Invoice

Столбцы:

Product.ID   
Product.Category  
Product.Manufacturer  
Invoice.ProductID  
Invoice.Category

Я использую ANTLR для генерации парсеракод.Затем я использую подход Слушателя, чтобы подключиться к интересующим меня поддеревам: table_name и column_name.

Вот файл грамматики: https://github.com/antlr/grammars-v4/tree/master/tsql

Любая помощь будетс благодарностью.

Редактировать
Вот как выглядит мой класс слушателя:

  class TSqlNameListener : TSqlParserBaseListener {
        public HashSet<string> Tables { get; set; }
        public List<string> Columns { get; set; }

        public TSqlNameListener() {
            Tables = new HashSet<string>();
            Columns = new List<string>();
        }

        public override void EnterTable_name([NotNull] TSqlParser.Table_nameContext context) {
            Tables.Add(context.GetText());
            base.EnterTable_name(context);
        }

        public override void EnterFull_column_name([NotNull] TSqlParser.Full_column_nameContext context) {
            Columns.Add(context.GetText());
            base.EnterFull_column_name(context);
        }
    }

1 Ответ

2 голосов
/ 13 мая 2019

Создайте таблицу символов из вашего дерева разбора. Это иерархическое представление вашего ввода, которое позволяет определить контекст для данного символа. В такой таблице символов у вас будет узел, скажем, SelectSymbol, который представляет команду SELECT. Этот узел содержит дочерние элементы для каждой части этого запроса, включая узел WhereSymbol для предложения WHERE. Я думаю, что вы видите шаблон.

С этой таблицей теперь вы можете выполнять поиск, начиная с позиции вашего столбца на входе. Найдя его, вы затем идете вверх по родительской цепочке, чтобы найти контекст для столбца (здесь субселект), который содержит нужную таблицу + псевдоним.

Пример использования слушателя для создания таблицы символов можно найти в моем коде расширения antlr4-vscode . Этот слушатель заполняет таблицу символов из грамматики ANTLR4.

Примечание: этот подход возможен только в том случае, если ваш ввод синтаксически корректен (то есть может быть проанализирован). Если это не всегда (например, в редакторе), вам нужен другой подход, который требует больше работы.

...