ps protocol analysis add defense check
This commit is contained in:
		@ -63,6 +63,19 @@ using namespace sql;
 | 
			
		||||
using namespace pl;
 | 
			
		||||
namespace observer
 | 
			
		||||
{
 | 
			
		||||
inline int ObPSAnalysisChecker::detection(const int64_t len)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  if (!need_check_) {
 | 
			
		||||
  } else if (*pos_ + len > end_pos_) {
 | 
			
		||||
    ret = OB_ERR_MALFORMED_PS_PACKET;
 | 
			
		||||
    LOG_USER_ERROR(OB_ERR_MALFORMED_PS_PACKET);
 | 
			
		||||
    LOG_ERROR("malformed ps data packet, please check the number and content of data packet parameters", K(ret), KP(pos_), KP(begin_pos_),
 | 
			
		||||
    K(end_pos_ - begin_pos_), K(len), K(data_len_), K(remain_len()));
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ObMPStmtExecute::ObMPStmtExecute(const ObGlobalContext &gctx)
 | 
			
		||||
    : ObMPBase(gctx),
 | 
			
		||||
      retry_ctrl_(/*ctx_.retry_info_*/),
 | 
			
		||||
@ -506,28 +519,32 @@ int ObMPStmtExecute::before_process()
 | 
			
		||||
    }
 | 
			
		||||
    const ObMySQLRawPacket &pkt = reinterpret_cast<const ObMySQLRawPacket&>(req_->get_packet());
 | 
			
		||||
    const char* pos = pkt.get_cdata();
 | 
			
		||||
    analysis_checker_.init(pos, pkt.get_clen());
 | 
			
		||||
    int32_t stmt_id = -1; //INVALID_STMT_ID
 | 
			
		||||
    ObMySQLUtil::get_int4(pos, stmt_id);
 | 
			
		||||
    stmt_id_ = stmt_id;
 | 
			
		||||
 | 
			
		||||
    // pos += 1; //skip flags
 | 
			
		||||
    int8_t flag = 0;
 | 
			
		||||
    ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
    const uint8_t ARRAYBINDING_MODE = 8;
 | 
			
		||||
    const uint8_t SAVE_EXCEPTION_MODE = 16;
 | 
			
		||||
    is_arraybinding_ = flag & ARRAYBINDING_MODE;
 | 
			
		||||
    is_save_exception_ = flag & SAVE_EXCEPTION_MODE;
 | 
			
		||||
    ps_cursor_type_ = 0 != (flag & CURSOR_TYPE_READ_ONLY)
 | 
			
		||||
                        ? ObExecutePsCursorType
 | 
			
		||||
                        : ObNormalType;
 | 
			
		||||
 | 
			
		||||
    // 4 bytes, iteration-count, used for checksum
 | 
			
		||||
    uint32_t ps_stmt_checksum = 0;
 | 
			
		||||
    ObMySQLUtil::get_uint4(pos, ps_stmt_checksum);
 | 
			
		||||
 | 
			
		||||
    ObSQLSessionInfo *session = NULL;
 | 
			
		||||
    if (is_arraybinding_) {
 | 
			
		||||
      OZ (init_for_arraybinding(alloc));
 | 
			
		||||
    PS_DEFENSE_CHECK(9) // stmt_id(4) + flag(1) + checksum(4)
 | 
			
		||||
    {
 | 
			
		||||
      ObMySQLUtil::get_int4(pos, stmt_id);
 | 
			
		||||
      stmt_id_ = stmt_id;
 | 
			
		||||
 | 
			
		||||
      // pos += 1; //skip flags
 | 
			
		||||
      int8_t flag = 0;
 | 
			
		||||
      ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
      const uint8_t ARRAYBINDING_MODE = 8;
 | 
			
		||||
      const uint8_t SAVE_EXCEPTION_MODE = 16;
 | 
			
		||||
      is_arraybinding_ = flag & ARRAYBINDING_MODE;
 | 
			
		||||
      is_save_exception_ = flag & SAVE_EXCEPTION_MODE;
 | 
			
		||||
      ps_cursor_type_ = 0 != (flag & CURSOR_TYPE_READ_ONLY)
 | 
			
		||||
                          ? ObExecutePsCursorType
 | 
			
		||||
                          : ObNormalType;
 | 
			
		||||
 | 
			
		||||
      // 4 bytes, iteration-count, used for checksum
 | 
			
		||||
      ObMySQLUtil::get_uint4(pos, ps_stmt_checksum);
 | 
			
		||||
 | 
			
		||||
      if (is_arraybinding_) {
 | 
			
		||||
        OZ (init_for_arraybinding(alloc));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (OB_FAIL(ret)) {
 | 
			
		||||
    } else if (OB_FAIL(get_session(session))) {
 | 
			
		||||
@ -611,10 +628,13 @@ int ObMPStmtExecute::parse_request_type(const char* &pos,
 | 
			
		||||
    uint8_t type = 0;
 | 
			
		||||
    int8_t flag = 0;
 | 
			
		||||
    if (1 == new_param_bound_flag) {
 | 
			
		||||
      ObMySQLUtil::get_uint1(pos, type);
 | 
			
		||||
      ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
      if (OB_FAIL(param_types.push_back(static_cast<EMySQLFieldType>(type)))) {
 | 
			
		||||
        LOG_WARN("fail to push back", K(type), K(i));
 | 
			
		||||
      PS_DEFENSE_CHECK(2) // type(1) + flag(1)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_uint1(pos, type);
 | 
			
		||||
        ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
        if (OB_FAIL(param_types.push_back(static_cast<EMySQLFieldType>(type)))) {
 | 
			
		||||
          LOG_WARN("fail to push back", K(type), K(i));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (num_of_params != param_types.count()) {
 | 
			
		||||
@ -634,9 +654,12 @@ int ObMPStmtExecute::parse_request_type(const char* &pos,
 | 
			
		||||
        if (OB_FAIL(decode_type_info(pos, type_name_info))) {
 | 
			
		||||
          LOG_WARN("failed to decode type info", K(ret));
 | 
			
		||||
        } else if (type_name_info.type_name_.empty()) {
 | 
			
		||||
          type_name_info.is_elem_type_ = true;
 | 
			
		||||
          ObMySQLUtil::get_uint1(pos, elem_type);
 | 
			
		||||
          ObObjType ob_elem_type;
 | 
			
		||||
          type_name_info.is_elem_type_ = true;
 | 
			
		||||
          PS_DEFENSE_CHECK(1) // elem_type(1)
 | 
			
		||||
          {
 | 
			
		||||
            ObMySQLUtil::get_uint1(pos, elem_type);
 | 
			
		||||
          }
 | 
			
		||||
          OZ (ObSMUtils::get_ob_type(
 | 
			
		||||
            ob_elem_type, static_cast<EMySQLFieldType>(elem_type)), elem_type);
 | 
			
		||||
          OX (type_name_info.elem_type_.set_obj_type(ob_elem_type));
 | 
			
		||||
@ -718,6 +741,19 @@ int ObMPStmtExecute::parse_request_param_value(ObIAllocator &alloc,
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObMPStmtExecute::is_contain_complex_element(const sql::ParamTypeArray ¶m_types) const
 | 
			
		||||
{
 | 
			
		||||
  bool b_ret = false;
 | 
			
		||||
  for (int64_t i = 0; i < param_types.count(); i++) {
 | 
			
		||||
    const obmysql::EMySQLFieldType field_type = param_types.at(i);
 | 
			
		||||
    if (MYSQL_TYPE_COMPLEX == field_type) {
 | 
			
		||||
      b_ret = true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return b_ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ObMPStmtExecute::request_params(ObSQLSessionInfo *session,
 | 
			
		||||
                                    const char* &pos,
 | 
			
		||||
                                    uint32_t ps_stmt_checksum,
 | 
			
		||||
@ -793,17 +829,20 @@ int ObMPStmtExecute::request_params(ObSQLSessionInfo *session,
 | 
			
		||||
      int64_t bitmap_types = (params_num_ + 7) / 8;
 | 
			
		||||
      const char *bitmap = pos;
 | 
			
		||||
      pos += bitmap_types;
 | 
			
		||||
      // Step2: 获取new_param_bound_flag字段
 | 
			
		||||
      ObMySQLUtil::get_int1(pos, new_param_bound_flag);
 | 
			
		||||
      ParamTypeArray ¶m_types = ps_session_info->get_param_types();
 | 
			
		||||
      ParamTypeInfoArray param_type_infos;
 | 
			
		||||
      ParamCastArray param_cast_infos;
 | 
			
		||||
 | 
			
		||||
      ParamTypeArray returning_param_types;
 | 
			
		||||
      ParamTypeInfoArray returning_param_type_infos;
 | 
			
		||||
 | 
			
		||||
      if (new_param_bound_flag == 1) {
 | 
			
		||||
        param_types.reuse();
 | 
			
		||||
      int64_t len = bitmap_types + 1/*new_param_bound_flag*/;
 | 
			
		||||
      PS_DEFENSE_CHECK(len) // bitmap_types
 | 
			
		||||
      {
 | 
			
		||||
        // Step2: 获取new_param_bound_flag字段
 | 
			
		||||
        ObMySQLUtil::get_int1(pos, new_param_bound_flag);
 | 
			
		||||
        if (new_param_bound_flag == 1) {
 | 
			
		||||
          param_types.reuse();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (OB_FAIL(ret)) {
 | 
			
		||||
        // do nothing
 | 
			
		||||
@ -839,6 +878,8 @@ int ObMPStmtExecute::request_params(ObSQLSessionInfo *session,
 | 
			
		||||
                                                     param_types,
 | 
			
		||||
                                                     param_type_infos))) {
 | 
			
		||||
        LOG_WARN("fail to parse input params type", K(ret));
 | 
			
		||||
      } else if (is_contain_complex_element(param_types)) {
 | 
			
		||||
        analysis_checker_.need_check_ = false;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Step3-2: 获取returning into params type信息
 | 
			
		||||
@ -920,8 +961,11 @@ int ObMPStmtExecute::decode_type_info(const char*& buf, TypeInfo &type_info)
 | 
			
		||||
    if (OB_FAIL(ObMySQLUtil::get_length(buf, length))) {
 | 
			
		||||
      LOG_WARN("failed to get length", K(ret));
 | 
			
		||||
    } else {
 | 
			
		||||
      type_info.relation_name_.assign_ptr(buf, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
      buf += length;
 | 
			
		||||
      PS_DEFENSE_CHECK(length)
 | 
			
		||||
      {
 | 
			
		||||
        type_info.relation_name_.assign_ptr(buf, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
        buf += length;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (OB_SUCC(ret)) {
 | 
			
		||||
@ -929,8 +973,11 @@ int ObMPStmtExecute::decode_type_info(const char*& buf, TypeInfo &type_info)
 | 
			
		||||
    if (OB_FAIL(ObMySQLUtil::get_length(buf, length))) {
 | 
			
		||||
      LOG_WARN("failed to get length", K(ret));
 | 
			
		||||
    } else {
 | 
			
		||||
      type_info.type_name_.assign_ptr(buf, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
      buf += length;
 | 
			
		||||
      PS_DEFENSE_CHECK(length)
 | 
			
		||||
      {
 | 
			
		||||
        type_info.type_name_.assign_ptr(buf, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
        buf += length;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if (OB_SUCC(ret)) {
 | 
			
		||||
@ -2000,7 +2047,8 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator,
 | 
			
		||||
                                             const char *& data,
 | 
			
		||||
                                             const common::ObTimeZoneInfo *tz_info,
 | 
			
		||||
                                             ObObj ¶m,
 | 
			
		||||
                                             bool is_complex_element)
 | 
			
		||||
                                             bool is_complex_element,
 | 
			
		||||
                                             ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  UNUSED(charset);
 | 
			
		||||
@ -2009,74 +2057,89 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator,
 | 
			
		||||
    case MYSQL_TYPE_SHORT:
 | 
			
		||||
    case MYSQL_TYPE_LONG:
 | 
			
		||||
    case MYSQL_TYPE_LONGLONG: {
 | 
			
		||||
      if (OB_FAIL(parse_integer_value(type, data, param, allocator, is_complex_element))) {
 | 
			
		||||
      if (OB_FAIL(parse_integer_value(type, data, param, allocator, is_complex_element, checker))) {
 | 
			
		||||
        LOG_WARN("parse integer value from client failed", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_FLOAT: {
 | 
			
		||||
      float value = 0;
 | 
			
		||||
      MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
      data += sizeof(value);
 | 
			
		||||
      param.set_float(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, sizeof(value))
 | 
			
		||||
      {
 | 
			
		||||
        MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
        data += sizeof(value);
 | 
			
		||||
        param.set_float(value);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_ORA_BINARY_FLOAT: {
 | 
			
		||||
      float value = 0;
 | 
			
		||||
      MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
      data += sizeof(value);
 | 
			
		||||
      param.set_float(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, sizeof(value))
 | 
			
		||||
      {
 | 
			
		||||
        MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
        data += sizeof(value);
 | 
			
		||||
        param.set_float(value);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_DOUBLE: {
 | 
			
		||||
      double value = 0;
 | 
			
		||||
      MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
      data += sizeof(value);
 | 
			
		||||
      if (lib::is_mysql_mode()) {
 | 
			
		||||
        param.set_double(value);
 | 
			
		||||
      } else {
 | 
			
		||||
        char *buf = NULL;
 | 
			
		||||
        int64_t buf_len = 0;
 | 
			
		||||
        number::ObNumber nb;
 | 
			
		||||
        const int64_t alloc_size = OB_MAX_DOUBLE_FLOAT_DISPLAY_WIDTH;
 | 
			
		||||
        if (OB_ISNULL(buf = static_cast<char *>(allocator.alloc(alloc_size)))) {
 | 
			
		||||
          ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
			
		||||
          LOG_WARN("failed to allocate memory", K(ret));
 | 
			
		||||
        } else if (FALSE_IT(buf_len = ob_gcvt_strict(value, OB_GCVT_ARG_DOUBLE, alloc_size,
 | 
			
		||||
                                                     buf, NULL, TRUE/*is_oracle_mode*/,
 | 
			
		||||
                                                     FALSE/*is_binary_double*/, FALSE))) {
 | 
			
		||||
        } else if (OB_FAIL(nb.from_sci_opt(buf, buf_len, allocator))) {
 | 
			
		||||
          LOG_WARN("decode double param to number failed", K(ret));
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, sizeof(value))
 | 
			
		||||
      {
 | 
			
		||||
        MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
        data += sizeof(value);
 | 
			
		||||
        if (lib::is_mysql_mode()) {
 | 
			
		||||
          param.set_double(value);
 | 
			
		||||
        } else {
 | 
			
		||||
          param.set_number(nb);
 | 
			
		||||
          char *buf = NULL;
 | 
			
		||||
          int64_t buf_len = 0;
 | 
			
		||||
          number::ObNumber nb;
 | 
			
		||||
          const int64_t alloc_size = OB_MAX_DOUBLE_FLOAT_DISPLAY_WIDTH;
 | 
			
		||||
          if (OB_ISNULL(buf = static_cast<char *>(allocator.alloc(alloc_size)))) {
 | 
			
		||||
            ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
			
		||||
            LOG_WARN("failed to allocate memory", K(ret));
 | 
			
		||||
          } else if (FALSE_IT(buf_len = ob_gcvt_strict(value, OB_GCVT_ARG_DOUBLE, alloc_size,
 | 
			
		||||
                                                      buf, NULL, TRUE/*is_oracle_mode*/,
 | 
			
		||||
                                                      FALSE/*is_binary_double*/, FALSE))) {
 | 
			
		||||
          } else if (OB_FAIL(nb.from_sci_opt(buf, buf_len, allocator))) {
 | 
			
		||||
            LOG_WARN("decode double param to number failed", K(ret));
 | 
			
		||||
          } else {
 | 
			
		||||
            param.set_number(nb);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_ORA_BINARY_DOUBLE: {
 | 
			
		||||
      double value = 0;
 | 
			
		||||
      MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
      data += sizeof(value);
 | 
			
		||||
      param.set_double(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, sizeof(value))
 | 
			
		||||
      {
 | 
			
		||||
        MEMCPY(&value, data, sizeof(value));
 | 
			
		||||
        data += sizeof(value);
 | 
			
		||||
        param.set_double(value);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_YEAR: {
 | 
			
		||||
      int16_t value = 0;
 | 
			
		||||
      ObMySQLUtil::get_int2(data, value);
 | 
			
		||||
      param.set_year(static_cast<uint8_t>(value));
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 2)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int2(data, value);
 | 
			
		||||
        param.set_year(static_cast<uint8_t>(value));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_DATE:
 | 
			
		||||
    case MYSQL_TYPE_DATETIME:
 | 
			
		||||
    case MYSQL_TYPE_TIMESTAMP: {
 | 
			
		||||
      if (OB_FAIL(parse_mysql_timestamp_value(static_cast<EMySQLFieldType>(type), data,
 | 
			
		||||
                                              param, tz_info))) {
 | 
			
		||||
                                              param, tz_info, checker))) {
 | 
			
		||||
        LOG_WARN("parse timestamp value from client failed", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_TIME:{
 | 
			
		||||
      if (OB_FAIL(parse_mysql_time_value(data, param))) {
 | 
			
		||||
      if (OB_FAIL(parse_mysql_time_value(data, param, checker))) {
 | 
			
		||||
        LOG_WARN("parse timestamp value from client failed", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
@ -2086,7 +2149,7 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator,
 | 
			
		||||
    case MYSQL_TYPE_OB_TIMESTAMP_NANO: {
 | 
			
		||||
      ObTimeConvertCtx cvrt_ctx(tz_info, true);
 | 
			
		||||
      if (OB_FAIL(parse_oracle_timestamp_value(
 | 
			
		||||
                            static_cast<EMySQLFieldType>(type), data, cvrt_ctx, param))) {
 | 
			
		||||
                            static_cast<EMySQLFieldType>(type), data, cvrt_ctx, param, checker))) {
 | 
			
		||||
        LOG_WARN("parse timestamp value from client failed", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
@ -2115,7 +2178,10 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator,
 | 
			
		||||
      if (OB_FAIL(ObMySQLUtil::get_length(data, length))) {
 | 
			
		||||
        LOG_ERROR("decode varchar param value failed", K(ret));
 | 
			
		||||
      } else {
 | 
			
		||||
        str.assign_ptr(data, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
        PS_STATIC_DEFENSE_CHECK(checker, length)
 | 
			
		||||
        {
 | 
			
		||||
          str.assign_ptr(data, static_cast<ObString::obstr_size_t>(length));
 | 
			
		||||
        }
 | 
			
		||||
        if (OB_FAIL(ret)) {
 | 
			
		||||
        } else if (MYSQL_TYPE_OB_NVARCHAR2 == type
 | 
			
		||||
                  || MYSQL_TYPE_OB_NCHAR == type) {
 | 
			
		||||
@ -2291,13 +2357,13 @@ int ObMPStmtExecute::parse_basic_param_value(ObIAllocator &allocator,
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_OB_INTERVAL_YM: {
 | 
			
		||||
      if (OB_FAIL(parse_oracle_interval_ym_value(data, param))) {
 | 
			
		||||
      if (OB_FAIL(parse_oracle_interval_ym_value(data, param, checker))) {
 | 
			
		||||
        LOG_WARN("failed to parse oracle interval year to month value", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_OB_INTERVAL_DS:{
 | 
			
		||||
      if (OB_FAIL(parse_oracle_interval_ds_value(data, param))) {
 | 
			
		||||
      if (OB_FAIL(parse_oracle_interval_ds_value(data, param, checker))) {
 | 
			
		||||
        LOG_WARN("failed to parse oracle interval year to month value", K(ret));
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
@ -2356,7 +2422,7 @@ int ObMPStmtExecute::parse_param_value(ObIAllocator &allocator,
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      if (OB_FAIL(parse_basic_param_value(allocator, type, charset, cs_type, ncs_type,
 | 
			
		||||
                                          data, tz_info, param))) {
 | 
			
		||||
                                          data, tz_info, param, false, &analysis_checker_))) {
 | 
			
		||||
        LOG_WARN("failed to parse basic param value", K(ret));
 | 
			
		||||
      } else {
 | 
			
		||||
        param.set_param_meta();
 | 
			
		||||
@ -2440,7 +2506,7 @@ int ObMPStmtExecute::parse_param_value(ObIAllocator &allocator,
 | 
			
		||||
        } else {
 | 
			
		||||
          const char* src = tmp;
 | 
			
		||||
          if (OB_FAIL(parse_basic_param_value(allocator, type, charset, cs_type, ncs_type,
 | 
			
		||||
                                              src, tz_info, param))) {
 | 
			
		||||
                                              src, tz_info, param, false))) {
 | 
			
		||||
            LOG_WARN("failed to parse basic param value", K(ret));
 | 
			
		||||
          } else {
 | 
			
		||||
            param.set_param_meta();
 | 
			
		||||
@ -2515,45 +2581,58 @@ int ObMPStmtExecute::parse_integer_value(const uint32_t type,
 | 
			
		||||
                                         const char *&data,
 | 
			
		||||
                                         ObObj ¶m,
 | 
			
		||||
                                         ObIAllocator &allocator,
 | 
			
		||||
                                         bool is_complex_element)
 | 
			
		||||
                                         bool is_complex_element,
 | 
			
		||||
                                         ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  bool cast_to_number = !(lib::is_mysql_mode() || is_complex_element || MYSQL_TYPE_TINY == type);
 | 
			
		||||
  int64_t res_val = 0;
 | 
			
		||||
  switch(type) {
 | 
			
		||||
    case MYSQL_TYPE_TINY: {
 | 
			
		||||
      int8_t value;
 | 
			
		||||
      ObMySQLUtil::get_int1(data, value);
 | 
			
		||||
      param.set_tinyint(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 1)
 | 
			
		||||
      {
 | 
			
		||||
        int8_t value;
 | 
			
		||||
        ObMySQLUtil::get_int1(data, value);
 | 
			
		||||
        param.set_tinyint(value);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_SHORT: {
 | 
			
		||||
      int16_t value = 0;
 | 
			
		||||
      ObMySQLUtil::get_int2(data, value);
 | 
			
		||||
      if (!cast_to_number) {
 | 
			
		||||
        param.set_smallint(value);
 | 
			
		||||
      } else {
 | 
			
		||||
        res_val = static_cast<int64_t>(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 2)
 | 
			
		||||
      {
 | 
			
		||||
        int16_t value = 0;
 | 
			
		||||
        ObMySQLUtil::get_int2(data, value);
 | 
			
		||||
        if (!cast_to_number) {
 | 
			
		||||
          param.set_smallint(value);
 | 
			
		||||
        } else {
 | 
			
		||||
          res_val = static_cast<int64_t>(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_LONG: {
 | 
			
		||||
      int32_t value = 0;
 | 
			
		||||
      ObMySQLUtil::get_int4(data, value);
 | 
			
		||||
      if (!cast_to_number) {
 | 
			
		||||
        param.set_int32(value);
 | 
			
		||||
      } else {
 | 
			
		||||
        res_val = static_cast<int64_t>(value);
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 4)
 | 
			
		||||
      {
 | 
			
		||||
        int32_t value = 0;
 | 
			
		||||
        ObMySQLUtil::get_int4(data, value);
 | 
			
		||||
        if (!cast_to_number) {
 | 
			
		||||
          param.set_int32(value);
 | 
			
		||||
        } else {
 | 
			
		||||
          res_val = static_cast<int64_t>(value);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case MYSQL_TYPE_LONGLONG: {
 | 
			
		||||
      int64_t value = 0;
 | 
			
		||||
      ObMySQLUtil::get_int8(data, value);
 | 
			
		||||
      if (!cast_to_number) {
 | 
			
		||||
        param.set_int(value);
 | 
			
		||||
      } else {
 | 
			
		||||
        res_val = value;
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 8)
 | 
			
		||||
      {
 | 
			
		||||
        int64_t value = 0;
 | 
			
		||||
        ObMySQLUtil::get_int8(data, value);
 | 
			
		||||
        if (!cast_to_number) {
 | 
			
		||||
          param.set_int(value);
 | 
			
		||||
        } else {
 | 
			
		||||
          res_val = value;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
@ -2577,7 +2656,8 @@ int ObMPStmtExecute::parse_integer_value(const uint32_t type,
 | 
			
		||||
int ObMPStmtExecute::parse_mysql_timestamp_value(const EMySQLFieldType field_type,
 | 
			
		||||
                                                 const char *&data,
 | 
			
		||||
                                                 ObObj ¶m,
 | 
			
		||||
                                                 const common::ObTimeZoneInfo *tz_info)
 | 
			
		||||
                                                 const common::ObTimeZoneInfo *tz_info,
 | 
			
		||||
                                                 ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  int8_t length = 0;
 | 
			
		||||
@ -2588,32 +2668,44 @@ int ObMPStmtExecute::parse_mysql_timestamp_value(const EMySQLFieldType field_typ
 | 
			
		||||
  int8_t min = 0;
 | 
			
		||||
  int8_t second = 0;
 | 
			
		||||
  int32_t microsecond = 0;
 | 
			
		||||
  ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
  ObPreciseDateTime value;
 | 
			
		||||
  if (0 == length) {
 | 
			
		||||
    value = 0;
 | 
			
		||||
  } else if (4 == length) {
 | 
			
		||||
    ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
  } else if (7 == length) {
 | 
			
		||||
    ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
  } else if (11 == length) {
 | 
			
		||||
    ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
    ObMySQLUtil::get_int4(data, microsecond);
 | 
			
		||||
  } else {
 | 
			
		||||
    ret = OB_ERROR;
 | 
			
		||||
    LOG_WARN("invalid mysql timestamp value length", K(length));
 | 
			
		||||
  PS_STATIC_DEFENSE_CHECK(checker, 1)
 | 
			
		||||
  {
 | 
			
		||||
    ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
    if (0 == length) {
 | 
			
		||||
      value = 0;
 | 
			
		||||
    } else if (4 == length) {
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 4)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (7 == length) {
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 7)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (11 == length) {
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 11)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int2(data, year);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, month);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, day);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
        ObMySQLUtil::get_int4(data, microsecond);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      ret = OB_ERROR;
 | 
			
		||||
      LOG_WARN("invalid mysql timestamp value length", K(length));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (OB_SUCC(ret)) {
 | 
			
		||||
@ -2665,27 +2757,34 @@ int ObMPStmtExecute::parse_mysql_timestamp_value(const EMySQLFieldType field_typ
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ObMPStmtExecute::parse_oracle_timestamp_value(const obmysql::EMySQLFieldType field_type,
 | 
			
		||||
    const char *&data, const ObTimeConvertCtx &cvrt_ctx, ObObj ¶m)
 | 
			
		||||
    const char *&data, const ObTimeConvertCtx &cvrt_ctx, ObObj ¶m, ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  int8_t total_len = 0;
 | 
			
		||||
  ObObjType obj_type;
 | 
			
		||||
  ObOTimestampData ot_data;
 | 
			
		||||
  int8_t scale = -1;
 | 
			
		||||
  ObMySQLUtil::get_int1(data, total_len);
 | 
			
		||||
  if (OB_FAIL(ObSMUtils::get_ob_type(obj_type, field_type))) {
 | 
			
		||||
  PS_STATIC_DEFENSE_CHECK(checker, 1)
 | 
			
		||||
  {
 | 
			
		||||
    ObMySQLUtil::get_int1(data, total_len);
 | 
			
		||||
  }
 | 
			
		||||
  if (OB_FAIL(ret)) {
 | 
			
		||||
  } else if (OB_FAIL(ObSMUtils::get_ob_type(obj_type, field_type))) {
 | 
			
		||||
    LOG_WARN("failed to get_ob_type", K(ret));
 | 
			
		||||
  } else if (OB_FAIL(ObTimeConverter::decode_otimestamp(obj_type, data, total_len, cvrt_ctx, ot_data, scale))) {
 | 
			
		||||
    LOG_WARN("failed to decode_otimestamp", K(ret));
 | 
			
		||||
  } else {
 | 
			
		||||
    data += total_len;
 | 
			
		||||
    param.set_otimestamp_value(obj_type, ot_data);
 | 
			
		||||
    param.set_scale(scale);
 | 
			
		||||
    PS_STATIC_DEFENSE_CHECK(checker, total_len)
 | 
			
		||||
    {
 | 
			
		||||
      data += total_len;
 | 
			
		||||
      param.set_otimestamp_value(obj_type, ot_data);
 | 
			
		||||
      param.set_scale(scale);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ObMPStmtExecute::parse_mysql_time_value(const char *&data, ObObj ¶m)
 | 
			
		||||
int ObMPStmtExecute::parse_mysql_time_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  int8_t length = 0;
 | 
			
		||||
@ -2699,44 +2798,53 @@ int ObMPStmtExecute::parse_mysql_time_value(const char *&data, ObObj ¶m)
 | 
			
		||||
  int32_t microsecond = 0;
 | 
			
		||||
  struct tm tmval;
 | 
			
		||||
  MEMSET(&tmval, 0, sizeof(tmval));
 | 
			
		||||
  ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
  int64_t value;
 | 
			
		||||
  if (0 == length) {
 | 
			
		||||
    value = 0;
 | 
			
		||||
  } else if (8 == length) {
 | 
			
		||||
    ObMySQLUtil::get_int1(data, is_negative);
 | 
			
		||||
    ObMySQLUtil::get_int4(data, day);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
  } else if (12 == length) {
 | 
			
		||||
    ObMySQLUtil::get_int1(data, is_negative);
 | 
			
		||||
    ObMySQLUtil::get_int4(data, day);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
    ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
    ObMySQLUtil::get_int4(data, microsecond);
 | 
			
		||||
  } else {
 | 
			
		||||
    ret = OB_ERR_UNEXPECTED;
 | 
			
		||||
    LOG_ERROR("unexpected time length", K(length), K(ret));
 | 
			
		||||
  }
 | 
			
		||||
  PS_STATIC_DEFENSE_CHECK(checker, 1)
 | 
			
		||||
  {
 | 
			
		||||
    ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
    if (0 == length) {
 | 
			
		||||
      value = 0;
 | 
			
		||||
    } else if (8 == length) {
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 8)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int1(data, is_negative);
 | 
			
		||||
        ObMySQLUtil::get_int4(data, day);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (12 == length) {
 | 
			
		||||
      PS_STATIC_DEFENSE_CHECK(checker, 12)
 | 
			
		||||
      {
 | 
			
		||||
        ObMySQLUtil::get_int1(data, is_negative);
 | 
			
		||||
        ObMySQLUtil::get_int4(data, day);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, hour);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, min);
 | 
			
		||||
        ObMySQLUtil::get_int1(data, second);
 | 
			
		||||
        ObMySQLUtil::get_int4(data, microsecond);
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      ret = OB_ERR_UNEXPECTED;
 | 
			
		||||
      LOG_ERROR("unexpected time length", K(length), K(ret));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (OB_SUCC(ret)) {
 | 
			
		||||
    ObTime ob_time;
 | 
			
		||||
    if (0 != length) {
 | 
			
		||||
      ob_time.parts_[DT_YEAR] = year;
 | 
			
		||||
      ob_time.parts_[DT_MON] = month;
 | 
			
		||||
      ob_time.parts_[DT_MDAY] = day;
 | 
			
		||||
      ob_time.parts_[DT_HOUR] = hour;
 | 
			
		||||
      ob_time.parts_[DT_MIN] = min;
 | 
			
		||||
      ob_time.parts_[DT_SEC] = second;
 | 
			
		||||
      ob_time.parts_[DT_USEC] = microsecond;
 | 
			
		||||
      if (!ObTimeUtility2::is_valid_time(hour, min, second, microsecond)) {
 | 
			
		||||
        ret = OB_INVALID_DATE_FORMAT;
 | 
			
		||||
        LOG_WARN("invalid date format", K(ret));
 | 
			
		||||
      } else {
 | 
			
		||||
        ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
 | 
			
		||||
        value = ObTimeConverter::ob_time_to_time(ob_time);
 | 
			
		||||
    if (OB_SUCC(ret)) {
 | 
			
		||||
      ObTime ob_time;
 | 
			
		||||
      if (0 != length) {
 | 
			
		||||
        ob_time.parts_[DT_YEAR] = year;
 | 
			
		||||
        ob_time.parts_[DT_MON] = month;
 | 
			
		||||
        ob_time.parts_[DT_MDAY] = day;
 | 
			
		||||
        ob_time.parts_[DT_HOUR] = hour;
 | 
			
		||||
        ob_time.parts_[DT_MIN] = min;
 | 
			
		||||
        ob_time.parts_[DT_SEC] = second;
 | 
			
		||||
        ob_time.parts_[DT_USEC] = microsecond;
 | 
			
		||||
        if (!ObTimeUtility2::is_valid_time(hour, min, second, microsecond)) {
 | 
			
		||||
          ret = OB_INVALID_DATE_FORMAT;
 | 
			
		||||
          LOG_WARN("invalid date format", K(ret));
 | 
			
		||||
        } else {
 | 
			
		||||
          ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time);
 | 
			
		||||
          value = ObTimeConverter::ob_time_to_time(ob_time);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -2747,7 +2855,7 @@ int ObMPStmtExecute::parse_mysql_time_value(const char *&data, ObObj ¶m)
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ObMPStmtExecute::parse_oracle_interval_ds_value(const char *&data, ObObj ¶m)
 | 
			
		||||
int ObMPStmtExecute::parse_oracle_interval_ds_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  int8_t length = 0;
 | 
			
		||||
@ -2755,18 +2863,20 @@ int ObMPStmtExecute::parse_oracle_interval_ds_value(const char *&data, ObObj &pa
 | 
			
		||||
  ObIntervalDSValue value;
 | 
			
		||||
 | 
			
		||||
  ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
 | 
			
		||||
  if (OB_FAIL(ObTimeConverter::decode_interval_ds(data, length, value, scale))) {
 | 
			
		||||
    LOG_WARN("fail to decode interval day to second", K(ret), K(length));
 | 
			
		||||
  } else {
 | 
			
		||||
    param.set_interval_ds(value);
 | 
			
		||||
    param.set_scale(scale);
 | 
			
		||||
  PS_STATIC_DEFENSE_CHECK(checker, length)
 | 
			
		||||
  {
 | 
			
		||||
    if (OB_FAIL(ObTimeConverter::decode_interval_ds(data, length, value, scale))) {
 | 
			
		||||
      LOG_WARN("fail to decode interval day to second", K(ret), K(length));
 | 
			
		||||
    } else {
 | 
			
		||||
      param.set_interval_ds(value);
 | 
			
		||||
      param.set_scale(scale);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ObMPStmtExecute::parse_oracle_interval_ym_value(const char *&data, ObObj ¶m)
 | 
			
		||||
int ObMPStmtExecute::parse_oracle_interval_ym_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker)
 | 
			
		||||
{
 | 
			
		||||
  int ret = OB_SUCCESS;
 | 
			
		||||
  int8_t length = 0;
 | 
			
		||||
@ -2774,11 +2884,14 @@ int ObMPStmtExecute::parse_oracle_interval_ym_value(const char *&data, ObObj &pa
 | 
			
		||||
  ObIntervalYMValue value;
 | 
			
		||||
 | 
			
		||||
  ObMySQLUtil::get_int1(data, length);
 | 
			
		||||
  if (OB_FAIL(ObTimeConverter::decode_interval_ym(data, length, value, scale))) {
 | 
			
		||||
    LOG_WARN("fail to decode interval year to month", K(ret), K(length));
 | 
			
		||||
  } else {
 | 
			
		||||
    param.set_interval_ym(value);
 | 
			
		||||
    param.set_scale(scale);
 | 
			
		||||
  PS_STATIC_DEFENSE_CHECK(checker, length)
 | 
			
		||||
  {
 | 
			
		||||
    if (OB_FAIL(ObTimeConverter::decode_interval_ym(data, length, value, scale))) {
 | 
			
		||||
      LOG_WARN("fail to decode interval year to month", K(ret), K(length));
 | 
			
		||||
    } else {
 | 
			
		||||
      param.set_interval_ym(value);
 | 
			
		||||
      param.set_scale(scale);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ret;
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,46 @@ enum ObPSCursorType
 | 
			
		||||
  ObPrexecutePsCursorType
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ObPSAnalysisChecker
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  ObPSAnalysisChecker()
 | 
			
		||||
    : pos_(nullptr), begin_pos_(nullptr), end_pos_(nullptr),
 | 
			
		||||
      data_len_(0), need_check_(true)
 | 
			
		||||
  {}
 | 
			
		||||
  void init(const char*& pos, const int64_t len)
 | 
			
		||||
  {
 | 
			
		||||
    pos_ = &pos;
 | 
			
		||||
    begin_pos_ = pos;
 | 
			
		||||
    end_pos_ = pos + len;
 | 
			
		||||
    data_len_ = len;
 | 
			
		||||
    need_check_ = true;
 | 
			
		||||
  }
 | 
			
		||||
  int detection(const int64_t len);
 | 
			
		||||
  inline int64_t remain_len()
 | 
			
		||||
  { return end_pos_ - (*pos_); }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  const char** pos_;
 | 
			
		||||
  const char* begin_pos_;
 | 
			
		||||
  const char* end_pos_;
 | 
			
		||||
  int64_t data_len_;
 | 
			
		||||
  bool need_check_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define PS_DEFENSE_CHECK(len)                              \
 | 
			
		||||
  if (OB_FAIL(ret)) {                                      \
 | 
			
		||||
  } else if (OB_FAIL(analysis_checker_.detection(len))) {  \
 | 
			
		||||
    LOG_WARN("memory access out of bounds", K(ret));       \
 | 
			
		||||
  } else
 | 
			
		||||
 | 
			
		||||
#define PS_STATIC_DEFENSE_CHECK(checker, len)              \
 | 
			
		||||
  if (OB_FAIL(ret)) {                                      \
 | 
			
		||||
  } else if (nullptr != checker                            \
 | 
			
		||||
    && OB_FAIL(checker->detection(len))) {                 \
 | 
			
		||||
    LOG_WARN("memory access out of bounds", K(ret));       \
 | 
			
		||||
  } else
 | 
			
		||||
 | 
			
		||||
class ObMPStmtExecute : public ObMPBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
@ -62,21 +102,25 @@ public:
 | 
			
		||||
                                    const char *& data,
 | 
			
		||||
                                    const common::ObTimeZoneInfo *tz_info,
 | 
			
		||||
                                    ObObj ¶m,
 | 
			
		||||
                                    bool is_complex_element = false);
 | 
			
		||||
                                    bool is_complex_element = false,
 | 
			
		||||
                                    ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_mysql_timestamp_value(const obmysql::EMySQLFieldType field_type,
 | 
			
		||||
                                    const char *&data,
 | 
			
		||||
                                    ObObj ¶m,
 | 
			
		||||
                                    const common::ObTimeZoneInfo *tz_info);
 | 
			
		||||
                                    const common::ObTimeZoneInfo *tz_info,
 | 
			
		||||
                                    ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_integer_value(const uint32_t type,
 | 
			
		||||
                                 const char *&data,
 | 
			
		||||
                                 ObObj ¶m,
 | 
			
		||||
                                 ObIAllocator &allocator,
 | 
			
		||||
                                 bool is_complex_element = false);
 | 
			
		||||
                                 bool is_complex_element = false,
 | 
			
		||||
                                 ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_oracle_timestamp_value(const obmysql::EMySQLFieldType field_type, const char *&data,
 | 
			
		||||
                                    const ObTimeConvertCtx &cvrt_ctx, ObObj ¶m);
 | 
			
		||||
  static int parse_mysql_time_value(const char *&data, ObObj ¶m);
 | 
			
		||||
  static int parse_oracle_interval_ym_value(const char *&data, ObObj ¶m);
 | 
			
		||||
  static int parse_oracle_interval_ds_value(const char *&data, ObObj ¶m);
 | 
			
		||||
                                    const ObTimeConvertCtx &cvrt_ctx, ObObj ¶m,
 | 
			
		||||
                                    ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_mysql_time_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_oracle_interval_ym_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  static int parse_oracle_interval_ds_value(const char *&data, ObObj ¶m, ObPSAnalysisChecker *checker = nullptr);
 | 
			
		||||
  int64_t get_single_process_timestamp() const { return single_process_timestamp_; }
 | 
			
		||||
  int64_t get_exec_start_timestamp() const { return exec_start_timestamp_; }
 | 
			
		||||
  int64_t get_exec_end_timestamp() const { return exec_end_timestamp_; }
 | 
			
		||||
@ -275,6 +319,7 @@ private:
 | 
			
		||||
  int get_pl_type_by_type_info(ObIAllocator &allocator,
 | 
			
		||||
                        const sql::TypeInfo *type_info,
 | 
			
		||||
                        const pl::ObUserDefinedType *&pl_type);
 | 
			
		||||
  bool is_contain_complex_element(const sql::ParamTypeArray ¶m_types) const;
 | 
			
		||||
 | 
			
		||||
  virtual int before_process();
 | 
			
		||||
  int response_query_header(sql::ObSQLSessionInfo &session, pl::ObDbmsCursorInfo &cursor);
 | 
			
		||||
@ -314,6 +359,7 @@ protected:
 | 
			
		||||
  int64_t params_value_len_;
 | 
			
		||||
  char *params_value_;
 | 
			
		||||
  int64_t curr_sql_idx_; // only for arraybinding
 | 
			
		||||
  ObPSAnalysisChecker analysis_checker_;
 | 
			
		||||
private:
 | 
			
		||||
  DISALLOW_COPY_AND_ASSIGN(ObMPStmtExecute);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -102,33 +102,42 @@ int ObMPStmtPrexecute::before_process()
 | 
			
		||||
    }
 | 
			
		||||
    const ObMySQLRawPacket &pkt = reinterpret_cast<const ObMySQLRawPacket&>(req_->get_packet());
 | 
			
		||||
    const char* pos = pkt.get_cdata();
 | 
			
		||||
    analysis_checker_.init(pos, pkt.get_clen());
 | 
			
		||||
    // stmt_id
 | 
			
		||||
    int32_t stmt_id = -1;
 | 
			
		||||
    ObMySQLUtil::get_int4(pos, stmt_id);
 | 
			
		||||
    stmt_id_ = stmt_id;
 | 
			
		||||
    PS_DEFENSE_CHECK(9) // stmt_id(4) + flag(1) + iteration_count(4)
 | 
			
		||||
    {
 | 
			
		||||
      ObMySQLUtil::get_int4(pos, stmt_id);
 | 
			
		||||
      stmt_id_ = stmt_id;
 | 
			
		||||
 | 
			
		||||
    // flags
 | 
			
		||||
    int8_t flag = 0;
 | 
			
		||||
    ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
      // flags
 | 
			
		||||
      int8_t flag = 0;
 | 
			
		||||
      ObMySQLUtil::get_int1(pos, flag);
 | 
			
		||||
 | 
			
		||||
    // iteration_count
 | 
			
		||||
    ObMySQLUtil::get_int4(pos, iteration_count_);
 | 
			
		||||
      // iteration_count
 | 
			
		||||
      ObMySQLUtil::get_int4(pos, iteration_count_);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // sql
 | 
			
		||||
    if (OB_SUCC(ret) && OB_FAIL(ObMySQLUtil::get_length(pos, sql_len_))) {
 | 
			
		||||
      LOG_WARN("failed to get length", K(ret));
 | 
			
		||||
    } else {
 | 
			
		||||
      sql_.assign_ptr(pos, static_cast<ObString::obstr_size_t>(sql_len_));
 | 
			
		||||
      pos += sql_len_;
 | 
			
		||||
      PS_DEFENSE_CHECK(sql_len_)
 | 
			
		||||
      {
 | 
			
		||||
        sql_.assign_ptr(pos, static_cast<ObString::obstr_size_t>(sql_len_));
 | 
			
		||||
        pos += sql_len_;
 | 
			
		||||
      }
 | 
			
		||||
      LOG_DEBUG("get sql in prexecute protocol.", K(stmt_id_), K(sql_));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // params_num
 | 
			
		||||
    int32_t num = 0;
 | 
			
		||||
    ObMySQLUtil::get_int4(pos, num);
 | 
			
		||||
    set_param_num(num);
 | 
			
		||||
 | 
			
		||||
    ObSQLSessionInfo *session = NULL;
 | 
			
		||||
    PS_DEFENSE_CHECK(4) // params_num
 | 
			
		||||
    {
 | 
			
		||||
      ObMySQLUtil::get_int4(pos, num);
 | 
			
		||||
      set_param_num(num);
 | 
			
		||||
    }
 | 
			
		||||
    if (OB_FAIL(ret)) {
 | 
			
		||||
      // do nothing
 | 
			
		||||
    } else if (OB_FAIL(get_session(session))) {
 | 
			
		||||
@ -284,49 +293,61 @@ int ObMPStmtPrexecute::before_process()
 | 
			
		||||
            if (OB_FAIL(request_params(session, pos, ps_stmt_checksum, *allocator_, params_num_))) {
 | 
			
		||||
              LOG_WARN("prepare-execute protocol get params request failed", K(ret));
 | 
			
		||||
            } else {
 | 
			
		||||
              ObMySQLUtil::get_uint4(pos, exec_mode_);
 | 
			
		||||
              //
 | 
			
		||||
              // is_commit_on_success_ is not use yet
 | 
			
		||||
              // other exec_mode set use ==
 | 
			
		||||
              is_commit_on_success_ = exec_mode_ & OB_OCI_COMMIT_ON_SUCCESS;
 | 
			
		||||
              exec_mode_ = exec_mode_ & (0xffffffff - OB_OCI_COMMIT_ON_SUCCESS);
 | 
			
		||||
              if (OB_OCI_BATCH_ERRORS == exec_mode_ && !is_pl_stmt(stmt_type_)) {
 | 
			
		||||
                set_save_exception(true);
 | 
			
		||||
              }
 | 
			
		||||
              if (OB_SUCC(ret)) {
 | 
			
		||||
                ObMySQLUtil::get_uint4(pos, close_stmt_count_);
 | 
			
		||||
                int tmp_ret = OB_SUCCESS;
 | 
			
		||||
                if (0 != close_stmt_count_) {
 | 
			
		||||
                  LOG_INFO("close stmt count:", K(close_stmt_count_), K(stmt_id_));
 | 
			
		||||
                  // OCI not support close_stmt_count_ is not 0 yet.
 | 
			
		||||
                  // for (int64_t i = 0; i < close_stmt_count_; i++) {
 | 
			
		||||
                  //   int32_t close_stmt_id = -1;
 | 
			
		||||
                  //   ObMySQLUtil::get_int4(pos, close_stmt_id);
 | 
			
		||||
                  //   if (OB_NOT_NULL(session->get_cursor(close_stmt_id))) {
 | 
			
		||||
                  //     if (OB_FAIL(session->close_cursor(close_stmt_id))) {
 | 
			
		||||
                  //       tmp_ret = ret;
 | 
			
		||||
                  //       LOG_WARN("fail to close cursor", K(ret), K(stmt_id_), K(close_stmt_id), K(session->get_sessid()));
 | 
			
		||||
                  //     }
 | 
			
		||||
                  //   }
 | 
			
		||||
                  //   if (OB_FAIL(session->close_ps_stmt(close_stmt_id))) {
 | 
			
		||||
                  //     LOG_WARN("close ps stmt fail in prepare-execute.", K(stmt_id_), K(close_stmt_id));
 | 
			
		||||
                  //   }
 | 
			
		||||
                  //   if (OB_SUCCESS != tmp_ret) {
 | 
			
		||||
                  //     ret = tmp_ret;
 | 
			
		||||
                  //   }
 | 
			
		||||
                  // }
 | 
			
		||||
              PS_DEFENSE_CHECK(4) // exec_mode
 | 
			
		||||
              {
 | 
			
		||||
                ObMySQLUtil::get_uint4(pos, exec_mode_);
 | 
			
		||||
                //
 | 
			
		||||
                // is_commit_on_success_ is not use yet
 | 
			
		||||
                // other exec_mode set use ==
 | 
			
		||||
                is_commit_on_success_ = exec_mode_ & OB_OCI_COMMIT_ON_SUCCESS;
 | 
			
		||||
                exec_mode_ = exec_mode_ & (0xffffffff - OB_OCI_COMMIT_ON_SUCCESS);
 | 
			
		||||
                if (OB_OCI_BATCH_ERRORS == exec_mode_ && !is_pl_stmt(stmt_type_)) {
 | 
			
		||||
                  set_save_exception(true);
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              if (OB_SUCC(ret)) {
 | 
			
		||||
                ObMySQLUtil::get_uint4(pos, ps_stmt_checksum);
 | 
			
		||||
                if (DEFAULT_ITERATION_COUNT == ps_stmt_checksum
 | 
			
		||||
                      || (OB_NOT_NULL(ps_session_info)
 | 
			
		||||
                          && ps_stmt_checksum != ps_session_info->get_ps_stmt_checksum())) {
 | 
			
		||||
                    ret = OB_ERR_PREPARE_STMT_CHECKSUM;
 | 
			
		||||
                    LOG_ERROR("ps stmt checksum fail", K(ret), "session_id", session->get_sessid(),
 | 
			
		||||
                                                    K(ps_stmt_checksum), K(*ps_session_info));
 | 
			
		||||
                } else {
 | 
			
		||||
                    ObMySQLUtil::get_uint4(pos, extend_flag_);
 | 
			
		||||
                PS_DEFENSE_CHECK(4) // close stmt count
 | 
			
		||||
                {
 | 
			
		||||
                  ObMySQLUtil::get_uint4(pos, close_stmt_count_);
 | 
			
		||||
                  int tmp_ret = OB_SUCCESS;
 | 
			
		||||
                  if (0 != close_stmt_count_) {
 | 
			
		||||
                    LOG_INFO("close stmt count:", K(close_stmt_count_), K(stmt_id_));
 | 
			
		||||
                    // OCI not support close_stmt_count_ is not 0 yet.
 | 
			
		||||
                    // for (int64_t i = 0; i < close_stmt_count_; i++) {
 | 
			
		||||
                    //   int32_t close_stmt_id = -1;
 | 
			
		||||
                    //   ObMySQLUtil::get_int4(pos, close_stmt_id);
 | 
			
		||||
                    //   if (OB_NOT_NULL(session->get_cursor(close_stmt_id))) {
 | 
			
		||||
                    //     if (OB_FAIL(session->close_cursor(close_stmt_id))) {
 | 
			
		||||
                    //       tmp_ret = ret;
 | 
			
		||||
                    //       LOG_WARN("fail to close cursor", K(ret), K(stmt_id_), K(close_stmt_id), K(session->get_sessid()));
 | 
			
		||||
                    //     }
 | 
			
		||||
                    //   }
 | 
			
		||||
                    //   if (OB_FAIL(session->close_ps_stmt(close_stmt_id))) {
 | 
			
		||||
                    //     LOG_WARN("close ps stmt fail in prepare-execute.", K(stmt_id_), K(close_stmt_id));
 | 
			
		||||
                    //   }
 | 
			
		||||
                    //   if (OB_SUCCESS != tmp_ret) {
 | 
			
		||||
                    //     ret = tmp_ret;
 | 
			
		||||
                    //   }
 | 
			
		||||
                    // }
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              if (OB_SUCC(ret)) {
 | 
			
		||||
                PS_DEFENSE_CHECK(4) // checksum
 | 
			
		||||
                {
 | 
			
		||||
                  ObMySQLUtil::get_uint4(pos, ps_stmt_checksum);
 | 
			
		||||
                  if (DEFAULT_ITERATION_COUNT == ps_stmt_checksum
 | 
			
		||||
                        || (OB_NOT_NULL(ps_session_info)
 | 
			
		||||
                            && ps_stmt_checksum != ps_session_info->get_ps_stmt_checksum())) {
 | 
			
		||||
                      ret = OB_ERR_PREPARE_STMT_CHECKSUM;
 | 
			
		||||
                      LOG_ERROR("ps stmt checksum fail", K(ret), "session_id", session->get_sessid(),
 | 
			
		||||
                                                      K(ps_stmt_checksum), K(*ps_session_info));
 | 
			
		||||
                  } else {
 | 
			
		||||
                    PS_DEFENSE_CHECK(4) // extend_flag
 | 
			
		||||
                    {
 | 
			
		||||
                      ObMySQLUtil::get_uint4(pos, extend_flag_);
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
              if (OB_FAIL(ret)) {
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -2238,6 +2238,7 @@ DEFINE_ERROR_EXT(OB_ERR_SP_NO_DROP_SP, -9743, ER_SP_NO_DROP_SP, "HY000", "Can't
 | 
			
		||||
DEFINE_ORACLE_ERROR(OB_ERR_RECOMPILATION_OBJECT, -9744, -1, "HY000", "errors during recompilation/revalidation of object", 4045, "errors during recompilation/revalidation of %.*s.%.*s");
 | 
			
		||||
DEFINE_ORACLE_ERROR(OB_ERR_VARIABLE_NOT_IN_SELECT_LIST, -9745, -1, "HY000", "variable not in select list", 1007, "variable not in select list");
 | 
			
		||||
DEFINE_ORACLE_ERROR(OB_ERR_MULTI_RECORD, -9746, -1, "HY000", "coercion into multiple record targets not supported", 494, "coercion into multiple record targets not supported");
 | 
			
		||||
DEFINE_ERROR(OB_ERR_MALFORMED_PS_PACKET, -9747, -1, "HY000", "malformed ps packet");
 | 
			
		||||
////////////////////////////////////////////////////////////////
 | 
			
		||||
// !!! text/blob || clob/blob erro code
 | 
			
		||||
// for compat we cant not remove this errno!!!!
 | 
			
		||||
 | 
			
		||||
@ -1698,6 +1698,7 @@ constexpr int OB_ERR_SP_NO_DROP_SP = -9743;
 | 
			
		||||
constexpr int OB_ERR_RECOMPILATION_OBJECT = -9744;
 | 
			
		||||
constexpr int OB_ERR_VARIABLE_NOT_IN_SELECT_LIST = -9745;
 | 
			
		||||
constexpr int OB_ERR_MULTI_RECORD = -9746;
 | 
			
		||||
constexpr int OB_ERR_MALFORMED_PS_PACKET = -9747;
 | 
			
		||||
constexpr int OB_SP_RAISE_APPLICATION_ERROR = -20000;
 | 
			
		||||
constexpr int OB_SP_RAISE_APPLICATION_ERROR_NUM = -21000;
 | 
			
		||||
constexpr int OB_CLOB_ONLY_SUPPORT_WITH_MULTIBYTE_FUN = -22998;
 | 
			
		||||
@ -3739,6 +3740,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219;
 | 
			
		||||
#define OB_ERR_RECOMPILATION_OBJECT__USER_ERROR_MSG "errors during recompilation/revalidation of object"
 | 
			
		||||
#define OB_ERR_VARIABLE_NOT_IN_SELECT_LIST__USER_ERROR_MSG "variable not in select list"
 | 
			
		||||
#define OB_ERR_MULTI_RECORD__USER_ERROR_MSG "coercion into multiple record targets not supported"
 | 
			
		||||
#define OB_ERR_MALFORMED_PS_PACKET__USER_ERROR_MSG "malformed ps packet"
 | 
			
		||||
#define OB_SP_RAISE_APPLICATION_ERROR__USER_ERROR_MSG "%.*s"
 | 
			
		||||
#define OB_SP_RAISE_APPLICATION_ERROR_NUM__USER_ERROR_MSG "error number argument to raise_application_error of '%d' is out of range"
 | 
			
		||||
#define OB_CLOB_ONLY_SUPPORT_WITH_MULTIBYTE_FUN__USER_ERROR_MSG "CLOB or NCLOB in multibyte character set not supported"
 | 
			
		||||
@ -5780,6 +5782,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219;
 | 
			
		||||
#define OB_ERR_RECOMPILATION_OBJECT__ORA_USER_ERROR_MSG "ORA-04045: errors during recompilation/revalidation of %.*s.%.*s"
 | 
			
		||||
#define OB_ERR_VARIABLE_NOT_IN_SELECT_LIST__ORA_USER_ERROR_MSG "ORA-01007: variable not in select list"
 | 
			
		||||
#define OB_ERR_MULTI_RECORD__ORA_USER_ERROR_MSG "ORA-00494: coercion into multiple record targets not supported"
 | 
			
		||||
#define OB_ERR_MALFORMED_PS_PACKET__ORA_USER_ERROR_MSG "ORA-00600: internal error code, arguments: -9747, malformed ps packet"
 | 
			
		||||
#define OB_SP_RAISE_APPLICATION_ERROR__ORA_USER_ERROR_MSG "ORA%06ld: %.*s"
 | 
			
		||||
#define OB_SP_RAISE_APPLICATION_ERROR_NUM__ORA_USER_ERROR_MSG "ORA-21000: error number argument to raise_application_error of '%d' is out of range"
 | 
			
		||||
#define OB_CLOB_ONLY_SUPPORT_WITH_MULTIBYTE_FUN__ORA_USER_ERROR_MSG "ORA-22998: CLOB or NCLOB in multibyte character set not supported"
 | 
			
		||||
@ -5790,7 +5793,7 @@ constexpr int OB_ERR_INVALID_DATE_MSG_FMT_V2 = -4219;
 | 
			
		||||
#define OB_ERR_DATA_TOO_LONG_MSG_FMT_V2__ORA_USER_ERROR_MSG "ORA-12899: value too large for column %.*s (actual: %ld, maximum: %ld)"
 | 
			
		||||
#define OB_ERR_INVALID_DATE_MSG_FMT_V2__ORA_USER_ERROR_MSG "ORA-01861: Incorrect datetime value for column '%.*s' at row %ld"
 | 
			
		||||
 | 
			
		||||
extern int g_all_ob_errnos[2037];
 | 
			
		||||
extern int g_all_ob_errnos[2038];
 | 
			
		||||
 | 
			
		||||
  const char *ob_error_name(const int oberr);
 | 
			
		||||
  const char* ob_error_cause(const int oberr);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user