diff options
author | vvvv <vvvv@ydb.tech> | 2023-08-28 19:16:26 +0300 |
---|---|---|
committer | vvvv <vvvv@ydb.tech> | 2023-08-28 20:41:21 +0300 |
commit | 15ab95546529b917e592563f8081c972c08d301c (patch) | |
tree | 6a6768d80600bd7ef07984af8682d91dee207419 | |
parent | 80813963258b24f435ecede4c9f9f915ad2f1340 (diff) | |
download | ydb-15ab95546529b917e592563f8081c972c08d301c.tar.gz |
Moved sql2yql
-rw-r--r-- | ydb/library/yql/tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/CMakeLists.darwin-x86_64.txt | 41 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/CMakeLists.linux-aarch64.txt | 44 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/CMakeLists.linux-x86_64.txt | 46 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/CMakeLists.txt | 17 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/CMakeLists.windows-x86_64.txt | 34 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/sql2yql.cpp | 356 | ||||
-rw-r--r-- | ydb/library/yql/tools/sql2yql/ya.make | 25 | ||||
-rw-r--r-- | ydb/library/yql/tools/ya.make | 1 |
9 files changed, 565 insertions, 0 deletions
diff --git a/ydb/library/yql/tools/CMakeLists.txt b/ydb/library/yql/tools/CMakeLists.txt index 73d4896db45..02221978de6 100644 --- a/ydb/library/yql/tools/CMakeLists.txt +++ b/ydb/library/yql/tools/CMakeLists.txt @@ -8,4 +8,5 @@ add_subdirectory(astdiff) add_subdirectory(mrjob) +add_subdirectory(sql2yql) add_subdirectory(yqlrun) diff --git a/ydb/library/yql/tools/sql2yql/CMakeLists.darwin-x86_64.txt b/ydb/library/yql/tools/sql2yql/CMakeLists.darwin-x86_64.txt new file mode 100644 index 00000000000..6490a346a35 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,41 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_executable(sql2yql) +target_compile_options(sql2yql PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_link_libraries(sql2yql PUBLIC + contrib-libs-cxxsupp + yutil + library-cpp-cpuid_check + contrib-libs-antlr3_cpp_runtime + library-cpp-getopt + cpp-testing-unittest + yql-parser-lexer_common + yql-parser-pg_wrapper + udf-service-stub + library-yql-sql + yql-sql-pg + sql-v1-format +) +target_link_options(sql2yql PRIVATE + -Wl,-platform_version,macos,11.0,11.0 + -fPIC + -fPIC + -framework + CoreFoundation +) +target_sources(sql2yql PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/tools/sql2yql/sql2yql.cpp +) +target_allocator(sql2yql + system_allocator +) +vcs_info(sql2yql) diff --git a/ydb/library/yql/tools/sql2yql/CMakeLists.linux-aarch64.txt b/ydb/library/yql/tools/sql2yql/CMakeLists.linux-aarch64.txt new file mode 100644 index 00000000000..d2bf38f9c09 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/CMakeLists.linux-aarch64.txt @@ -0,0 +1,44 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_executable(sql2yql) +target_compile_options(sql2yql PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_link_libraries(sql2yql PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + contrib-libs-antlr3_cpp_runtime + library-cpp-getopt + cpp-testing-unittest + yql-parser-lexer_common + yql-parser-pg_wrapper + udf-service-stub + library-yql-sql + yql-sql-pg + sql-v1-format +) +target_link_options(sql2yql PRIVATE + -ldl + -lrt + -Wl,--no-as-needed + -fPIC + -fPIC + -lpthread + -lrt + -ldl +) +target_sources(sql2yql PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/tools/sql2yql/sql2yql.cpp +) +target_allocator(sql2yql + cpp-malloc-jemalloc +) +vcs_info(sql2yql) diff --git a/ydb/library/yql/tools/sql2yql/CMakeLists.linux-x86_64.txt b/ydb/library/yql/tools/sql2yql/CMakeLists.linux-x86_64.txt new file mode 100644 index 00000000000..a0e8f3864a0 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/CMakeLists.linux-x86_64.txt @@ -0,0 +1,46 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_executable(sql2yql) +target_compile_options(sql2yql PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_link_libraries(sql2yql PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp + yutil + library-cpp-cpuid_check + contrib-libs-antlr3_cpp_runtime + library-cpp-getopt + cpp-testing-unittest + yql-parser-lexer_common + yql-parser-pg_wrapper + udf-service-stub + library-yql-sql + yql-sql-pg + sql-v1-format +) +target_link_options(sql2yql PRIVATE + -ldl + -lrt + -Wl,--no-as-needed + -fPIC + -fPIC + -lpthread + -lrt + -ldl +) +target_sources(sql2yql PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/tools/sql2yql/sql2yql.cpp +) +target_allocator(sql2yql + cpp-malloc-tcmalloc + libs-tcmalloc-no_percpu_cache +) +vcs_info(sql2yql) diff --git a/ydb/library/yql/tools/sql2yql/CMakeLists.txt b/ydb/library/yql/tools/sql2yql/CMakeLists.txt new file mode 100644 index 00000000000..f8b31df0c11 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/ydb/library/yql/tools/sql2yql/CMakeLists.windows-x86_64.txt b/ydb/library/yql/tools/sql2yql/CMakeLists.windows-x86_64.txt new file mode 100644 index 00000000000..2ee47824b41 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/CMakeLists.windows-x86_64.txt @@ -0,0 +1,34 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_executable(sql2yql) +target_compile_options(sql2yql PRIVATE + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_link_libraries(sql2yql PUBLIC + contrib-libs-cxxsupp + yutil + library-cpp-cpuid_check + contrib-libs-antlr3_cpp_runtime + library-cpp-getopt + cpp-testing-unittest + yql-parser-lexer_common + yql-parser-pg_wrapper + udf-service-stub + library-yql-sql + yql-sql-pg + sql-v1-format +) +target_sources(sql2yql PRIVATE + ${CMAKE_SOURCE_DIR}/ydb/library/yql/tools/sql2yql/sql2yql.cpp +) +target_allocator(sql2yql + system_allocator +) +vcs_info(sql2yql) diff --git a/ydb/library/yql/tools/sql2yql/sql2yql.cpp b/ydb/library/yql/tools/sql2yql/sql2yql.cpp new file mode 100644 index 00000000000..e5536be91f3 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/sql2yql.cpp @@ -0,0 +1,356 @@ +#include <ydb/library/yql/ast/yql_ast.h> +#include <ydb/library/yql/ast/yql_ast_annotation.h> +#include <ydb/library/yql/ast/yql_expr.h> + +#include <ydb/library/yql/parser/lexer_common/hints.h> + +#include <ydb/library/yql/sql/sql.h> +#include <ydb/library/yql/providers/common/provider/yql_provider_names.h> +#include <ydb/library/yql/parser/pg_wrapper/interface/parser.h> + +#include <library/cpp/getopt/last_getopt.h> +#include <ydb/library/yql/sql/v1/format/sql_format.h> +#include <library/cpp/testing/unittest/registar.h> + +#include <util/stream/file.h> +#include <util/generic/hash.h> +#include <util/generic/hash_set.h> +#include <util/generic/string.h> +#include <util/string/escape.h> + +#include <google/protobuf/message.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/repeated_field.h> + +struct TPosOutput { + IOutputStream& Out; + ui32 Line; + ui32 Column; + + TPosOutput(IOutputStream& out) + : Out(out) + , Line(1) + , Column(0) + { + } + + void Output(ui32 line, ui32 column, const TString& value) { + while (Line < line) { + Out << Endl; + ++Line; + Column = 0; + } + while (Column < column) { + Out << " "; + ++Column; + } + if (value != "<EOF>") { + Out << value; + Column += value.size(); + } + } +}; + +static void ExtractQuery(TPosOutput& out, const google::protobuf::Message& node); + +static void VisitField(TPosOutput& out, const google::protobuf::FieldDescriptor& descr, const google::protobuf::Message& field) { + using namespace google::protobuf; + const Descriptor* d = descr.message_type(); + if (!d) { + ythrow yexception() << "Invalid AST: non-message node encountered"; + } + if (d->name() == "TToken") { + const Reflection* r = field.GetReflection(); + out.Output(r->GetUInt32(field, d->field(0)), r->GetUInt32(field, d->field(1)), r->GetString(field, d->field(2))); + } else { + ExtractQuery(out, field); + } +} + +static void ExtractQuery(TPosOutput& out, const google::protobuf::Message& node) { + using namespace google::protobuf; + TVector<const FieldDescriptor*> fields; + const Reflection* ref = node.GetReflection(); + ref->ListFields(node, &fields); + + for (auto it = fields.begin(); it != fields.end(); ++it) { + if ((*it)->is_repeated()) { + const ui32 fieldSize = ref->FieldSize(node, *it); + for (ui32 i = 0; i < fieldSize; ++i) { + VisitField(out, **it, ref->GetRepeatedMessage(node, *it, i)); + } + } else { + VisitField(out, **it, ref->GetMessage(node, *it)); + } + } +} + +bool TestFormat(const TString& query, const NSQLTranslation::TTranslationSettings& settings, const TString& queryFile, const NYql::TAstParseResult& parseRes, const TString& outFileName) { + TStringStream yqlProgram; + parseRes.Root->PrettyPrintTo(yqlProgram, NYql::TAstPrintFlags::PerLine | NYql::TAstPrintFlags::ShortQuote); + + TString frmQuery; + NYql::TIssues issues; + auto formatter = NSQLFormat::MakeSqlFormatter(settings); + if (!formatter->Format(query, frmQuery, issues)) { + Cerr << "Failed to format query: " << issues.ToString() << Endl; + return false; + } + NYql::TAstParseResult frmParseRes = NSQLTranslation::SqlToYql(query, settings); + TStringStream frmYqlProgram; + frmParseRes.Root->PrettyPrintTo(frmYqlProgram, NYql::TAstPrintFlags::PerLine | NYql::TAstPrintFlags::ShortQuote); + if (!frmParseRes.Issues.Empty()) { + frmParseRes.Issues.PrintWithProgramTo(Cerr, queryFile, frmQuery); + if (AnyOf(frmParseRes.Issues, [](const auto& issue) { return issue.GetSeverity() == NYql::TSeverityIds::S_ERROR;})) { + return false; + } + } + if (!frmParseRes.IsOk()) { + Cerr << "No error reported, but no yql compiled result!" << Endl << Endl; + return false; + } + if (yqlProgram.Str() != frmYqlProgram.Str()) { + Cerr << "source query's AST and formatted query's AST are not same\n"; + return false; + } + + TString frmQuery2; + if (!formatter->Format(frmQuery, frmQuery2, issues)) { + Cerr << "Failed to format already formatted query: " << issues.ToString() << Endl; + return false; + } + + if (!outFileName.empty()) { + TFixedBufferFileOutput out{outFileName}; + out << frmQuery; + } + return true; +} + +class TStoreMappingFunctor: public NLastGetopt::IOptHandler { +public: + TStoreMappingFunctor(THashMap<TString, TString>* target, char delim = '@') + : Target(target) + , Delim(delim) + { + } + + void HandleOpt(const NLastGetopt::TOptsParser* parser) final { + const TStringBuf val(parser->CurValOrDef()); + const auto service = TString(val.After(Delim)); + auto res = Target->emplace(TString(val.Before(Delim)), service); + if (!res.second) { + /// force replace already exist parametr + res.first->second = service; + } + } + +private: + THashMap<TString, TString>* Target; + char Delim; +}; + +int BuildAST(int argc, char* argv[]) { + NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); + + TString outFileName; + TString queryString; + ui16 syntaxVersion; + TString outFileNameFormat; + THashMap<TString, TString> clusterMapping; + clusterMapping["plato"] = NYql::YtProviderName; + + THashMap<TString, TString> tables; + THashSet<TString> flags; + + opts.AddLongOption('o', "output", "save output to file").RequiredArgument("file").StoreResult(&outFileName); + opts.AddLongOption('q', "query", "query string").RequiredArgument("query").StoreResult(&queryString); + opts.AddLongOption('t', "tree", "print AST proto text").NoArgument(); + opts.AddLongOption('d', "diff", "print inlined diff for original query and query build from AST if they differ").NoArgument(); + opts.AddLongOption('D', "dump", "dump inlined diff for original query and query build from AST").NoArgument(); + opts.AddLongOption('p', "print-query", "print given query before parsing").NoArgument(); + opts.AddLongOption('y', "yql", "translate result to Yql and print it").NoArgument(); + opts.AddLongOption('l', "lexer", "print query token stream").NoArgument(); + opts.AddLongOption("ansi-lexer", "use ansi lexer").NoArgument(); + opts.AddLongOption("pg", "use pg_query parser").NoArgument(); + opts.AddLongOption('a', "ann", "print Yql annotations").NoArgument(); + opts.AddLongOption('C', "cluster", "set cluster to service mapping").RequiredArgument("name@service").Handler(new TStoreMappingFunctor(&clusterMapping)); + opts.AddLongOption('T', "table", "set table to filename mapping").RequiredArgument("table@path").Handler(new TStoreMappingFunctor(&tables)); + opts.AddLongOption('R', "replace", "replace Output table with each statement result").NoArgument(); + opts.AddLongOption("sqllogictest", "input files are in sqllogictest format").NoArgument(); + opts.AddLongOption("syntax-version", "SQL syntax version").StoreResult(&syntaxVersion).DefaultValue(1); + opts.AddLongOption('F', "flags", "SQL pragma flags").SplitHandler(&flags, ','); + opts.AddLongOption("assume-ydb-on-slash", "Assume YDB provider if cluster name starts with '/'").NoArgument(); + opts.AddLongOption("test-format", "compare formatted query's AST with the original query's AST (only syntaxVersion=1 is supported).").NoArgument(); + opts.AddLongOption("format-output", "Saves formatted query to it").RequiredArgument("format-output").StoreResult(&outFileNameFormat); + opts.SetFreeArgDefaultTitle("query file"); + opts.AddHelpOption(); + + NLastGetopt::TOptsParseResult res(&opts, argc, argv); + TVector<TString> queryFiles(res.GetFreeArgs()); + + THolder<TFixedBufferFileOutput> outFile; + if (!outFileName.empty()) { + outFile.Reset(new TFixedBufferFileOutput(outFileName)); + } + IOutputStream& out = outFile ? *outFile.Get() : Cout; + + if (!res.Has("query") && queryFiles.empty()) { + Cerr << "No --query nor query file was specified" << Endl << Endl; + opts.PrintUsage(argv[0], Cerr); + } + + TVector<TString> queries; + int errors = 0; + for (ui32 i = 0; i <= queryFiles.size(); ++i) { + queries.clear(); + TString queryFile("query"); + if (i < queryFiles.size()) { + queryFile = queryFiles[i]; + TAutoPtr<TFileInput> filePtr; + if (queryFile != "-") { + filePtr.Reset(new TFileInput(queryFile)); + } + IInputStream& in = filePtr.Get() ? *filePtr : Cin; + if (res.Has("sqllogictest")) { + ui32 lineNum = 1; + TString line; + bool take = false; + while (in.ReadLine(line)) { + if (line.StartsWith("statement") || line.StartsWith("query")) { + take = true; + queries.emplace_back(); + queryFile = queryFiles[i] + " line " + ToString(lineNum + 1); + } else if (line.StartsWith("----") || line.empty()) { + take = false; + } else if (take) { + queries.back().append(line).append("\n"); + } + ++lineNum; + + } + } else { + queries.push_back(in.ReadAll()); + } + } else { + queries.push_back(queryString); + } + + for (const auto query: queries) { + if (query.empty()) { + continue; + } + if (res.Has("print-query")) { + out << query << Endl; + } + + google::protobuf::Arena arena; + NSQLTranslation::TTranslationSettings settings; + settings.Arena = &arena; + settings.ClusterMapping = clusterMapping; + settings.Flags = flags; + settings.SyntaxVersion = syntaxVersion; + settings.AnsiLexer = res.Has("ansi-lexer"); + settings.WarnOnV0 = false; + settings.V0ForceDisable = false; + settings.AssumeYdbOnClusterWithSlash = res.Has("assume-ydb-on-slash"); + + if (res.Has("lexer")) { + NYql::TIssues issues; + auto lexer = NSQLTranslation::SqlLexer(query, issues, settings); + NSQLTranslation::TParsedTokenList tokens; + if (lexer && NSQLTranslation::Tokenize(*lexer, query, queryFile, tokens, issues, NSQLTranslation::SQL_MAX_PARSER_ERRORS)) { + for (auto& token : tokens) { + out << token.Line << ":" << token.LinePos << "\t\t" << token.Name << "(" << EscapeC(token.Content) << ")\n"; + } + } + if (!issues.Empty()) { + issues.PrintTo(Cerr); + } + + bool hasError = AnyOf(issues, [](const auto& issue) { return issue.GetSeverity() == NYql::TSeverityIds::S_ERROR;}); + if (hasError) { + ++errors; + } + continue; + } + + NYql::TAstParseResult parseRes; + if (res.Has("pg")) { + parseRes = NSQLTranslationPG::PGToYql(query, settings); + } else { + if (res.Has("tree") || res.Has("diff") || res.Has("dump")) { + google::protobuf::Message* ast(NSQLTranslation::SqlAST(query, queryFile, parseRes.Issues, + NSQLTranslation::SQL_MAX_PARSER_ERRORS, settings)); + if (ast) { + if (res.Has("tree")) { + out << ast->DebugString() << Endl; + } + if (res.Has("diff") || res.Has("dump")) { + TStringStream result; + TPosOutput posOut(result); + ExtractQuery(posOut, *ast); + if (res.Has("dump") || query != result.Str()) { + out << NUnitTest::ColoredDiff(query, result.Str()) << Endl; + } + } + + NSQLTranslation::TSQLHints hints; + auto lexer = SqlLexer(query, parseRes.Issues, settings); + if (lexer && CollectSqlHints(*lexer, query, queryFile, settings.File, hints, parseRes.Issues, settings.MaxErrors)) { + parseRes = NSQLTranslation::SqlASTToYql(*ast, hints, settings); + } + } + } else { + parseRes = NSQLTranslation::SqlToYql(query, settings); + } + } + + if (parseRes.Root) { + TStringStream yqlProgram; + parseRes.Root->PrettyPrintTo(yqlProgram, NYql::TAstPrintFlags::PerLine | NYql::TAstPrintFlags::ShortQuote); + if (res.Has("yql")) { + out << yqlProgram.Str(); + } + if (res.Has("ann")) { + TMemoryPool pool(1024); + NYql::AnnotatePositions(*parseRes.Root, pool)->PrettyPrintTo(out, NYql::TAstPrintFlags::PerLine); + } + } + + bool hasError = false; + if (!parseRes.Issues.Empty()) { + parseRes.Issues.PrintWithProgramTo(Cerr, queryFile, query); + hasError = AnyOf(parseRes.Issues, [](const auto& issue) { return issue.GetSeverity() == NYql::TSeverityIds::S_ERROR;}); + } + + if (!parseRes.IsOk() && !hasError) { + hasError = true; + Cerr << "No error reported, but no yql compiled result!" << Endl << Endl; + } + + if (res.Has("test-format") && syntaxVersion == 1 && !hasError && parseRes.Root) { + hasError = !TestFormat(query, settings, queryFile, parseRes, outFileNameFormat); + } + + if (hasError) { + ++errors; + } + } + } + + return errors; +} + +int main(int argc, char* argv[]) { + try { + return BuildAST(argc, argv); + } catch (const yexception& e) { + Cerr << "Caught exception:" << e.what() << Endl; + return 1; + } catch (...) { + Cerr << "Caught exception" << Endl; + return 1; + } + return 0; +} diff --git a/ydb/library/yql/tools/sql2yql/ya.make b/ydb/library/yql/tools/sql2yql/ya.make new file mode 100644 index 00000000000..5ee84c5c1c2 --- /dev/null +++ b/ydb/library/yql/tools/sql2yql/ya.make @@ -0,0 +1,25 @@ +PROGRAM() + +PEERDIR( + contrib/libs/antlr3_cpp_runtime + library/cpp/getopt + library/cpp/testing/unittest + ydb/library/yql/parser/lexer_common + ydb/library/yql/parser/pg_wrapper + ydb/library/yql/public/udf/service/stub + ydb/library/yql/sql + ydb/library/yql/sql/pg + ydb/library/yql/sql/v1/format +) + +NO_COMPILER_WARNINGS() + +ADDINCL( + GLOBAL contrib/libs/antlr3_cpp_runtime/include +) + +SRCS( + sql2yql.cpp +) + +END() diff --git a/ydb/library/yql/tools/ya.make b/ydb/library/yql/tools/ya.make index 3e928cff45d..a17f84573b4 100644 --- a/ydb/library/yql/tools/ya.make +++ b/ydb/library/yql/tools/ya.make @@ -2,4 +2,5 @@ RECURSE( astdiff mrjob yqlrun + sql2yql ) |