/** * Copyright (c) 2021 OceanBase * OceanBase CE 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 SQL_ENG #include #include "sql/parser/ob_item_type.h" #include "sql/engine/expr/ob_expr_inet.h" #include "sql/engine/ob_exec_context.h" using namespace oceanbase::common; namespace oceanbase { namespace sql { int ObExprInetCommon::str_to_ipv4(int len, const char *str, bool& is_ip_format_invalid, in_addr* ipv4addr) { is_ip_format_invalid = false; int ret = OB_SUCCESS; //Shortest IPv4 address:"x.x.x.x",length:7 if (7 > len || INET_ADDRSTRLEN - 1 < len) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, too short or too long", K(len)); } else if (OB_UNLIKELY(OB_UNLIKELY(OB_ISNULL(str) || OB_ISNULL(ipv4addr)))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ip_str or ipv4addr is null", K(ret), K(str), K(ipv4addr)); } else { unsigned char byte_addr[4]; memset(byte_addr,0,sizeof(byte_addr)); int dotcnt = 0, numcnt = 0; int byte = 0; char c; for (int i = 0; !is_ip_format_invalid && i < len && *(i + str); ++i) { c = *(i + str); if ('.' == c) { if (255 < byte) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(byte)); } else if (0 == numcnt || 3 < numcnt) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, group num count invalid", K(numcnt), K(dotcnt)); } else if (i == len - 1 || !*(i + str + 1)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, end with '.'", K(i)); } else { byte_addr[dotcnt] = (unsigned char) byte; } dotcnt ++; if (3 < dotcnt) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, too much '.'", K(dotcnt), K(i)); } else { } byte = 0; numcnt = 0; } else if ('9' >= c && '0' <= c) { byte = byte * 10 + c - '0'; numcnt ++; } else { is_ip_format_invalid = true; LOG_WARN("ip format invalid, invalid number", K(c), K(i)); } } if (255 < byte) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(byte)); } else if (3 != dotcnt) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, number of '.' is not 3", K(dotcnt)); } else if ('.' == c) { // IP number can't end on '.' is_ip_format_invalid = true; LOG_WARN("ip format invalid, end with '.'"); } else { byte_addr[3] = (unsigned char) byte; } MEMCPY((unsigned char *) ipv4addr, byte_addr, sizeof(in_addr)); } return ret; } int ObExprInetCommon::str_to_ipv6(int len, const char *str, bool& is_ip_format_invalid, in6_addr* ipv6addr) { int ret = OB_SUCCESS; is_ip_format_invalid = false; //Ipv6 length of mysql support: 2~39 //Shortest IPv6 address:"::",length:2 if (2 > len || INET6_ADDRSTRLEN - 1 < len) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, too short or too long", K(len)); } else if (OB_UNLIKELY(OB_ISNULL(str) || OB_ISNULL(ipv6addr))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ip_str or ipv6addr is null", K(ret), K(str), K(ipv6addr)); } else { int dst_index = 0; char c; int group = 0, num = 0; int numcnt = 0; int group_start = 0; int gap_index = -1; int i = 0; uint8_t ip_addr[sizeof(in6_addr)]; MEMSET(ip_addr, 0, sizeof(in6_addr)); if (':' == str[0]) { if (':' == str[1]) { i = 1; } else { //cannot start with ":x" is_ip_format_invalid = true; LOG_WARN("ip format invalid, start with :x", K(str[1])); } } else { } for (; !is_ip_format_invalid && i < len && str[i]; ++i) { c = str[i]; if (':' == c) { group_start = i + 1; if (0 == numcnt) { if (-1 == gap_index) { gap_index = dst_index; } else { //number of "::" greater than 1 is_ip_format_invalid = true; LOG_WARN("ip format invalid, too much '::'", K(gap_index), K(i)); } } else if (i >= len || !str[i+1]) { // cannot end with "x:" is_ip_format_invalid = true; LOG_WARN("ip format invalid, end with x:", K(i)); } else if (dst_index + 2 > sizeof(in6_addr)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(i), K(dst_index)); } else { ip_addr[dst_index] = (unsigned char) (group >> 8) & 0xff; ip_addr[dst_index + 1] = (unsigned char) group & 0xff; dst_index += 2; group = 0; numcnt = 0; } } else if ('.' == c) { if (dst_index + sizeof(in_addr) > sizeof(in6_addr)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, no room for ipv4", K(dst_index), K(i)); } else if (OB_FAIL(str_to_ipv4(len - group_start, str + group_start, is_ip_format_invalid, (in_addr *)(ip_addr + dst_index)))) { LOG_WARN("fail to excute str_to_ipv4", K(ret)); } else if (is_ip_format_invalid) { LOG_WARN("ipv4 format invalid", K(group_start)); } else { numcnt = 0; dst_index += 4; } break; } else { numcnt++; if (4 < numcnt) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, too many numbers in one group", K(numcnt), K(i)); } else { if ('0' <= c && '9' >= c) { num = c - '0'; } else if ('a' <= c && 'f' >= c) { num = c - 'a' + 10; } else if ('A' <= c && 'F' >= c) { num = c - 'A' + 10; } else { is_ip_format_invalid = true; LOG_WARN("ip format invalid, invaild number", K(c), K(i)); } group = (group << 4) | num; } } } if (!is_ip_format_invalid) { if (0 != numcnt) { //add last group: ":xxxx" if (dst_index + 2 > sizeof(in6_addr)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, too many groups", K(dst_index), K(i)); } else { ip_addr[dst_index] = (unsigned char) (group >> 8) & 0xff; ip_addr[dst_index+1] = (unsigned char) group & 0xff; dst_index += 2; } } else { } if (-1 != gap_index) { if (dst_index == sizeof(in6_addr)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid, no room for ::", K(gap_index)); } else { int to_move = dst_index - gap_index; for (int i = 1; i <= to_move; ++i) { ip_addr[sizeof(in6_addr) - i] = ip_addr[gap_index + to_move - i]; ip_addr[gap_index + to_move - i] = 0; } } } else if (dst_index != sizeof(in6_addr)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(dst_index),K(sizeof(in6_addr))); } else { } MEMCPY(ipv6addr, ip_addr, sizeof(in6_addr)); } } return ret; } int ObExprInetCommon::ip_to_str(ObString& ip_binary, bool& is_ip_format_invalid, ObString& ip_str) { is_ip_format_invalid = false; int ret = OB_SUCCESS; const char *ip = ip_binary.ptr(); char * result_ptr = ip_str.ptr(); char result[common::MAX_IP_ADDR_LENGTH]; if (OB_UNLIKELY(OB_ISNULL(ip) || OB_ISNULL(result_ptr))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("ip or result is null", K(ret), K(ip), K(result)); }else if (sizeof(in_addr) == ip_binary.length()) { const unsigned char *ipv4_groups = (const unsigned char *) ip; sprintf((char *)result_ptr, "%d.%d.%d.%d", ipv4_groups[0], ipv4_groups[1], ipv4_groups[2], ipv4_groups[3]); ip_str.assign(result_ptr, static_cast(strlen(result_ptr))); } else if (sizeof(in6_addr) == ip_binary.length()) { int gap = -1, gap_len = -1; int rg = -1, rg_len = -1; const uint16_t *ipv6_binary = (const uint16_t *) ip; uint16_t ipv6_groups[8]; for (int i= 0; i < 8; ++i) { ipv6_groups[i] = (ipv6_binary[i] << 8) | ((ipv6_binary[i] >> 8) & 0xff); } //find longest gap for (int i = 0; i < 8; ++i) { if (0 == ipv6_groups[i]) { if (-1 == rg_len) { rg_len = 1; rg = i; } else { rg_len++; } } else { if (rg_len > gap_len) { gap = rg; gap_len = rg_len; } else { } rg_len = -1; } } if (rg_len > gap_len) { gap = rg; gap_len = rg_len; } else { } char *p = &result[0]; for (int i = 0; i < 8; ++i) { if (gap == i) { if (0 == i) { *p = ':'; ++p; } else { } *p = ':'; ++p; i += gap_len - 1; //skip gap } else if (6 == i && 0 == gap && (6 == gap_len || // IPv4-compatible (5 == gap_len && 0xffff == ipv6_groups[5]) // IPv4-mapped )) { const unsigned char *ipv4_groups = (const unsigned char *) ip + 12; p += sprintf(p, "%d.%d.%d.%d", ipv4_groups[0], ipv4_groups[1], ipv4_groups[2], ipv4_groups[3]); break; } else { p += sprintf(p, "%x", ipv6_groups[i]); if (i != 7) { *p = ':'; ++p; } } } *p = '\0'; int len = static_cast(strlen(result)); MEMCPY(result_ptr, result, len); ip_str.assign(result_ptr, len); } else { is_ip_format_invalid = true; LOG_WARN("invalid ip length", K(ip_binary.length())); } return ret; } ObExprInetAton::ObExprInetAton(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_INETATON, N_INETATON, 1, NOT_ROW_DIMENSION) {} ObExprInetAton::~ObExprInetAton() {} int ObExprInetAton::calc(ObObj& result, const ObObj& text, uint64_t cast_mode) { int ret = OB_SUCCESS; if (text.is_null()) { result.set_null(); } else { ObString m_text = text.get_string(); bool is_ip_format_invalid = false; if (OB_FAIL(ob_inet_aton(result, m_text, is_ip_format_invalid))) { LOG_WARN("fail to excute ob_inet_aton", K(ret)); } else if (is_ip_format_invalid) { if (CM_IS_WARN_ON_FAIL(cast_mode)) { result.set_null(); } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("ip format invalid", K(ret), K(m_text)); } } } return ret; } int ObExprInetAton::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; uint64_t cast_mode = 0; ObSQLSessionInfo* session = expr_ctx.my_session_; if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (OB_FAIL(calc(result, text, cast_mode))) { LOG_WARN("fail to calc", K(ret)); } else if (OB_LIKELY(!result.is_null())) { result.set_collation_type(result_type_.get_collation_type()); result.set_collation_level(result_type_.get_collation_level()); } else { } } return ret; } template int ObExprInetAton::ob_inet_aton(T& result, const ObString& text, bool& is_ip_format_invalid) { int ret = OB_SUCCESS; is_ip_format_invalid = false; if (text.empty()) { is_ip_format_invalid = true; LOG_WARN("ip length is zero"); } else { int len = text.length(); char c; int cnt = 0; unsigned long value = 0; int byte = 0; for (int i = 0; !is_ip_format_invalid && i < len; ++i) { c = text.ptr()[i]; if ('0' <= c && '9' >= c) { byte = byte * 10 + c - '0'; if (255 < byte) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(byte), K(text)); } else { } } else if ('.' == c) { cnt++; value = (value << 8) + byte; byte = 0; } else { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(c), K(text)); } } if (is_ip_format_invalid) { } else if (3 < cnt || '.' == c) { // IP number can't end on '.', '.' count <= 3 is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(text), K(cnt), K(c)); } else { /* Attempt to support short forms of IP-addresses. Examples: 127 -> 0.0.0.127 127.255 -> 127.0.0.255 127.256 -> NULL 127.2.1 -> 127.2.0.1 */ if (2 == cnt) { value <<= 8; } else if (1 == cnt) { value <<= 16; } else { } value = (value << 8) + byte; result.set_int(value); } } return ret; } int ObExprInetAton::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (rt_expr.arg_cnt_ != 1) { ret = OB_INVALID_ARGUMENT; LOG_WARN("inet_aton expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of inet_aton expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprInetAton::calc_inet_aton; } return ret; } int ObExprInetAton::calc_inet_aton(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("inet_aton expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); if (text.is_null()) { expr_datum.set_null(); } else { ObString m_text = text.get_string(); bool is_ip_format_invalid = false; if (OB_FAIL(ob_inet_aton(expr_datum, m_text, is_ip_format_invalid))) { LOG_WARN("fail to excute ob_inet_aton", K(ret)); }else if (is_ip_format_invalid) { uint64_t cast_mode = 0; ObSQLSessionInfo* session = ctx.exec_ctx_.get_my_session(); if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (CM_IS_WARN_ON_FAIL(cast_mode)) { //support no strict sql_mode expr_datum.set_null(); } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("fail to convert ip to int", K(ret), K(m_text)); } } } } } return ret; } ObExprInet6Ntoa::ObExprInet6Ntoa(ObIAllocator& alloc) : ObStringExprOperator(alloc, T_FUN_SYS_INET6NTOA, N_INET6NTOA, 1) {} ObExprInet6Ntoa::~ObExprInet6Ntoa() {} inline int ObExprInet6Ntoa::calc_result_type1( ObExprResType& type, ObExprResType& text, common::ObExprTypeCtx& type_ctx) const { int ret = OB_SUCCESS; UNUSED(text); type.set_varchar(); type.set_length(common::MAX_IP_ADDR_LENGTH); type.set_collation_level(common::CS_LEVEL_COERCIBLE); const sql::ObSQLSessionInfo *session = type_ctx.get_session(); if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is null",K(ret)); } else { type.set_collation_type(get_default_collation_type(type.get_type(), *type_ctx.get_session())); } return ret; } int ObExprInet6Ntoa::calc(ObObj& result, const ObObj& text, common::ObExprStringBuf& string_buf, uint64_t cast_mode) { int ret = OB_SUCCESS; bool is_ip_format_invalid = false; if (text.is_null()) { result.set_null(); } else if (!text.is_varbinary()) { is_ip_format_invalid = true; LOG_WARN("ip is not binary", K(ret), K(text)); } else { ObString num_val = text.get_varbinary(); char *buf = static_cast(string_buf.alloc(MAX_IP_ADDR_LENGTH)); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc memory failed", K(ret), K(text)); } else { ObString ip_str(MAX_IP_ADDR_LENGTH, 0, buf); ObExprInetCommon::ip_to_str(num_val, is_ip_format_invalid, ip_str); result.set_varchar(ip_str); } } if (OB_SUCC(ret) && is_ip_format_invalid) { if (CM_IS_WARN_ON_FAIL(cast_mode)) { result.set_null(); } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("ip format invalid", K(ret), K(text)); } } return ret; } int ObExprInet6Ntoa::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; uint64_t cast_mode = 0; ObSQLSessionInfo* session = expr_ctx.my_session_; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (OB_FAIL(calc(result, text, *expr_ctx.calc_buf_, cast_mode))) { LOG_WARN("fail to calc", K(ret)); } else if (OB_LIKELY(!result.is_null())) { result.set_collation_type(result_type_.get_collation_type()); result.set_collation_level(result_type_.get_collation_level()); } else { } } return ret; } int ObExprInet6Ntoa::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("inet6_ntoa expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of inet6_ntoa expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprInet6Ntoa::calc_inet6_ntoa; } return ret; } int ObExprInet6Ntoa::calc_inet6_ntoa(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("inet6_ntoa expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); if (text.is_null()) { expr_datum.set_null(); } else { char * buf = NULL; CK(expr.res_buf_len_ >= MAX_IP_ADDR_LENGTH); if (OB_FAIL(ret)) { LOG_WARN("result buf size greater than MAX_IP_ADDR_LENGTH", K(ret)); } else if (OB_ISNULL(buf = expr.get_str_res_mem(ctx, MAX_IP_ADDR_LENGTH))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to allocate memory for lob locator", K(ret), K(MAX_IP_ADDR_LENGTH)); } else { bool is_ip_format_invalid = false; ObString num_val = text.get_string(); ObString ip_str(MAX_IP_ADDR_LENGTH, 0, buf); if (!ob_is_varbinary_type(expr.args_[0]->datum_meta_.type_,expr.args_[0]->datum_meta_.cs_type_)) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(ret), K(text)); } else if (OB_FAIL(ObExprInetCommon::ip_to_str(num_val, is_ip_format_invalid, ip_str))) { LOG_WARN("fail to excute ip_to_str", K(ret)); } else if (!is_ip_format_invalid) { expr_datum.set_string(ip_str); } if (OB_SUCC(ret) && is_ip_format_invalid) { uint64_t cast_mode = 0; ObSQLSessionInfo* session = ctx.exec_ctx_.get_my_session(); if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (CM_IS_WARN_ON_FAIL(cast_mode)) { expr_datum.set_null(); //support no strict sql_mode } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("ip format invalid", K(ret),K(text)); } } } } } } return ret; } ObExprInet6Aton::ObExprInet6Aton(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_INET6ATON, N_INET6ATON, 1, NOT_ROW_DIMENSION) {} ObExprInet6Aton::~ObExprInet6Aton() {} int ObExprInet6Aton::calc(ObObj& result, const ObObj& text, common::ObExprStringBuf& string_buf, uint64_t cast_mode) { int ret = OB_SUCCESS; if (text.is_null()) { result.set_null(); } else { ObString num_val = text.get_varbinary(); char *buf = static_cast(string_buf.alloc(sizeof(in6_addr))); if (OB_ISNULL(buf)) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("alloc memory failed", K(ret), K(text)); } else { bool is_ip_format_invalid = false; ObString m_text = text.get_string(); ObString result_buf(sizeof(in6_addr), 0, buf); if (OB_FAIL(inet6_aton(m_text, is_ip_format_invalid, result_buf))) { LOG_WARN("fail to excute inet6_aton"); } else if (is_ip_format_invalid) { if (CM_IS_WARN_ON_FAIL(cast_mode)) { result.set_null(); //support no strict mode } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("ip format invalid", K(ret), K(m_text)); } } else { result.set_varbinary(result_buf); } } } return ret; } int ObExprInet6Aton::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; uint64_t cast_mode = 0; ObSQLSessionInfo* session = expr_ctx.my_session_; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else if (OB_UNLIKELY(OB_ISNULL(session))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (OB_FAIL(calc(result, text, *expr_ctx.calc_buf_, cast_mode))) { LOG_WARN("fail to calc", K(ret)); } else if (OB_LIKELY(!result.is_null())) { result.set_collation_type(result_type_.get_collation_type()); result.set_collation_level(result_type_.get_collation_level()); } else { } } return ret; } int ObExprInet6Aton::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("inet6_aton expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of inet6_aton expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprInet6Aton::calc_inet6_aton; } return ret; } int ObExprInet6Aton::calc_inet6_aton(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("inet6_ntoa expr eval param value failed", K(ret)); } else { char * buf = NULL; CK(expr.res_buf_len_ >= sizeof(in6_addr)); if (OB_FAIL(ret)) { LOG_WARN("result buf size greater than sizeof(in6_addr)", K(ret)); } else if (OB_ISNULL(buf = expr.get_str_res_mem(ctx, sizeof(in6_addr)))) { ret = OB_ALLOCATE_MEMORY_FAILED; LOG_WARN("Failed to allocate memory for lob locator", K(ret), K(sizeof(in6_addr))); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); ObString m_text = text.get_string(); bool is_ip_format_invalid = false; if (text.is_null()) { expr_datum.set_null(); } else { ObString str_result(sizeof(in6_addr), 0, buf); if (OB_FAIL(inet6_aton(m_text, is_ip_format_invalid, str_result))) { LOG_WARN("fail to excute inet6_aton", K(ret)); } else if (is_ip_format_invalid) { uint64_t cast_mode = 0; ObSQLSessionInfo* session = ctx.exec_ctx_.get_my_session(); if (OB_ISNULL(session)) { LOG_WARN("session is NULL", K(ret)); } else { ObSQLUtils::get_default_cast_mode(session->get_stmt_type(), session, cast_mode); if (CM_IS_WARN_ON_FAIL(cast_mode)) { expr_datum.set_null(); //support no strict mode } else { ret = OB_INVALID_ARGUMENT; LOG_WARN("ip format invalid", K(ret)); } } } else { expr_datum.set_string(str_result); } } } } return ret; } int ObExprInet6Aton::inet6_aton(const ObString& ip, bool& is_ip_format_invalid, ObString& str_result) { is_ip_format_invalid = false; int ret = OB_SUCCESS; char buf[MAX_IP_ADDR_LENGTH]; if (INET6_ADDRSTRLEN - 1 < ip.length()) { is_ip_format_invalid = true; LOG_WARN("ip format invalid", K(ip)); } else { char *result_buf = str_result.ptr(); if (OB_UNLIKELY(OB_ISNULL(result_buf))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("result_buf is null", K(ret)); } else { MEMCPY(buf, ip.ptr(), ip.length()); buf[ip.length()] = '\0'; if (OB_FAIL(ObExprInetCommon::str_to_ipv4(ip.length(), buf, is_ip_format_invalid, (in_addr *)result_buf))) { LOG_WARN("fail to excute str_to_ipv4", K(ret)); }else if (is_ip_format_invalid) { if (OB_FAIL(ObExprInetCommon::str_to_ipv6(ip.length(), buf, is_ip_format_invalid, (in6_addr *)result_buf))) { LOG_WARN("fail to excute str_to_ipv6", K(ret)); } else if (is_ip_format_invalid) { LOG_WARN("ip format invalid", K(ip)); } else { str_result.assign(result_buf, sizeof(in6_addr)); } } else { str_result.assign(result_buf, sizeof(in_addr)); } } } return ret; } ObExprIsIpv4::ObExprIsIpv4(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_IS_IPV4, N_IS_IPV4, 1, NOT_ROW_DIMENSION) {} ObExprIsIpv4::~ObExprIsIpv4() {} int ObExprIsIpv4::calc(ObObj& result, const ObObj& text) { int ret = OB_SUCCESS; if (text.is_null()) { result.set_int(0); } else { ObString m_text = text.get_string(); if (OB_FAIL(is_ipv4(result, m_text))) { LOG_WARN("fail to excute is_ipv4", K(ret)); } } return ret; } int ObExprIsIpv4::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else if (OB_FAIL(calc(result, text))) { LOG_WARN("fail to excute calc", K(ret)); } return ret; } template int ObExprIsIpv4::is_ipv4(T& result, const ObString& text) { char buf[16]; int ipv4_ret = 1; int ret = OB_SUCCESS; if (INET_ADDRSTRLEN - 1 < text.length()) { ipv4_ret = 0; } else { MEMCPY(buf, text.ptr(), text.length()); int len = text.length(); buf[len] = '\0'; struct in_addr addr; bool is_ip_invalid; if (OB_FAIL(ObExprInetCommon::str_to_ipv4(len, buf, is_ip_invalid, &addr))) { LOG_WARN("fail to excute str_to_ipv4"); } else { ipv4_ret = is_ip_invalid ? 0 : 1; } } result.set_int(ipv4_ret); return ret; } int ObExprIsIpv4::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("is_ipv4 expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0])))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of is_ipv4 expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprIsIpv4::calc_is_ipv4; } return ret; } int ObExprIsIpv4::calc_is_ipv4(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("is_ipv4 expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); ObString m_text = text.get_string(); if (text.is_null()) { expr_datum.set_int(0); } else if (OB_FAIL(is_ipv4(expr_datum, m_text))) { LOG_WARN("fail to excute is_ipv4", K(ret)); } else { } } return ret; } ObExprIsIpv4Mapped::ObExprIsIpv4Mapped(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_IS_IPV4_MAPPED, N_IS_IPV4_MAPPED, 1, NOT_ROW_DIMENSION) {} ObExprIsIpv4Mapped::~ObExprIsIpv4Mapped() {} void ObExprIsIpv4Mapped::calc(ObObj& result, const ObObj& text) { if (text.is_null()) { result.set_int(0); } else if (!text.is_varbinary()) { result.set_int(0); } else { ObString m_text = text.get_varbinary(); is_ipv4_mapped(result, m_text); } } int ObExprIsIpv4Mapped::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else { calc(result, text); } return ret; } int ObExprIsIpv4Mapped::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("is_ipv4_mapped expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of is_ipv4_mapped expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprIsIpv4Mapped::calc_is_ipv4_mapped; } return ret; } int ObExprIsIpv4Mapped::calc_is_ipv4_mapped(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("is_ipv4_mapped expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); if (text.is_null()) { expr_datum.set_int(0); } else if (!ob_is_varbinary_type(expr.args_[0]->datum_meta_.type_,expr.args_[0]->datum_meta_.cs_type_)) { expr_datum.set_int(0); } else { ObString m_text = text.get_string(); is_ipv4_mapped(expr_datum, m_text); } } return ret; } template void ObExprIsIpv4Mapped::is_ipv4_mapped(T& result, const ObString& num_val) { char buf[16]; int ipv4_ret = 1; if (sizeof(in6_addr) != num_val.length()) { //length of binary ipv6 addr is 16 ipv4_ret = 0; } else { MEMCPY(buf, num_val.ptr(), num_val.length()); ipv4_ret = IN6_IS_ADDR_V4MAPPED((struct in6_addr *) buf); } result.set_int(ipv4_ret); } ObExprIsIpv4Compat::ObExprIsIpv4Compat(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_IS_IPV4_COMPAT, N_IS_IPV4_COMPAT, 1, NOT_ROW_DIMENSION) {} ObExprIsIpv4Compat::~ObExprIsIpv4Compat() {} void ObExprIsIpv4Compat::calc(ObObj& result, const ObObj& text) { if (text.is_null()) { result.set_int(0); } else if (!text.is_varbinary()) { result.set_int(0); } else { ObString m_text = text.get_varbinary(); is_ipv4_compat(result, m_text); } } int ObExprIsIpv4Compat::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else { calc(result, text); } return ret; } int ObExprIsIpv4Compat::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("is_ipv4_compat expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of is_ipv4_compat expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprIsIpv4Compat::calc_is_ipv4_compat; } return ret; } int ObExprIsIpv4Compat::calc_is_ipv4_compat(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("is_ipv4_compat expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); if (text.is_null()) { expr_datum.set_int(0); } else if (!ob_is_varbinary_type(expr.args_[0]->datum_meta_.type_, expr.args_[0]->datum_meta_.cs_type_)) { expr_datum.set_int(0); } else { ObString m_text = text.get_string(); is_ipv4_compat(expr_datum, m_text); } } return ret; } template void ObExprIsIpv4Compat::is_ipv4_compat(T& result, const ObString& num_val) { char buf[16]; int ipv4_ret = 1; if (sizeof(in6_addr) != num_val.length()) { //length of binary ipv6 addr is 16 ipv4_ret = 0; } else { MEMCPY(buf, num_val.ptr(), num_val.length()); ipv4_ret = IN6_IS_ADDR_V4COMPAT((struct in6_addr *) buf); } result.set_int(ipv4_ret); } ObExprIsIpv6::ObExprIsIpv6(ObIAllocator& alloc) : ObFuncExprOperator(alloc, T_FUN_SYS_IS_IPV6, N_IS_IPV6, 1, NOT_ROW_DIMENSION) {} ObExprIsIpv6::~ObExprIsIpv6() {} int ObExprIsIpv6::calc(ObObj& result, const ObObj& text) { int ret = OB_SUCCESS; if (text.is_null()) { result.set_int(0); } else { ObString m_text = text.get_string(); if (OB_FAIL(is_ipv6(result, m_text))) { LOG_WARN("fail to excute is_ipv6", K(ret)); } } return ret; } int ObExprIsIpv6::calc_result1(ObObj& result, const ObObj& text, ObExprCtx& expr_ctx) const { int ret = OB_SUCCESS; if (OB_ISNULL(expr_ctx.calc_buf_)) { ret = OB_NOT_INIT; LOG_WARN("varchar buffer not init", K(ret)); } else if (OB_FAIL(calc(result, text))) { LOG_WARN("fail to excute calc", K(ret)); } return ret; } int ObExprIsIpv6::cg_expr(ObExprCGCtx& op_cg_ctx, const ObRawExpr& raw_expr, ObExpr& rt_expr) const { UNUSED(op_cg_ctx); UNUSED(raw_expr); int ret = OB_SUCCESS; if (1 != rt_expr.arg_cnt_) { ret = OB_INVALID_ARGUMENT; LOG_WARN("is_ipv6 expr should have one param", K(ret), K(rt_expr.arg_cnt_)); } else if (OB_UNLIKELY(OB_ISNULL(rt_expr.args_) || OB_ISNULL(rt_expr.args_[0]))) { ret = OB_ERR_UNEXPECTED; LOG_WARN("children of is_ipv6 expr is null", K(ret), K(rt_expr.args_)); } else { rt_expr.eval_func_ = ObExprIsIpv6::calc_is_ipv6; } return ret; } int ObExprIsIpv6::calc_is_ipv6(const ObExpr& expr, ObEvalCtx& ctx, ObDatum& expr_datum) { int ret = OB_SUCCESS; if (OB_FAIL(expr.eval_param_value(ctx))) { LOG_WARN("is_ipv6 expr eval param value failed", K(ret)); } else { ObDatum& text = expr.locate_param_datum(ctx, 0); ObString m_text = text.get_string(); if (text.is_null()) { expr_datum.set_int(0); } else if (OB_FAIL(is_ipv6(expr_datum, m_text))) { LOG_WARN("fail to excute is_ipv6", K(ret)); } } return ret; } template int ObExprIsIpv6::is_ipv6(T& result, const ObString& text) { char buf[MAX_IP_ADDR_LENGTH]; int ipv6_ret = 1; int ret = OB_SUCCESS; if (MAX_IP_ADDR_LENGTH - 1 < text.length()) { ipv6_ret = 0; } else { MEMCPY(buf, text.ptr(), text.length()); buf[text.length()] = '\0'; in6_addr addr; bool is_ip_invaild; if (OB_FAIL(ObExprInetCommon::str_to_ipv6(text.length(), buf, is_ip_invaild, &addr))) { LOG_WARN("fail to excute str_to_ipv6", K(ret)); } else { ipv6_ret = is_ip_invaild ? 0 : 1; } } result.set_int(ipv6_ret); return ret; } } // namespace sql } // namespace oceanbase