Comments 35

Может я чего подзабыл, но разве зависимости для хранимок не лежат где-то в системных таблицах?

не уверен, что из зависимостей мы можем получить
конкретные связи между таблицами по полям

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


Это впрочем не делает примененный способ менее полезным. Я сам так делал совсем недавно, правда, на примере VBA — т.е. парсил код, и искал зависимости между процедурами и функциями.

Валидность процедур проверить просто,
пересоздав их(или перекомпилировать).

А вот того кто меняет структуру таблиц не заботясь о том, что упадет могут и расстрелять.))
тов. KvanTTT поправил меня, тезис «как оказалось он(Visitor) чаще используется для постоянно изменяемого кода, в котором могут быть синтаксические ошибки»,
Listener тоже так используется(а может использовался). Я ж говорю, подзабыл, сам видел в исходниках NetBeans. Обязательно рассмотрю реализацию в NetBeans. Надеюсь статья не последняя.

Писал аналогичный скрипт для PL/SQL на Python. Подскажите, как решались проблемы с:
1) Сложными конструкциями в блоках select и for
2) Устаревшим синтаксисом в стандартном наборе ANTRL

Если я Вас правильно понял, то
достаточно просто повнимательнее взглянуть на грамматику — там иерархия выражений. Если не хватает чего-то в грамматике, то надо дописать в ней. Обрабатываем только нужные нам узлы. Методы именуются так же как выражения в грамматике + префикс «Enter» в начале.
Проще самому потестировать этот код и поудалять мешающие return.
Чтобы обход дерева был более наглядным можно вставлять в методы код обхода дочерних узлов
for (ii = 0; ii < ctx.ChildCount; ++ii)
{
    Console.WriteLine("ii=" + ii.ToString());
    Console.WriteLine(ctx.GetChild(ii).GetType().ToString());
    Console.WriteLine(ctx.GetChild(ii).GetText());
}
Да, вот по ссылке books
лежит книга по предыдущей версии ATNLR от Terence Parr — «The Definitive ANTLR Reference»

Эх, бедный антлер, как только над ним не изгаляются: antl, ANTRL, ATNLR =)


Ну а так вообще конечно лучше новую книгу читать The Definitive ANTLR 4 Reference. В четвертой версии ANTLR появилось несколько фундамельных изменений (полноценный LL парсинг, поддержка левой рекурсии). Хотя даже с 2013 года в ANTLR 4 много нововведений и рантаймов, доступно в списке релизов.

1) Сложными конструкциями в блоках select и for

Что вы имеете в виду, можно пример? Можно использовать дополнителный стек для контроля вложенности конструкций.


2) Устаревшим синтаксисом в стандартном наборе ANTRL

Опять-таки, что за устаревший синтаксис в стандартном наборе? Грамматика PL/SQL в репозитории сейчас актуальная.

1) Я как раз про дополнительную обработку всего и вся рекурсивно, включая select секцию и не только.
2) Синтаксис Oracle SQL, PL/SQL в стандартном наборе действительно стал значительно лучше в последнее время. Только я не вижу некоторых новых конструкции из Oracle 12c (навскидку WITH_PLSQL, MATCH_RECOGNIZE). А между прочим расширенная поддержка 11g заканчивается уже в этом месяце.

Я вообще к чему это всё, инструмент — рабочий, общую картину увидеть позволяет. Но к сожалению от 10% до 30% связей мы не увидим. Частично из-за старой граматики (это как раз исправимо, пиши граматику сам), а вот проблема с динамическим кодом неразрешима.

В итоге получается, что инструменту на 100% доверять нельзя и всё-равно приходится посмотривать весь код глазами. Поиграться — да, надёжный инструмент — нет.

У Информатики даже продукт готовый есть за много тысяч долларов — Metadata Manager, увы, с той же степенью надёжности.

В случае с Oracle, если код в хранимых процедурах, то гораздо проще пользоваться таблицей ALL_DEPENDENCIES (пролема с динамикой остаётся). Если код в SVN, то только ANTRL.
Вы говорите примерно следующее,
«жалко, что молоток сам не выпрямляет гнутые гвозди», но молоток не был для этого предназначен. Инструмент на 100% рабочий. То что нужно детерминировать процедуры с динамическим кодом(которого думаю небольшой процент) и поставить заглушки и получить статический код и обработать его отдельно, я не вижу проблемы. Грамматику дописать? Конечно, и тут надо поработать, изучить как пишутся правила и т.д. Но, елки, ты ж программист.
Удачи.
Только я не вижу некоторых новых конструкции из Oracle 12c (навскидку WITH_PLSQL, MATCH_RECOGNIZE). А между прочим расширенная поддержка 11g заканчивается уже в этом месяце.

Можете создать issue на GitHub — рассмотрим. А в идеале вообще Pull Request.


Частично из-за старой граматики (это как раз исправимо, пиши граматику сам), а вот проблема с динамическим кодом неразрешима.

