#include "check_format.h" #include "ast.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace NSQLFormat { bool ValidateAST( const TString& original, TMaybe originalRes, const TString& formatted, const NSQLTranslation::TTranslationSettings& settings, const NSQLTranslationV1::TLexers& lexers, const NSQLTranslationV1::TParsers& parsers, NYql::TIssues& issues) { NYql::TAstParseResult originalResHolder; if (!originalRes.Defined()) { originalResHolder = NSQLTranslationV1::SqlToYql(lexers, parsers, original, settings); originalRes = originalResHolder.Root; } const NYql::TAstNode* expectedYQLs = *originalRes; NYql::TAstParseResult formattedRes = NSQLTranslationV1::SqlToYql(lexers, parsers, formatted, settings); const NYql::TAstNode* formattedYQLs = formattedRes.Root; const bool formattedIsOk = static_cast(formattedYQLs); const bool expectedIsOk = static_cast(expectedYQLs); if (expectedIsOk != formattedIsOk) { issues.AddIssue( TStringBuilder() << "Formatter changed semantics: " << "original was " << (expectedIsOk ? "OK" : "BAD") << ", but " << "formatted is " << (formattedIsOk ? "OK" : "BAD")); return false; } if (expectedYQLs && formattedYQLs) { TMaybe areEqual = AreAstEqual(expectedYQLs, formattedYQLs); if (areEqual && !*areEqual) { issues.AddIssue("Source query's AST and formatted query's AST are not same"); return false; } } return true; } bool ValidateConvergence( const ISqlFormatter::TPtr& formatter, const TString& formatted, NYql::TIssues& issues, EConvergenceRequirement convergence) { switch (convergence) { case EConvergenceRequirement::None: { return true; } case EConvergenceRequirement::Triple: { TString formatted2; if (!formatter->Format(formatted, formatted2, issues)) { return false; } TString formatted3; if (!formatter->Format(formatted2, formatted3, issues)) { return false; } if (formatted2 != formatted3) { issues.AddIssue( TStringBuilder() << "Triple formatting check failed. " << "Formatting a doubly formatted query yielded a different result."); return false; } return true; } case EConvergenceRequirement::Double: { TString formatted2; if (!formatter->Format(formatted, formatted2, issues)) { return false; } if (formatted != formatted2) { issues.AddIssue( TStringBuilder() << "Double formatting check failed. " << "Formatting an already formatted query yielded a different result. " << "Add /* skip double format */ to suppress"); return false; } return true; } } } TMaybe CheckedFormat( const TString& query, TMaybe ast, NSQLTranslation::TTranslationSettings settings, NYql::TIssues& issues, EConvergenceRequirement convergence) { if (!NSQLTranslation::ParseTranslationSettings(query, settings, issues)) { return Nothing(); } else if (settings.PgParser) { return query; } NSQLTranslationV1::TLexers lexers = { .Antlr4 = NSQLTranslationV1::MakeAntlr4LexerFactory(), .Antlr4Ansi = NSQLTranslationV1::MakeAntlr4AnsiLexerFactory(), }; NSQLTranslationV1::TParsers parsers = { .Antlr4 = NSQLTranslationV1::MakeAntlr4ParserFactory(), .Antlr4Ansi = NSQLTranslationV1::MakeAntlr4AnsiParserFactory(), }; auto formatter = NSQLFormat::MakeSqlFormatter(lexers, parsers, settings); TString formatted; if (!formatter->Format(query, formatted, issues)) { return Nothing(); } if (!ValidateAST(query, ast, formatted, settings, lexers, parsers, issues)) { return Nothing(); } if (!ValidateConvergence(formatter, formatted, issues, convergence)) { return Nothing(); } return formatted; } } // namespace NSQLFormat