MySQL 源码|26 - 句法解析:ShowWarningsParser 解析器

MySQL 源码 - 26|ShowWarningsParser 解析器

源码位置:(版本 = MySQL 8.0.37)

前置文档:MySQL 源码|SQLParser 类及其子类

ShowWarningsParser 解析器

ShowWarningsParser 解析方法的函数原型如下:

stdx::expected<std::variant<std::monostate, ShowWarningCount, ShowWarnings>,
               std::string>
ShowWarningsParser::parse()

这个函数的返回值为将 std::variant<std::monostate, ShowWarningCount, ShowWarnings> 作为预期值的 stdx::expected 类型。

解析函数逻辑如下:

  • 若第 1 个 token 为 SHOW

    • 若第 2 个 token 为 WARNINGS

      • 此时若下一个 token 为 LIMIT 则尝试解析 limit 子句(详见下面 “LIMIT 子句解析”),若 SQL 已结束,则返回 {std::in_place,ShowWarnings{ShowWarnings::Verbosity::Warning, limit_res->row_count, limit_res->offset}},否则返回 {}
      • 若下一个 token 不是 LIMIT,且 SQL 已结束则返回 {std::in_place, ShowWarnings{ShowWarnings::Verbosity::Warning}},否则返回 {}
    • 若第 2 个 token 为 ERRORS:逻辑与第 2 个 tokenWARNINGS 类似,只是将 ShowWarnings 的第 1 个参数替换为 ShowWarningCount::Verbosity::Error

    • 若第 2 - 5 个 token 依次为 COUNT(*)

      • 若下一个 token 为 WARNINGS:若此时 SQL 已结束,则返回 return {std::in_place, ShowWarningCount{ShowWarningCount::Verbosity::Warning, ShowWarningCount::Scope::Session}};;否则返回 {}
      • 若下一个 token 为 ERRORS:若此时 SQL 已结束,则返回 return {std::in_place, ShowWarningCount{ShowWarningCount::Verbosity::Error, ShowWarningCount::Scope::Session}};;否则返回 {}
      • 否则,返回 {}
  if (accept(SHOW)) {
    if (accept(WARNINGS)) {
      stdx::expected<Limit, std::string> limit_res;

      if (accept(LIMIT)) {  // optional limit
        limit_res = limit();
      }

      if (accept(END_OF_INPUT)) {
        if (limit_res) {
          return {std::in_place,
                  ShowWarnings{ShowWarnings::Verbosity::Warning,
                               limit_res->row_count, limit_res->offset}};
        }

        return {std::in_place, ShowWarnings{ShowWarnings::Verbosity::Warning}};
      }

      // unexpected input after SHOW WARNINGS [LIMIT ...]
      return {};
    } else if (accept(ERRORS)) {
      stdx::expected<Limit, std::string> limit_res;

      if (accept(LIMIT)) {
        limit_res = limit();
      }

      if (accept(END_OF_INPUT)) {
        if (limit_res) {
          return {std::in_place,
                  ShowWarnings{ShowWarningCount::Verbosity::Error,
                               limit_res->row_count, limit_res->offset}};
        }

        return {std::in_place,
                ShowWarnings{ShowWarningCount::Verbosity::Error}};
      }

      // unexpected input after SHOW ERRORS [LIMIT ...]
      return {};
    } else if (accept(COUNT_SYM) && accept('(') && accept('*') && accept(')')) {
      if (accept(WARNINGS)) {
        if (accept(END_OF_INPUT)) {
          return {std::in_place,
                  ShowWarningCount{ShowWarningCount::Verbosity::Warning,
                                   ShowWarningCount::Scope::Session}};
        }

        // unexpected input after SHOW COUNT(*) WARNINGS
        return {};
      } else if (accept(ERRORS)) {
        if (accept(END_OF_INPUT)) {
          return {std::in_place,
                  ShowWarningCount{ShowWarningCount::Verbosity::Error,
                                   ShowWarningCount::Scope::Session}};
        }

        // unexpected input after SHOW COUNT(*) ERRORS
        return {};
      }

      // unexpected input after SHOW COUNT(*), expected WARNINGS|ERRORS.
      return {};
    } else {
      // unexpected input after SHOW, expected WARNINGS|ERRORS|COUNT
      return {};
    }
  }
  • 若第 1 个 token 为 SELECT
    • 若第 2 - 3 个 token 均为 @
      • 若第 4 - 5 个 token 依次为 SESSION.
        • 若第 6 个 token 为 warning_count,且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Warning, ShowWarningCount::Scope::Session)}
        • 若第 6 个 token 为 error_count,且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Error, ShowWarningCount::Scope::Session)}
        • 否则,返回预期之外的字符串
      • 若第 4 - 5 个 token 依次为 LOCAL.
        • 若第 6 个 token 为 warning_count,且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Warning, ShowWarningCount::Scope::Local)}
        • 若第 6 个 token 为 error_count,且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Error, ShowWarningCount::Scope::Local)}
        • 否则,返回预期之外的字符串
      • 若第 4 个 token 不是 warning_count且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Warning, ShowWarningCount::Scope::None)}
      • 若第 4 个 token 为 error_count,且 SQL 已结束,则返回 {std::in_place, ShowWarningCount(ShowWarnings::Verbosity::Error, ShowWarningCount::Scope::None)}
    • 否则返回 {}
  else if (accept(SELECT_SYM)) {
    // match
    //
    // SELECT @@((LOCAL|SESSION).)?warning_count|error_count;
    //
    if (accept('@')) {
      if (accept('@')) {
        if (accept(SESSION_SYM)) {
          if (accept('.')) {
            auto ident_res = warning_count_ident();
            if (ident_res && accept(END_OF_INPUT)) {
              return ret_type{
                  std::in_place,
                  ShowWarningCount(*ident_res,
                                   ShowWarningCount::Scope::Session)};
            }
          }
        } else if (accept(LOCAL_SYM)) {
          if (accept('.')) {
            auto ident_res = warning_count_ident();
            if (ident_res && accept(END_OF_INPUT)) {
              return ret_type{
                  std::in_place,
                  ShowWarningCount(*ident_res, ShowWarningCount::Scope::Local)};
            }
          }
        } else {
          auto ident_res = warning_count_ident();
          if (ident_res && accept(END_OF_INPUT)) {
            return ret_type{
                std::in_place,
                ShowWarningCount(*ident_res, ShowWarningCount::Scope::None)};
          }
        }
      }
    }
  }
  • 若第 1 个 token 不是 SHOWSELECT,则返回 {}
