MySQL 源码 - 27|ImplicitCommitParser 解析器和 SplittingAllowedParser 解析器的调用位置

MySQL 源码 - 27|ImplicitCommitParser 解析器和 SplittingAllowedParser 解析器的调用位置

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

前置文档:

ImplicitCommitParser 解析器

ImplicitCommitParseris_implicitly_committed() 函数中被调用。该函数接收 2 个参数,分别为词法分析结果的 token遍历器 lexer 和事务状态 trx_state。根据 ImplicitCommitParser 解析器的逻辑,这个函数返回 SQL 需要隐式提交则返回 true,否则返回 false。

stdx::expected<bool, std::string> is_implicitly_committed(
    SqlLexer &&lexer,
    std::optional<classic_protocol::session_track::TransactionState>
        trx_state) {
  return ImplicitCommitParser(lexer.begin(), lexer.end()).parse(trx_state);
}

函数 is_implicitly_committedQueryForwarder::command() 的如下位置被调用:

  • 调用 connection()->trx_state() 判断当前是否在事务中,如果不在则将 stage 更新为 Stage::ClassifyQuery
  • 如果在事务中,则调用 is_implicitly_committed() 函数判断是否需要隐式提交:
    • 如果 is_implicitly_committed() 函数遭遇异常,则调用 harness_assert_this_should_not_execute()

    • 如果需要隐式提交,则判断当前连接是否已经打开(!server_conn.is_open()):

      • 如果连接已经打开,则调用并 trace_connect_and_explicit_commit() 并将当前阶段置为 Stage::ExplicitCommitConnect
      • 如果连接已经打开,则将当前阶段置为 Stage::ExplicitCommit
    • 如果不需要隐式提交,则将当前阶段置为 Stage::ClassifyQuery

    if (!connection()->trx_state()) {
      // no trx state, no trx.
      stage(Stage::ClassifyQuery);
    } else {
      auto is_implictly_committed_res = is_implicitly_committed(
          sql_parser_state_.lexer(), connection()->trx_state());
      if (!is_implictly_committed_res) {
        // it fails if trx-state() is not set, but it has been set.
        harness_assert_this_should_not_execute();
      } else if (*is_implictly_committed_res) {
        auto &server_conn = connection()->server_conn();
        if (!server_conn.is_open()) {
          trace_event_connect_and_explicit_commit_ =
              trace_connect_and_explicit_commit(trace_event_command_);
          stage(Stage::ExplicitCommitConnect);
        } else {
          stage(Stage::ExplicitCommit);
        }
      } else {
        // not implicitly committed.
        stage(Stage::ClassifyQuery);
      }
    }
SplittingAllowedParser 解析器

SplittingAllowedParsersplitting_allowed() 函数中被调用。该函数接收 1 个参数,为词法分析结果的 token遍历器 lexer。根据 SplittingAllowedParser 解析器的逻辑,这个函数返回 Allowed 状态。

stdx::expected<SplittingAllowedParser::Allowed, std::string> splitting_allowed(
    SqlLexer &&lexer) {
  return SplittingAllowedParser(lexer.begin(), lexer.end()).parse();
}

函数 splitting_allowed()QueryForwarder::command() 的如下分支中被调用,推测是当前 access_mode 仍为自动,还没有被指定:

if (connection()->context().access_mode() == routing::AccessMode::kAuto) {
    ...
}

具体地,调用逻辑如下:

const auto allowed_res = splitting_allowed(sql_parser_state_.lexer());

如果遇到了预期外的问题,则构造报错信息并将当前阶段置为 Stage::Done,返回 Result::SendToClient

      if (!allowed_res) {
        auto send_res = ClassicFrame::send_msg<
            classic_protocol::borrowed::message::server::Error>(
            src_conn, {ER_ROUTER_NOT_ALLOWED_WITH_CONNECTION_SHARING,
                       allowed_res.error(), "HY000"});
        if (!send_res) return send_client_failed(send_res.error());

        discard_current_msg(src_conn);

        stage(Stage::Done);
        return Result::SendToClient;
      }

否则,switch 处理 splitting_allowed() 函数返回的各个枚举值。

  • 如果返回 Allowed::Always 则不执行任何操作
        case SplittingAllowedParser::Allowed::Always:
          break;
  • 如果返回 Allowed::Never,则构造报错信息并将当前阶段置为 Stage::Done,返回 Result::SendToClient
        case SplittingAllowedParser::Allowed::Never: {
          auto send_res = ClassicFrame::send_msg<
              classic_protocol::borrowed::message::server::Error>(
              src_conn,
              {ER_ROUTER_NOT_ALLOWED_WITH_CONNECTION_SHARING,
               "Statement not allowed if access_mode is 'auto'", "HY000"});
          if (!send_res) return send_client_failed(send_res.error());

          discard_current_msg(src_conn);

          stage(Stage::Done);
          return Result::SendToClient;
        }
  • 如果返回其他枚举值,如果当前不在事务中,则构造报错信息并将当前阶段置为 Stage::Done,返回 Result::SendToClient;否则不做任何操作。

如果当前事务状态的类型为 _,即说明不在事务中,不需要提交,直接返回 false。详见 MySQL 源码 - 23|句法解析:ImplicitCommitParser 的解析方法 的 Step 2,来源于注释描述。

        case SplittingAllowedParser::Allowed::OnlyReadOnly:
        case SplittingAllowedParser::Allowed::OnlyReadWrite:
        case SplittingAllowedParser::Allowed::InTransaction:
          if (!connection()->trx_state() ||
              connection()->trx_state()->trx_type() == '_') {
            auto send_res = ClassicFrame::send_msg<
                classic_protocol::borrowed::message::server::Error>(
                src_conn,
                {ER_ROUTER_NOT_ALLOWED_WITH_CONNECTION_SHARING,
                 "Statement not allowed outside a transaction if access_mode "
                 "is 'auto'",
                 "HY000"});
            if (!send_res) return send_client_failed(send_res.error());

            discard_current_msg(src_conn);

            stage(Stage::Done);
            return Result::SendToClient;
          }
          break;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
mysql-connector-java是MySQL官方提供的Java驱动程序,用于在Java应用程序中连接和操作MySQL数据库。下面是mysql-connector-java源码的一些解析: 1. 驱动程序注册 在使用mysql-connector-java之前,需要先将驱动程序注册到JDBC驱动程序管理器中。这可以通过以下代码实现: ``` Class.forName("com.mysql.jdbc.Driver"); ``` 2. 创建连接 创建连接的过程可以通过以下代码实现: ``` Connection conn = DriverManager.getConnection(jdbcurl, username, password); ``` 其中,jdbcurl是连接字符串,包括数据库的地址、端口、数据库名称等信息。 3. 连接池 为了提高应用程序的性能,可以使用连接池来管理数据库连接。mysql-connector-java提供了一个名为“com.mysql.jdbc.jdbc2.optional.MysqlDataSource”的类,用于创建连接池。以下是一个简单的示例: ``` MysqlDataSource dataSource = new MysqlDataSource(); dataSource.setURL(jdbcurl); dataSource.setUser(username); dataSource.setPassword(password); Connection conn = dataSource.getConnection(); ``` 4. 执行SQL语句 mysql-connector-java提供了一个名为“java.sql.Statement”的接口,用于执行SQL语句。以下是一个简单的示例: ``` Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM users"); while (rs.next()) { System.out.println(rs.getString("username")); } ``` 5. 关闭连接 使用完连接后,需要将其关闭以释放资源。可以通过以下代码实现: ``` conn.close(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

长行

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

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

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

打赏作者

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

抵扣说明:

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

余额充值