format.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #include "check_runner.h"
  2. #include <yql/essentials/sql/v1/format/sql_format.h>
  3. #include <util/string/builder.h>
  4. namespace NYql {
  5. namespace NFastCheck {
  6. namespace {
  7. constexpr size_t FormatContextLimit = 100;
  8. class TFormatRunner : public ICheckRunner {
  9. public:
  10. TString GetCheckName() const final {
  11. return "format";
  12. }
  13. TCheckResponse Run(const TChecksRequest& request) final {
  14. switch (request.Syntax) {
  15. case ESyntax::SExpr:
  16. return RunSExpr(request);
  17. case ESyntax::PG:
  18. return RunPg(request);
  19. case ESyntax::YQL:
  20. return RunYql(request);
  21. }
  22. }
  23. private:
  24. TCheckResponse RunSExpr(const TChecksRequest& request) {
  25. Y_UNUSED(request);
  26. // no separate check for format here
  27. return TCheckResponse{.CheckName = GetCheckName(), .Success = true};
  28. }
  29. TCheckResponse RunPg(const TChecksRequest& request) {
  30. Y_UNUSED(request);
  31. // no separate check for format here
  32. return TCheckResponse{.CheckName = GetCheckName(), .Success = true};
  33. }
  34. TCheckResponse RunYql(const TChecksRequest& request) {
  35. TCheckResponse res {.CheckName = GetCheckName()};
  36. if (request.SyntaxVersion != 1) {
  37. res.Issues.AddIssue(TIssue({}, "Only SyntaxVersion 1 is supported"));
  38. return res;
  39. }
  40. google::protobuf::Arena arena;
  41. NSQLTranslation::TTranslationSettings settings;
  42. settings.Arena = &arena;
  43. settings.File = request.File;
  44. settings.Antlr4Parser = true;
  45. settings.AnsiLexer = request.IsAnsiLexer;
  46. auto formatter = NSQLFormat::MakeSqlFormatter(settings);
  47. NYql::TIssues issues;
  48. TString formattedQuery;
  49. res.Success = formatter->Format(request.Program, formattedQuery, issues);
  50. if (res.Success && formattedQuery != request.Program) {
  51. res.Success = false;
  52. TPosition origPos(0, 1, request.File);
  53. TTextWalker origWalker(origPos, true);
  54. size_t i = 0;
  55. for (; i < Min(request.Program.size(), formattedQuery.size()); ++i) {
  56. if (request.Program[i] == formattedQuery[i]) {
  57. origWalker.Advance(request.Program[i]);
  58. continue;
  59. }
  60. while (i > 0 && TTextWalker::IsUtf8Intermediate(request.Program[i])) {
  61. --i;
  62. }
  63. break;
  64. }
  65. TString formattedSample = formattedQuery.substr(i, FormatContextLimit);
  66. while (!formattedSample.empty() && TTextWalker::IsUtf8Intermediate(formattedQuery.back())) {
  67. formattedSample.erase(formattedSample.size() - 1);
  68. }
  69. TString origSample = request.Program.substr(i, FormatContextLimit);
  70. while (!origSample.empty() && TTextWalker::IsUtf8Intermediate(origSample.back())) {
  71. origSample.erase(origSample.size() - 1);
  72. }
  73. res.Issues.AddIssue(TIssue(origPos, TStringBuilder() <<
  74. "Format mismatch, expected:\n" << formattedSample << "\nbut got:\n" << origSample));
  75. }
  76. return res;
  77. }
  78. };
  79. }
  80. std::unique_ptr<ICheckRunner> MakeFormatRunner() {
  81. return std::make_unique<TFormatRunner>();
  82. }
  83. }
  84. }