LIMIT 子句解析

ShowWarningsParser 解析器中,用到了 LIMIT 子句的解析逻辑,具体如下:

stdx::expected<Limit, std::string> ShowWarningsParser::limit() {
  if (auto num1_tkn = expect(NUM)) {
    auto num1 = sv_to_num(num1_tkn.text());  // offset_or_row_count
    if (accept(',')) {
      if (auto num2_tkn = expect(NUM)) {
        auto num2 = sv_to_num(num2_tkn.text());  // row_count

        return Limit{num2, num1};
      }
    } else {
      return Limit{num1, 0};
    }
  }

  return stdx::make_unexpected(error_);
}

首先,num1_tkn = expect(NUM) 尝试匹配一个整型的字面值,然后 num1 = sv_to_num(num1_tkn.text()) 将这个字面值解析并存入 num1 变量。

接着,尝试匹配 ,,如果能够匹配则说明是 LIMIT 1, 3 的形式,再尝试匹配一个整型的字面值,然后将这个字面值解析并存入 num2 变量。

如果能够匹配到 , 则说明 num1 是 OFFSET,num2 是 LIMIT,返回 Limit{num2, num1}。否则,说明 num1 是 LIMIT,OFFSET 为 0,返回 Limit{num1, 0}

这个函数的返回值类型为 Limit,定义在 show_warnings_parser.h 中:

struct Limit {
  uint64_t row_count{std::numeric_limits<uint64_t>::max()};
  uint64_t offset{};
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值