text: /**
   * Copyright (c) 2021 OceanBase
   * OceanBase Database Proxy(ODP) is licensed under Mulan PubL v2.
   * You can use this software according to the terms and conditions of the Mulan PubL v2.
   * You may obtain a copy of Mulan PubL v2 at:
   *          http://license.coscl.org.cn/MulanPubL-2.0
   * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
   * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
   * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
   * See the Mulan PubL v2 for more details.
   */
  
  #define USING_LOG_PREFIX RPC_OBMYSQL
  
  #include "rpc/obmysql/ob_mysql_packet.h"
  
  #include "lib/utility/ob_macro_utils.h"
  #include "rpc/obmysql/ob_mysql_util.h"
  
  using namespace oceanbase::common;
  using namespace oceanbase::obmysql;
  
  namespace oceanbase
  {
  namespace obmysql
  {
  
  int ObMySQLPacket::encode_packet(char *buf, int64_t &len, int64_t &pos, const ObMySQLPacket &pkt)
  {
    int ret = OB_SUCCESS;
    if (OB_ISNULL(buf) || len <= 0 || pos < 0) {
      LOG_WARN("invalid buf or len", KP(buf), K(len), K(pos), K(ret));
      ret = OB_INVALID_ARGUMENT;
    } else {
      int64_t seri_size = 0;
      if (OB_FAIL(pkt.encode(buf + pos, len, seri_size))) {
        LOG_WARN("serialize response packet fail", K(ret));
      } else {
        len -= seri_size;
        pos += seri_size;
      }
    }
    return ret;
  }
  
  int ObMySQLPacket::encode(char *buffer, int64_t length, int64_t &pos) const
  {
    int ret = OB_SUCCESS;
  
    if (OB_ISNULL(buffer) || 0 >= length || pos < 0) {
      LOG_WARN("invalid argument", KP(buffer), K(length), K(pos));
      ret = OB_INVALID_ARGUMENT;
    } else {
      const int64_t orig_pos = pos;
      pos += OB_MYSQL_HEADER_LENGTH;
  
      if (OB_FAIL(serialize(buffer, length, pos))) {
        LOG_WARN("encode packet data failed", K(ret));
      } else {
        int32_t payload = static_cast<int32_t>(pos - orig_pos - OB_MYSQL_HEADER_LENGTH);
        pos = orig_pos;
        if (OB_FAIL(ObMySQLUtil::store_int3(buffer, length, payload, pos))) {
          LOG_ERROR("failed to encode int", K(ret)); // OB_ASSERT(false);
        } else if (OB_FAIL(ObMySQLUtil::store_int1(buffer, length, hdr_.seq_, pos))) {
          LOG_ERROR("failed to encode int", K(ret)); // OB_ASSERT(false);
        } else {
          pos += payload;
        }
      }
  
      if (OB_FAIL(ret)) {
        pos = orig_pos;
      }
    }
    return ret;
  }
  
  int64_t ObMySQLPacket::get_serialize_size() const
  {
    BACKTRACE(ERROR, 1, "not a serializiable packet");
    return -1;
  }
  
  int64_t ObMySQLRawPacket::get_serialize_size() const
  {
    return static_cast<int64_t>(get_clen()) + 1; // add 1 for cmd_
  }
  
  // serialize content in string<EOF> by default
  int ObMySQLRawPacket::serialize(char *buf, const int64_t length, int64_t &pos) const
  {
    int ret = OB_SUCCESS;
    if (OB_UNLIKELY(NULL == buf || length <= 0 || pos < 0
                    || length - pos < get_serialize_size() || NULL == cdata_)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid argument", KP(buf), K(length), K(get_serialize_size()), K(pos), K(ret));
    } else if (OB_FAIL(ObMySQLUtil::store_int1(buf, length, cmd_, pos))) {
      LOG_WARN("fail to store cmd", K(length), K(cmd_), K(pos), K(ret));
    } else if (OB_FAIL(ObMySQLUtil::store_str_vnzt(buf, length, get_cdata(), get_clen(), pos))) {
      LOG_WARN("fail to store content", K(length), K(get_cdata()), K(get_clen()), K(pos), K(ret));
    }
    return ret;
  }
  
  int ObMySQLRawPacket::encode_packet_meta(char *buf, int64_t &len, int64_t &pos) const
  {
    int ret = OB_SUCCESS;
    // healder len + cmd len = 4 + 1 = 5
    if (OB_UNLIKELY(NULL == buf || len <= 0 || pos < 0 || len - pos < 5)) {
      ret = OB_INVALID_ARGUMENT;
      LOG_WARN("invalid argument", KP(buf), K(len), K(pos), K(ret));
    } else {
      int32_t payload = 1 + hdr_.len_; // payload = cmd + request = 1 + hdr_.len
      if (OB_FAIL(ObMySQLUtil::store_int3(buf, len, payload, pos))) {
        LOG_ERROR("failed to encode int", K(ret));
      } else if (OB_FAIL(ObMySQLUtil::store_int1(buf, len, hdr_.seq_, pos))) {
        LOG_ERROR("failed to encode int", K(ret));
      } else if (OB_FAIL(ObMySQLUtil::store_int1(buf, len, cmd_, pos))) {
        LOG_WARN("fail to store cmd", K(len), K(cmd_), K(pos), K(ret));
      }
    }
  
    return ret;
  }
  
  char const *get_info_func_name(const ObInformationFunctions func)
  {
    const char *str = NULL;
    static const char *func_name_array[MAX_INFO_FUNC] =
    {
      "benchmark",
      "charset",
      "coercibility",
      "coliation",
      "connection_id",
      "current_user",
      "database",
      "found_rows",
      "last_insert_id",
      "row_count",
      "schema",
      "session_user",
      "system user",
      "user",
      "version",
    };
  
    if (func >= BENCHMARK_FUNC && func < MAX_INFO_FUNC) {
      str = func_name_array[func];
    }
    return str;
  }
  
  char const *get_mysql_cmd_str(ObMySQLCmd mysql_cmd)
  {
    const char *str = "invalid";
    static const char *mysql_cmd_array[OB_MYSQL_COM_MAX_NUM] =
    {
      "Sleep",  // OB_MYSQL_COM_SLEEP,
      "Quit",  // OB_MYSQL_COM_QUIT,
      "Init DB",  // OB_MYSQL_COM_INIT_DB,
      "Query",  // OB_MYSQL_COM_QUERY,
      "Field List",  // OB_MYSQL_COM_FIELD_LIST,
  
      "Create DB",  // OB_MYSQL_COM_CREATE_DB,
      "Drop DB",  // OB_MYSQL_COM_DROP_DB,
      "Refresh",  // OB_MYSQL_COM_REFRESH,
      "Shutdown",  // OB_MYSQL_COM_SHUTDOWN,
      "Statistics",  // OB_MYSQL_COM_STATISTICS,
  
      "Process Info",  // OB_MYSQL_COM_PROCESS_INFO,
      "Connect",  // OB_MYSQL_COM_CONNECT,
      "Process Kill",  // OB_MYSQL_COM_PROCESS_KILL,
      "Debug",  // OB_MYSQL_COM_DEBUG,
      "Ping",  // OB_MYSQL_COM_PING,
  
      "Time",  // OB_MYSQL_COM_TIME,
      "Delayed insert",  // OB_MYSQL_COM_DELAYED_INSERT,
      "Change user",  // OB_MYSQL_COM_CHANGE_USER,
      "Binlog dump",  // OB_MYSQL_COM_BINLOG_DUMP,
  
      "Table dump",  // OB_MYSQL_COM_TABLE_DUMP,
      "Connect out",  // OB_MYSQL_COM_CONNECT_OUT,
      "Register slave",  // OB_MYSQL_COM_REGISTER_SLAVE,
  
      "Prepare",  // OB_MYSQL_COM_STMT_PREPARE,
      "Execute",  // OB_MYSQL_COM_STMT_EXECUTE,
      "Stmt send long data",  // OB_MYSQL_COM_STMT_SEND_LONG_DATA,
      "Close stmt",  // OB_MYSQL_COM_STMT_CLOSE,
  
      "Stmt reset",  // OB_MYSQL_COM_STMT_RESET,
      "Set option",  // OB_MYSQL_COM_SET_OPTION,
      "Stmt fetch",  // OB_MYSQL_COM_STMT_FETCH,
      "Daemno",  // OB_MYSQL_COM_DAEMON,
  
      "Binlog dump gtid",  // OB_MYSQL_COM_BINLOG_DUMP_GTID,
      // "Reset connection",  // COM_RESET_CONNECTION,
      "Prepare Execute", // OB_MYSQL_COM_STMT_PREPARE_EXECUTE,
      "SEND PIECE DATA",
      "GET PIECE DATA",
      "End",  // OB_MYSQL_COM_END,
  
      "Delete session", // OB_MYSQL_COM_DELETE_SESSION
      "Handshake",  // OB_MYSQL_COM_HANDSHAKE,
      "Login"  // OB_MYSQL_COM_LOGIN,
    };
  
    if (mysql_cmd >= OB_MYSQL_COM_SLEEP && mysql_cmd <= OB_MYSQL_COM_BINLOG_DUMP_GTID) {
      str = mysql_cmd_array[mysql_cmd];
    } else if (mysql_cmd >= OB_MYSQL_COM_STMT_PREPARE_EXECUTE && mysql_cmd <= OB_MYSQL_COM_END) {
      int start = OB_MYSQL_COM_BINLOG_DUMP_GTID + 1;
      str = mysql_cmd_array[mysql_cmd - OBPROXY_NEW_MYSQL_CMD_START + start];
    } else if (mysql_cmd > OB_MYSQL_COM_END && mysql_cmd < OB_MYSQL_COM_MAX_NUM) {
      int start = OB_MYSQL_COM_BINLOG_DUMP_GTID + 1 + OB_MYSQL_COM_END - OB_MYSQL_COM_STMT_PREPARE_EXECUTE + 1;
      str = mysql_cmd_array[mysql_cmd - OBPROXY_MYSQL_CMD_START + start];
    }
    return str;
  
  }
  
  } // end of namespace obmysql
  } // end of namespace oceanbase
  