Ну да, это не проблема грамматики — нужно проводить дальнейшие действия над деревом разбора, возможно абстрактно интерпретировать.

Точнее сказать ограничить грамматику Java рантаймом.


Не поддерживаются в ANTLR вставки кода на универсальном языке, смотри мою issue Unified Actions Language. С другой стороны, уменьшать возможности грамматики из-за вырезания всех вставок кода я не хочу. Просто измените фрагменты кода Java на Python — это несложно.


Однако есть другой подход, который подходит к существующей версией ANTLR, смотри грамматику JavaScript. Однако в нем есть свои недостати: он громоздкий в реализации, да и не уверен, что применим к Python без доработки (поддерживаются C# и Java).

Дополнение для новой грамматики:
CaseChangingCharStream.cs на github
Program.cs:
...
//string text = System.IO.File.ReadAllText(@"c:\dev\antlr4\grammars-v4-master\tsql\examples\dml_select.sql");
//StringReader reader = new StringReader(text);
//// В качестве входного потока символов устанавливаем ...
//AntlrInputStream input = new AntlrInputStream(reader);
// Настраиваем лексер на этот поток

TSqlLexer lexer = new TSqlLexer(new CaseChangingCharStream(new AntlrFileStream(@"c:\dev\antlr4\grammars-v4-master\tsql\examples\dml_select1.sql"), true));//(input);
...

Спасибо тов. KvanTTT
Я пробовал воспроизвести тот пример, написал там вопрос.
Проблема: в гитхабе antlr4 лежат два файла: TSQLLexer.g4, TSQLParser.g4.
Я попробовал скомпилировать оба, но лексер прошел, а парсер дал массу ошибок типа
error(126): TSqlParser.g4:4030:48: cannot create implicit token for string literal in non-combined grammar: '^='
error(126): TSqlParser.g4:4030:55: cannot create implicit token for string literal in non-combined grammar: '|='
error(126): TSqlParser.g4:4034:35: cannot create implicit token for string literal in non-combined grammar: '%'
...


В статье, кстати, рассматривается грамматика TSQL.g4, видимо, в этом дело.
Но такого файла на гитхабе не нашел.
Нашел по ссылке в статье, прмер настроил. Кстати, в гугле группе пример отличается, здесь рабочий, там, похоже, требует коррекции.

Все правильно в репозитории. Похоже на то, что лексер вы все же не сгенерировали — ругается на неопределенные токены. Не могли бы показать команды, с помощью которых сгенерировали все?

Я здесь тот же вопрос задал
groups.google.com/forum/#!msg/antlr-discussion/avO91b8J2JE/iWuwBQ96AAAJ

Вот так генерировал, причем для лексера все прошло без ошибок.
java org.antlr.v4.Tool -visitor -Dlanguage=CSharp "%1\TSqlLexer.g4" -o "%1\TSQLLexer"
java org.antlr.v4.Tool -visitor -Dlanguage=CSharp "%1\TSqlParser.g4" -o "%1\TSQLParser"

Я могу тестовое приложение завернуть и выложить.

Кажется понял — генерация должна быть в одной папке, в которой создается файл .tokens при генерации лексера и который используется при генерации парсера. Т.е. значение параметра -o должно быть одинаковым в обоих случаях.

О, понял, спасибо, буду пробовать. А что думаете по поводу моего второго вопроса? & или &&
if ((mode == JoinMode.Undefined & ctx.ChildCount == 1) || (mode == JoinMode.Where))

Здесь разве &, а не &&?

public override void EnterTable_source_item_joined([NotNull] tsqlParser.Table_source_item_joinedContext ctx)
        {
            if ((mode == JoinMode.Undefined  & ctx.ChildCount == 1) || (mode == JoinMode.Where))

Да, скорее всего логическое и && — так и скобки лишние не нужны.

Ок. Кстати, еще ищу описание или примеры как сделать интепретатор на основе лексера и парсера? Я так понимаю, что сделать свой обходчик AST и добавить интерпретирующие функции
Интересно, спасибо! В связи с парсером на ANTLR4 — как и где лучше реализовывать интерпретатор? Лексер разбивает на лексемы, далее работает парсер, т.е. результатом является разобранный вход. Где по логике должен быть реализован интерпретатор?

Как минимум после парсинга, когда уже готово дерево разбора. Но возможно потребуется еще семантическая информация, информация о типах.

Статья называется «Парсим хранимки», но, собственно, о хранимках — ни слова.
В примере — только запросы. В чем же суть и как парсить хранимые процедуры? Что должно быть входом (sp?) и выходом?

Не совсем понятно, какая задача изначально решается. Скорей всего, поиск процедур, использующих таблицу или поиск таблиц, используемых в процедуре.
Через t-sql это можно получить одним запросом, см. sys.objects, object_definition, sys.sql_expression_dependencies.

Добрый день. Парсер ищет выражения в запросах, в которых есть равенство t1.f1 = t2.f2 и фиксирует его.
Это если кратко.
Only those users with full accounts are able to leave comments. Log in, please.