diff --git a/cmake/Env.cmake b/cmake/Env.cmake index 4a9367df2..e999049c2 100644 --- a/cmake/Env.cmake +++ b/cmake/Env.cmake @@ -274,7 +274,7 @@ EXECUTE_PROCESS(COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE if( ${ARCHITECTURE} STREQUAL "x86_64" ) set(MTUNE_CFLAGS -mtune=core2) set(ARCH_LDFLAGS "") - set(OCI_DEVEL_INC "${DEP_3RD_DIR}/usr/include/oracle/11.2/client64") + set(OCI_DEVEL_INC "${DEP_3RD_DIR}/usr/include/oracle/12.2/client64") else() set(MARCH_CFLAGS "-march=armv8-a+crc" ) set(MTUNE_CFLAGS "-mtune=generic" ) diff --git a/deps/oblib/src/CMakeLists.txt b/deps/oblib/src/CMakeLists.txt index acec02ba5..9e69d8e47 100644 --- a/deps/oblib/src/CMakeLists.txt +++ b/deps/oblib/src/CMakeLists.txt @@ -6,6 +6,7 @@ get_property(EASY_INCLUDE_DIRS GLOBAL PROPERTY "EASY_INCLUDE_DIRS" ) target_include_directories( oblib_base_base_base INTERFACE ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/deps/easy/src ${CMAKE_SOURCE_DIR}/deps/oblib/src ${CMAKE_SOURCE_DIR}/deps/oblib/src/common diff --git a/deps/oblib/src/lib/mysqlclient/ob_isql_connection.h b/deps/oblib/src/lib/mysqlclient/ob_isql_connection.h index 3eb671eda..431aa68d1 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_isql_connection.h +++ b/deps/oblib/src/lib/mysqlclient/ob_isql_connection.h @@ -17,6 +17,7 @@ #include "lib/mysqlclient/ob_isql_client.h" #include "lib/timezone/ob_timezone_info.h" #include "lib/mysqlclient/ob_isql_connection_pool.h" +#include "common/object/ob_object.h" namespace oceanbase { @@ -26,6 +27,19 @@ class ObSql; struct ObSqlCtx; class ObResultSet; } +namespace share +{ +namespace schema +{ +class ObRoutineInfo; +} + +} + +namespace pl +{ +class ObUserDefinedType; +} namespace common { class ObIAllocator; @@ -110,6 +124,48 @@ public: virtual int execute_write(const uint64_t tenant_id, const ObString &sql, int64_t &affected_rows, bool is_user_sql = false, const common::ObAddr *sql_exec_addr = nullptr) = 0; + virtual int execute_proc() { return OB_NOT_SUPPORTED; } + virtual int execute_proc(const uint64_t tenant_id, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) = 0; + virtual int prepare(const char *sql) { + UNUSED(sql); + return OB_NOT_SUPPORTED; + } + virtual int bind_basic_type_by_pos(uint64_t position, + void *param, + int64_t param_size, + int32_t datatype, + int32_t &indicator) + { + UNUSEDx(position, param, param_size, datatype); + return OB_NOT_SUPPORTED; + } + virtual int bind_array_type_by_pos(uint64_t position, + void *array, + int32_t *indicators, + int64_t ele_size, + int32_t ele_datatype, + uint64_t array_size, + uint32_t *out_valid_array_size) + { + UNUSEDx(position, array, ele_size, ele_datatype, array_size, out_valid_array_size); + return OB_NOT_SUPPORTED; + } + virtual int get_server_major_version(int64_t &major_version) { + return OB_NOT_SUPPORTED; + } + virtual int get_package_udts(ObIAllocator &alloctor, + const common::ObString &database_name, + const common::ObString &package_name, + common::ObIArray &udts, + uint64_t dblink_id, + uint64_t &next_object_id) + { return OB_NOT_SUPPORTED; } // transaction interface virtual int start_transaction(const uint64_t &tenant_id, bool with_snap_shot = false) = 0; diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.cpp index bcddea483..7ea2e9397 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.cpp @@ -92,19 +92,6 @@ void ObMySQLConnection::reset() set_last_error(OB_SUCCESS); } -int ObMySQLConnection::create_statement(ObMySQLStatement &stmt, const uint64_t tenant_id, const char *sql) -{ - int ret = OB_SUCCESS; - if (OB_FAIL(switch_tenant(tenant_id))) { - LOG_WARN("switch tenant failed", K(tenant_id), K(ret)); - } else if (OB_FAIL(reset_read_consistency())) { - LOG_WARN("fail to set read consistency", K(ret)); - } else if (OB_FAIL(stmt.init(*this, sql))) { - LOG_WARN("fail to init prepared statement", K(ret)); - } - return ret; -} - int ObMySQLConnection::prepare_statement(ObMySQLPreparedStatement &stmt, const char *sql) { int ret = OB_SUCCESS; @@ -524,6 +511,31 @@ int ObMySQLConnection::execute_write(const uint64_t tenant_id, const char *sql, return ret; } +int ObMySQLConnection::execute_proc(const uint64_t tenant_id, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) +{ + int ret = OB_SUCCESS; + if (OB_UNLIKELY(closed_)) { + ret = OB_NOT_INIT; + LOG_WARN("connection not established. call connect first", K(ret)); + } else { + ObMySQLProcStatement stmt; + if (OB_FAIL(create_statement(stmt, tenant_id, sql.ptr()))) { + LOG_WARN("create statement failed", K(sql), K(ret)); + } else if (OB_FAIL(stmt.execute_proc(allocator, params, routine_info, tz_info))) { + LOG_WARN("statement execute update failed", K(sql), K(ret)); + } else if (OB_FAIL(stmt.close())) { + LOG_WARN("fail to close stmt", K(ret)); + } + } + return ret; +} + int ObMySQLConnection::execute_read(const int64_t cluster_id, const uint64_t tenant_id, const ObString &sql, ObISQLClient::ReadResult &res, bool is_user_sql, const common::ObAddr *sql_exec_addr) diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.h index 9b7d859ab..cac6b6441 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_connection.h @@ -55,7 +55,8 @@ public: void close(); virtual bool is_closed() const; // use user provided the statement - int create_statement(ObMySQLStatement &stmt, const uint64_t tenant_id, const char *sql); + template + int create_statement(T &stmt, const uint64_t tenant_id, const char *sql); int prepare_statement(ObMySQLPreparedStatement &stmt, const char *sql); int escape(const char *from, const int64_t from_size, char *to, const int64_t to_size, int64_t &out_size); @@ -83,6 +84,13 @@ public: virtual int execute_write(const uint64_t tenant_id, const char *sql, int64_t &affected_rows, bool is_user_sql = false, const common::ObAddr *sql_exec_addr = nullptr) override; + virtual int execute_proc(const uint64_t tenant_id, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) override; virtual int start_transaction(const uint64_t &tenant_id, bool with_snap_shot = false) override; virtual int rollback() override; virtual int commit() override; @@ -170,6 +178,20 @@ inline int64_t ObMySQLConnection::connection_version() const { return connection_version_; } + +template +int ObMySQLConnection::create_statement(T &stmt, const uint64_t tenant_id, const char *sql) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(switch_tenant(tenant_id))) { + _OB_LOG(WARN, "switch tenant failed, tenant_id=%ld, ret=%d", tenant_id, ret); + } else if (OB_FAIL(reset_read_consistency())) { + _OB_LOG(WARN, "fail to set read consistency, ret=%d", ret); + } else if (OB_FAIL(stmt.init(*this, sql))) { + _OB_LOG(WARN, "fail to init statement, ret=%d", ret); + } + return ret; +} } } } diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.cpp index c38050162..6746b005c 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.cpp @@ -80,22 +80,22 @@ void ObMySQLPreparedParam::close() } } -int ObMySQLPreparedParam::bind_param(const int64_t col_idx, enum_field_types buffer_type, char *out_buf, - const int64_t buf_len, unsigned long &res_len) +int ObMySQLPreparedParam::bind_param(ObBindParam ¶m) { int ret = OB_SUCCESS; if (OB_ISNULL(bind_)) { ret = OB_NOT_INIT; LOG_WARN("result not init. call init() first", K(ret)); - } else if (OB_LIKELY(col_idx >= 0) && OB_LIKELY(col_idx < param_count_)) { - bind_[col_idx].buffer_type = buffer_type; - bind_[col_idx].buffer = out_buf; - bind_[col_idx].buffer_length = buf_len; - bind_[col_idx].is_null = NULL; - bind_[col_idx].length = &res_len; + } else if (OB_LIKELY(param.col_idx_ >= 0) && OB_LIKELY(param.col_idx_ < param_count_)) { + bind_[param.col_idx_].buffer_type = param.buffer_type_; + bind_[param.col_idx_].buffer = param.buffer_; + bind_[param.col_idx_].buffer_length = param.buffer_len_; + bind_[param.col_idx_].length = ¶m.length_; + bind_[param.col_idx_].is_null = ¶m.is_null_; + bind_[param.col_idx_].is_unsigned = param.is_unsigned_; } else { ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid index", K(col_idx), K(param_count_)); + LOG_WARN("invalid index", K(param), K(param_count_)); } return ret; } diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.h index 474c37d5f..43e8919f6 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_param.h @@ -25,6 +25,7 @@ namespace common class ObIAllocator; namespace sqlclient { +class ObBindParam; class ObMySQLPreparedStatement; class ObMySQLPreparedParam { @@ -34,13 +35,8 @@ public: int init(); int bind_param(); void close(); - - /* - * bind data output buffer - */ - int bind_param(const int64_t col_idx, enum_field_types buf_type, char *out_buf, const int64_t buf_len, - unsigned long &res_len); - + int bind_param(ObBindParam ¶m); + int64_t get_stmt_param_count() const { return param_count_; } private: ObMySQLPreparedStatement &stmt_; diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.cpp index e5b4bbbb4..727a34dfb 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.cpp @@ -55,7 +55,7 @@ int ObMySQLPreparedResult::init() ret = OB_ALLOCATE_MEMORY_FAILED; LOG_ERROR("out of memory, alloc mem for mysql bind error", K(ret)); } else { - // LOG_INFO("statemen field count=%d", result_column_count_); + LOG_TRACE("statemen field count = ", K(result_column_count_)); } return ret; } @@ -107,22 +107,22 @@ int ObMySQLPreparedResult::next() return ret; } -int ObMySQLPreparedResult::bind_result(const int64_t col_idx, enum_field_types buffer_type, char *out_buf, - const int64_t buf_len, unsigned long &res_len) +int ObMySQLPreparedResult::bind_result(ObBindParam ¶m) { int ret = OB_SUCCESS; if (OB_ISNULL(bind_)) { ret = OB_NOT_INIT; LOG_WARN("result not init. call init() first", K(ret)); - } else if (OB_LIKELY(col_idx >= 0) && OB_LIKELY(col_idx < result_column_count_)) { - bind_[col_idx].buffer_type = buffer_type; - bind_[col_idx].buffer = out_buf; - bind_[col_idx].buffer_length = buf_len; - bind_[col_idx].is_null = NULL; - bind_[col_idx].length = &res_len; + } else if (OB_LIKELY(param.col_idx_ >= 0) && OB_LIKELY(param.col_idx_ < result_column_count_)) { + bind_[param.col_idx_].buffer_type = param.buffer_type_; + bind_[param.col_idx_].buffer = param.buffer_; + bind_[param.col_idx_].buffer_length = param.buffer_len_; + bind_[param.col_idx_].length = ¶m.length_; + bind_[param.col_idx_].is_null = ¶m.is_null_; + bind_[param.col_idx_].is_unsigned = param.is_unsigned_; } else { ret = OB_INVALID_ARGUMENT; - LOG_WARN("invalid index", K(col_idx), K(result_column_count_)); + LOG_WARN("invalid index", K(param), K(result_column_count_)); } return ret; } diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.h index ffb96d232..83cf1aeee 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_result.h @@ -25,6 +25,7 @@ namespace common class ObIAllocator; namespace sqlclient { +class ObBindParam; class ObMySQLPreparedStatement; class ObMySQLPreparedResult { @@ -46,13 +47,9 @@ public: */ int get_int(const int64_t col_idx, int64_t &int_val) const; int get_varchar(const int64_t col_idx, common::ObString &varchar_val) const; - // TODO: more types + int64_t get_result_column_count() const { return result_column_count_; } - /* - * bind data output buffer - */ - int bind_result(const int64_t col_idx, enum_field_types buf_type, char *out_buf, const int64_t buf_len, - unsigned long &res_len); + int bind_result(ObBindParam ¶m); private: ObMySQLPreparedStatement &stmt_; common::ObIAllocator &alloc_; diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.cpp index 2f9c1e68f..fa803c846 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.cpp @@ -18,6 +18,7 @@ #include "lib/mysqlclient/ob_mysql_prepared_param.h" #include "lib/mysqlclient/ob_mysql_prepared_result.h" #include "lib/mysqlclient/ob_mysql_prepared_statement.h" +#include "share/schema/ob_routine_info.h" namespace oceanbase { @@ -25,6 +26,703 @@ namespace common { namespace sqlclient { +static const obmysql::EMySQLFieldType ob_type_to_mysql_type[ObMaxType] = +{ + /* ObMinType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NULL, /* ObNullType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_TINY, /* ObTinyIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_SHORT, /* ObSmallIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_INT24, /* ObMediumIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_LONG, /* ObInt32Type */ + obmysql::EMySQLFieldType::MYSQL_TYPE_LONGLONG, /* ObIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_TINY, /* ObUTinyIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_SHORT, /* ObUSmallIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_INT24, /* ObUMediumIntType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_LONG, /* ObUInt32Type */ + obmysql::EMySQLFieldType::MYSQL_TYPE_LONGLONG, /* ObUInt64Type */ + obmysql::EMySQLFieldType::MYSQL_TYPE_FLOAT, /* ObFloatType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_DOUBLE, /* ObDoubleType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_FLOAT, /* ObUFloatType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_DOUBLE, /* ObUDoubleType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NEWDECIMAL, /* ObNumberType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NEWDECIMAL, /* ObUNumberType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_DATETIME, /* ObDateTimeType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_TIMESTAMP, /* ObTimestampType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_DATE, /* ObDateType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_TIME, /* ObTimeType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_YEAR, /* ObYearType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_VAR_STRING, /* ObVarcharType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_STRING, /* ObCharType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_VARCHAR, /* ObHexStringType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_COMPLEX, /* ObExtendType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NOT_DEFINED, /* ObUnknownType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_TINY_BLOB, /* ObTinyTextType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_BLOB, /* ObTextType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_MEDIUM_BLOB, /* ObMediumTextType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_LONG_BLOB, /* ObLongTextType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_BIT, /* ObBitType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_STRING, /* ObEnumType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_STRING, /* ObSetType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NOT_DEFINED, /* ObEnumInnerType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_NOT_DEFINED, /* ObSetInnerType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_WITH_TIME_ZONE, /* ObTimestampTZType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_WITH_LOCAL_TIME_ZONE, /* ObTimestampLTZType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_NANO, /* ObTimestampNanoType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_RAW, /* ObRawType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_INTERVAL_YM, /* ObIntervalYMType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_INTERVAL_DS, /* ObIntervalDSType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NUMBER_FLOAT, /* ObNumberFloatType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NVARCHAR2, /* ObNVarchar2Type */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NCHAR, /* ObNCharType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_OB_UROWID, + obmysql::EMySQLFieldType::MYSQL_TYPE_ORA_BLOB, /* ObLobType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_JSON, /* ObJsonType */ + obmysql::EMySQLFieldType::MYSQL_TYPE_GEOMETRY, /* ObGeometryType */ + /* ObMaxType */ +}; + +int ObBindParamEncode::encode_null(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + bind_param.is_null_ = 1; + return ret; +} + +int ObBindParamEncode::encode_int(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + bind_param.buffer_ = &(param.v_.int64_); + bind_param.buffer_len_ = sizeof(param.v_.int64_); + return ret; +} + +int ObBindParamEncode::encode_uint(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + if (OB_FAIL(encode_int(col_idx, is_output_param, tz_info, param, bind_param, allocator))) { + LOG_WARN("fail to encode", K(ret)); + } else { + bind_param.is_unsigned_ = 1; + } + return ret; +} + +int ObBindParamEncode::encode_float(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + bind_param.buffer_ = &(param.v_.float_); + bind_param.buffer_len_ = sizeof(param.v_.float_); + return ret; +} + +int ObBindParamEncode::encode_ufloat(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + if (OB_FAIL(encode_float(col_idx, is_output_param, tz_info, param, bind_param, allocator))) { + LOG_WARN("fail to encode", K(ret)); + } else { + bind_param.is_unsigned_ = 1; + } + return ret; +} + +int ObBindParamEncode::encode_double(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + bind_param.buffer_ = &(param.v_.double_); + bind_param.buffer_len_ = sizeof(param.v_.double_); + return ret; +} + +int ObBindParamEncode::encode_udouble(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info, allocator); + int ret = OB_SUCCESS; + if (OB_FAIL(encode_double(col_idx, is_output_param, tz_info, param, bind_param, allocator))) { + LOG_WARN("fail to encode", K(ret)); + } else { + bind_param.is_unsigned_ = 1; + } + return ret; +} + +int ObBindParamEncode::encode_number(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info); + int ret = OB_SUCCESS; + int64_t pos = 0; + char *buf = nullptr; + number::ObNumber num; + const int64_t buf_len = OB_CAST_TO_VARCHAR_MAX_LENGTH; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (OB_ISNULL(buf = reinterpret_cast(allocator.alloc(buf_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret), K(buf_len)); + } else if (OB_FAIL(param.get_number(num))) { + LOG_WARN("fail to get number", K(ret), K(param)); + } else if (OB_FAIL(num.format(buf, buf_len, pos, param.get_scale()))) { + LOG_WARN("fail to convert number to string", K(ret)); + } else { + bind_param.buffer_ = buf; + bind_param.buffer_len_ = buf_len; + bind_param.length_ = pos; + } + return ret; +} + +int ObBindParamEncode::encode_unumber(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param, tz_info); + int ret = OB_SUCCESS; + if (OB_FAIL(encode_number(col_idx, is_output_param, tz_info, param, bind_param, allocator))) { + LOG_WARN("fail to encode", K(ret)); + } else { + bind_param.is_unsigned_ = 1; + } + return ret; +} + +int ObBindParamEncode::encode_datetime(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param); + int ret = OB_SUCCESS; + ObTime ob_time; + MYSQL_TIME *tm = nullptr; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (OB_ISNULL(tm = reinterpret_cast(allocator.alloc(sizeof(MYSQL_TIME))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else if (OB_FAIL(ObTimeConverter::datetime_to_ob_time(param.get_datetime(), &tz_info, ob_time))) { + LOG_WARN("convert usec ", K(ret)); + } else { + MEMSET(tm, 0, sizeof(MYSQL_TIME)); + tm->year = ob_time.parts_[DT_YEAR]; + tm->month = ob_time.parts_[DT_MON]; + tm->day = ob_time.parts_[DT_MDAY]; + tm->hour= ob_time.parts_[DT_HOUR]; + tm->minute= ob_time.parts_[DT_MIN]; + tm->second= ob_time.parts_[DT_SEC]; + tm->second_part= ob_time.parts_[DT_USEC]; + tm->neg = DT_MODE_NEG & ob_time.mode_; + bind_param.buffer_ = tm; + bind_param.buffer_len_ = sizeof(MYSQL_TIME); + } + return ret; +} + +int ObBindParamEncode::encode_date(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param); + int ret = OB_SUCCESS; + ObTime ob_time; + MYSQL_TIME *tm = nullptr; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (OB_ISNULL(tm = reinterpret_cast(allocator.alloc(sizeof(MYSQL_TIME))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else if (OB_FAIL(ObTimeConverter::date_to_ob_time(param.get_date(), ob_time))) { + LOG_WARN("convert usec ", K(ret)); + } else { + MEMSET(tm, 0, sizeof(MYSQL_TIME)); + tm->year = ob_time.parts_[DT_YEAR]; + tm->month = ob_time.parts_[DT_MON]; + tm->day = ob_time.parts_[DT_MDAY]; + tm->neg = DT_MODE_NEG & ob_time.mode_; + bind_param.buffer_ = tm; + bind_param.buffer_len_ = sizeof(MYSQL_TIME); + } + return ret; +} + +int ObBindParamEncode::encode_time(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param); + int ret = OB_SUCCESS; + ObTime ob_time; + MYSQL_TIME *tm = nullptr; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (OB_ISNULL(tm = reinterpret_cast(allocator.alloc(sizeof(MYSQL_TIME))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else if (OB_FAIL(ObTimeConverter::time_to_ob_time(param.get_time(), ob_time))) { + LOG_WARN("convert usec ", K(ret)); + } else { + MEMSET(tm, 0, sizeof(MYSQL_TIME)); + tm->day = ob_time.parts_[DT_DATE]; + tm->hour= ob_time.parts_[DT_HOUR]; + tm->minute= ob_time.parts_[DT_MIN]; + tm->second= ob_time.parts_[DT_SEC]; + tm->second_part= ob_time.parts_[DT_USEC]; + tm->neg = DT_MODE_NEG & ob_time.mode_; + bind_param.buffer_ = tm; + bind_param.buffer_len_ = sizeof(MYSQL_TIME); + } + return ret; +} + +int ObBindParamEncode::encode_year(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(is_output_param); + int ret = OB_SUCCESS; + int64_t *year = nullptr; + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (OB_ISNULL(year = reinterpret_cast(allocator.alloc(sizeof(int64_t))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret)); + } else if (OB_FAIL(ObTimeConverter::year_to_int(param.get_year(), *year))) { + LOG_WARN("convert usec ", K(ret)); + } else { + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + bind_param.buffer_ = year; + bind_param.buffer_len_ = sizeof(int64_t); + } + return ret; +} + +int ObBindParamEncode::encode_string(ENCODE_FUNC_ARG_DECL) +{ + int ret = OB_SUCCESS; + ObLength length = param.get_length(); + ObString val = param.get_string(); + const ObObjType obj_type = param.get_type(); + enum_field_types buffer_type = static_cast(ob_type_to_mysql_type[obj_type]); + bind_param.col_idx_ = col_idx; + bind_param.buffer_type_ = buffer_type; + if (is_output_param) { + char *buf = nullptr; + const int64_t buf_len = length * 3; + if (OB_ISNULL(buf = reinterpret_cast(allocator.alloc(buf_len)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to alloc memory", K(ret), K(buf_len)); + } else { + MEMCPY(buf, val.ptr(), val.length()); + bind_param.buffer_ = buf; + bind_param.buffer_len_ = buf_len; + bind_param.length_ = val.length(); + } + } else { + bind_param.buffer_ = val.ptr(); + bind_param.buffer_len_ = val.length(); + bind_param.length_ = val.length(); + } + return ret; +} + +int ObBindParamEncode::encode_not_supported(ENCODE_FUNC_ARG_DECL) +{ + UNUSEDx(col_idx, is_output_param, tz_info, bind_param, allocator); + const ObObjType obj_type = param.get_type(); + int ret = OB_SUCCESS; + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported type", K(ret), K(obj_type)); + return ret; +} + +const ObBindParamEncode::EncodeFunc ObBindParamEncode::encode_map_[ObMaxType + 1] = +{ + ObBindParamEncode::encode_null, // ObNullType + ObBindParamEncode::encode_int, // ObTinyIntType + ObBindParamEncode::encode_int, // ObSmallIntType + ObBindParamEncode::encode_int, // ObMediumIntType + ObBindParamEncode::encode_int, // ObInt32Type + ObBindParamEncode::encode_int, // ObIntType + ObBindParamEncode::encode_uint, // ObUTinyIntType + ObBindParamEncode::encode_uint, // ObUSmallIntType + ObBindParamEncode::encode_uint, // ObUMediumIntType + ObBindParamEncode::encode_uint, // ObUInt32Type + ObBindParamEncode::encode_uint, // ObUInt64Type + ObBindParamEncode::encode_float, // ObFloatType + ObBindParamEncode::encode_double, // ObDoubleType + ObBindParamEncode::encode_ufloat, // ObUFloatType + ObBindParamEncode::encode_udouble, // ObUDoubleType + ObBindParamEncode::encode_number, // ObNumberType + ObBindParamEncode::encode_unumber, // ObUNumberType + ObBindParamEncode::encode_datetime, // ObDateTimeType + ObBindParamEncode::encode_datetime, // ObTimestampType + ObBindParamEncode::encode_date, // ObDateType + ObBindParamEncode::encode_time, // ObTimeType + ObBindParamEncode::encode_year, // ObYearType + ObBindParamEncode::encode_string, // ObVarcharType + ObBindParamEncode::encode_string, // ObCharType + ObBindParamEncode::encode_not_supported, // ObHexStringType + ObBindParamEncode::encode_not_supported, // ObExtendType + ObBindParamEncode::encode_not_supported, // ObUnknownType + ObBindParamEncode::encode_string, // ObTinyTextType + ObBindParamEncode::encode_string, // ObTextType + ObBindParamEncode::encode_string, // ObMediumTextType + ObBindParamEncode::encode_string, // ObLongTextType + ObBindParamEncode::encode_not_supported, // ObBitType + ObBindParamEncode::encode_not_supported, // ObEnumType + ObBindParamEncode::encode_not_supported, // ObSetType + ObBindParamEncode::encode_not_supported, // ObEnumInnerType + ObBindParamEncode::encode_not_supported, // ObSetInnerType + ObBindParamEncode::encode_not_supported, // ObTimestampTZType + ObBindParamEncode::encode_not_supported, // ObTimestampLTZType + ObBindParamEncode::encode_not_supported, // ObTimestampNanoType + ObBindParamEncode::encode_not_supported, // ObRawType + ObBindParamEncode::encode_not_supported, // ObIntervalYMType + ObBindParamEncode::encode_not_supported, // ObIntervalDSType + ObBindParamEncode::encode_not_supported, // ObNumberFloatType + ObBindParamEncode::encode_not_supported, // ObNVarchar2Type + ObBindParamEncode::encode_not_supported, // ObNCharType + ObBindParamEncode::encode_not_supported, // ObURowIDType + ObBindParamEncode::encode_not_supported, // ObLobType + ObBindParamEncode::encode_not_supported, // ObJsonType + ObBindParamEncode::encode_not_supported, // ObGeometryType + ObBindParamEncode::encode_not_supported // ObMaxType +}; + +int ObBindParamDecode::decode_null(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, bind_param, allocator); + int ret = OB_SUCCESS; + param.set_null(); + return ret; +} + +int ObBindParamDecode::decode_int(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(tz_info, allocator); + int ret = OB_SUCCESS; + switch (field_type) { + case MYSQL_TYPE_TINY: + param.set_tinyint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_SHORT: + param.set_smallint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_INT24: + param.set_mediumint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_LONG: + param.set_int32(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_LONGLONG: + param.set_int(*(reinterpret_cast(bind_param.buffer_))); + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unknown type", K(field_type)); + break; + }; + return ret; +} + +int ObBindParamDecode::decode_uint(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(tz_info, allocator); + int ret = OB_SUCCESS; + switch (field_type) { + case MYSQL_TYPE_TINY: + param.set_utinyint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_SHORT: + param.set_usmallint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_INT24: + param.set_umediumint(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_LONG: + param.set_uint32(*(reinterpret_cast(bind_param.buffer_))); + break; + case MYSQL_TYPE_LONGLONG: + param.set_uint64(*(reinterpret_cast(bind_param.buffer_))); + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unknown type", K(field_type)); + break; + }; + return ret; +} + +int ObBindParamDecode::decode_float(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, allocator); + int ret = OB_SUCCESS; + param.set_float(*(reinterpret_cast(bind_param.buffer_))); + return ret; +} + +int ObBindParamDecode::decode_ufloat(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, allocator); + int ret = OB_SUCCESS; + param.set_ufloat(*(reinterpret_cast(bind_param.buffer_))); + return ret; +} + +int ObBindParamDecode::decode_double(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, allocator); + int ret = OB_SUCCESS; + param.set_double(*(reinterpret_cast(bind_param.buffer_))); + return ret; +} + +int ObBindParamDecode::decode_udouble(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, allocator); + int ret = OB_SUCCESS; + param.set_udouble(*(reinterpret_cast(bind_param.buffer_))); + return ret; +} + +int ObBindParamDecode::decode_number(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info); + int ret = OB_SUCCESS; + number::ObNumber nb; + if (OB_FAIL(nb.from(reinterpret_cast(bind_param.buffer_), bind_param.length_, allocator))) { + LOG_WARN("decode param to number failed", K(ret), K(bind_param)); + } else { + param.set_number(nb); + } + return ret; +} + +int ObBindParamDecode::decode_unumber(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info); + int ret = OB_SUCCESS; + number::ObNumber nb; + if (OB_FAIL(nb.from(reinterpret_cast(bind_param.buffer_), bind_param.length_, allocator))) { + LOG_WARN("decode param to number failed", K(ret), K(bind_param)); + } else { + param.set_unumber(nb); + } + return ret; +} + +int ObBindParamDecode::decode_datetime(DECODE_FUNC_ARG_DECL) +{ + int ret = OB_SUCCESS; + ObTime ob_time; + ObPreciseDateTime value; + MYSQL_TIME *tm = reinterpret_cast(bind_param.buffer_); + if (0 == bind_param.length_) { + value = 0; + } else { + ob_time.parts_[DT_YEAR] = tm->year; + ob_time.parts_[DT_MON] = tm->month; + ob_time.parts_[DT_MDAY] = tm->day; + ob_time.parts_[DT_HOUR] = tm->hour; + ob_time.parts_[DT_MIN] = tm->minute; + ob_time.parts_[DT_SEC] = tm->second; + if (lib::is_oracle_mode()) { + ob_time.parts_[DT_USEC] = 0; + } else { + ob_time.parts_[DT_USEC] = tm->second_part; + } + ObTimeConvertCtx cvrt_ctx(NULL, false); + ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); + if (MYSQL_TYPE_DATE == field_type) { + value = ob_time.parts_[DT_DATE]; + } else if (OB_FAIL(ObTimeConverter::ob_time_to_datetime(ob_time, cvrt_ctx, value))){ + LOG_WARN("convert obtime to datetime failed", K(ret), K(value), K(tm->year), K(tm->month), + K(tm->day), K(tm->hour), K(tm->minute), K(tm->second)); + } + } + if (OB_SUCC(ret)) { + if (MYSQL_TYPE_TIMESTAMP == field_type) { + int64_t ts_value = 0; + if (OB_FAIL(ObTimeConverter::datetime_to_timestamp(value, &tz_info, ts_value))) { + LOG_WARN("datetime to timestamp failed", K(ret)); + } else { + param.set_timestamp(ts_value); + } + } else if (MYSQL_TYPE_DATETIME == field_type) { + param.set_datetime(value); + } else if (MYSQL_TYPE_DATE == field_type) { + param.set_date(static_cast(value)); + } + } + LOG_TRACE("get datetime", K(tm->year), K(tm->month), K(tm->day), K(tm->hour), K(tm->minute), + K(tm->second), K(tm->second_part), K(value)); + return ret; +} + +int ObBindParamDecode::decode_time(DECODE_FUNC_ARG_DECL) +{ + int ret = OB_SUCCESS; + ObTime ob_time; + ObPreciseDateTime value; + MYSQL_TIME *tm = reinterpret_cast(bind_param.buffer_); + if (0 == bind_param.length_) { + value = 0; + } else { + ob_time.parts_[DT_YEAR] = tm->year; + ob_time.parts_[DT_MON] = tm->month; + ob_time.parts_[DT_MDAY] = tm->day; + ob_time.parts_[DT_HOUR] = tm->hour; + ob_time.parts_[DT_MIN] = tm->minute; + ob_time.parts_[DT_SEC] = tm->second; + ob_time.parts_[DT_USEC] = tm->second_part; + ob_time.parts_[DT_DATE] = ObTimeConverter::ob_time_to_date(ob_time); + value = ObTimeConverter::ob_time_to_time(ob_time); + } + if (OB_SUCC(ret)) { + param.set_time(value); + } + LOG_TRACE("get time", K(tm->year), K(tm->month), K(tm->day), K(tm->hour), K(tm->minute), + K(tm->second), K(tm->second_part), K(value)); + return ret; +} + +int ObBindParamDecode::decode_year(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(field_type, tz_info, allocator); + int ret = OB_SUCCESS; + param.set_year(*reinterpret_cast(bind_param.buffer_)); + return ret; +} + +int ObBindParamDecode::decode_string(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(tz_info); + int ret = OB_SUCCESS; + ObString dst(bind_param.length_, static_cast(bind_param.buffer_)); + if (OB_FAIL(ob_write_string(allocator, dst, dst))) { + LOG_WARN("failed to write str", K(ret)); + } else { + switch (field_type) { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + param.set_varchar(dst); + break; + case MYSQL_TYPE_STRING: + param.set_char(dst); + case MYSQL_TYPE_TINY_BLOB: + param.set_lob_value(ObTinyTextType, dst.ptr(), dst.length()); + case MYSQL_TYPE_BLOB: + param.set_lob_value(ObTextType, dst.ptr(), dst.length()); + case MYSQL_TYPE_MEDIUM_BLOB: + param.set_lob_value(ObMediumTextType, dst.ptr(), dst.length()); + case MYSQL_TYPE_LONG_BLOB: + param.set_lob_value(ObLongTextType, dst.ptr(), dst.length()); + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("unknown type", K(ret), K(field_type)); + break; + } + } + return ret; +} + +int ObBindParamDecode::decode_not_supported(DECODE_FUNC_ARG_DECL) +{ + UNUSEDx(tz_info, bind_param, param, allocator); + int ret = OB_SUCCESS; + ret = OB_NOT_SUPPORTED; + LOG_WARN("not supported type", K(ret), K(field_type)); + return ret; +} + +const ObBindParamDecode::DecodeFunc ObBindParamDecode::decode_map_[ObMaxType + 1] = +{ + ObBindParamDecode::decode_null, // ObNullType + ObBindParamDecode::decode_int, // ObTinyIntType + ObBindParamDecode::decode_int, // ObSmallIntType + ObBindParamDecode::decode_int, // ObMediumIntType + ObBindParamDecode::decode_int, // ObInt32Type + ObBindParamDecode::decode_int, // ObIntType + ObBindParamDecode::decode_uint, // ObUTinyIntType + ObBindParamDecode::decode_uint, // ObUSmallIntType + ObBindParamDecode::decode_uint, // ObUMediumIntType + ObBindParamDecode::decode_uint, // ObUInt32Type + ObBindParamDecode::decode_uint, // ObUInt64Type + ObBindParamDecode::decode_float, // ObFloatType + ObBindParamDecode::decode_double, // ObDoubleType + ObBindParamDecode::decode_ufloat, // ObUFloatType + ObBindParamDecode::decode_udouble, // ObUDoubleType + ObBindParamDecode::decode_number, // ObNumberType + ObBindParamDecode::decode_unumber, // ObUNumberType + ObBindParamDecode::decode_datetime, // ObDateTimeType + ObBindParamDecode::decode_datetime, // ObTimestampType + ObBindParamDecode::decode_datetime, // ObDateType + ObBindParamDecode::decode_time, // ObTimeType + ObBindParamDecode::decode_year, // ObYearType + ObBindParamDecode::decode_string, // ObVarcharType + ObBindParamDecode::decode_string, // ObCharType + ObBindParamDecode::decode_not_supported, // ObHexStringType + ObBindParamDecode::decode_not_supported, // ObExtendType + ObBindParamDecode::decode_not_supported, // ObUnknownType + ObBindParamDecode::decode_string, // ObTinyTextType + ObBindParamDecode::decode_string, // ObTextType + ObBindParamDecode::decode_string, // ObMediumTextType + ObBindParamDecode::decode_string, // ObLongTextType + ObBindParamDecode::decode_not_supported, // ObBitType + ObBindParamDecode::decode_not_supported, // ObEnumType + ObBindParamDecode::decode_not_supported, // ObSetType + ObBindParamDecode::decode_not_supported, // ObEnumInnerType + ObBindParamDecode::decode_not_supported, // ObSetInnerType + ObBindParamDecode::decode_not_supported, // ObTimestampTZType + ObBindParamDecode::decode_not_supported, // ObTimestampLTZType + ObBindParamDecode::decode_not_supported, // ObTimestampNanoType + ObBindParamDecode::decode_not_supported, // ObRawType + ObBindParamDecode::decode_not_supported, // ObIntervalYMType + ObBindParamDecode::decode_not_supported, // ObIntervalDSType + ObBindParamDecode::decode_not_supported, // ObNumberFloatType + ObBindParamDecode::decode_not_supported, // ObNVarchar2Type + ObBindParamDecode::decode_not_supported, // ObNCharType + ObBindParamDecode::decode_not_supported, // ObURowIDType + ObBindParamDecode::decode_not_supported, // ObLobType + ObBindParamDecode::decode_not_supported, // ObJsonType + ObBindParamDecode::decode_not_supported, // ObGeometryType + ObBindParamDecode::decode_not_supported // ObMaxType +}; + +int ObBindParam::assign(const ObBindParam &other) +{ + int ret = OB_SUCCESS; + col_idx_ = other.col_idx_; + buffer_type_ = other.buffer_type_; + buffer_ = other.buffer_; + buffer_len_ = other.buffer_len_; + length_ = other.length_; + is_unsigned_ = other.is_unsigned_; + is_null_ = other.is_null_; + return ret; +} + ObMySQLPreparedStatement::ObMySQLPreparedStatement() : conn_(NULL), arena_allocator_(ObModIds::MYSQL_CLIENT_CACHE), @@ -32,7 +730,10 @@ ObMySQLPreparedStatement::ObMySQLPreparedStatement() : param_(*this), result_(*this), stmt_param_count_(0), - stmt_(NULL) + result_column_count_(0), + stmt_(NULL), + bind_params_(NULL), + result_params_(NULL) { } @@ -60,12 +761,182 @@ ObMySQLConnection *ObMySQLPreparedStatement::get_connection() return conn_; } +int ObMySQLPreparedStatement::alloc_bind_params(const int64_t size, ObBindParam *&bind_params) +{ + int ret = OB_SUCCESS; + if (size <= 0) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid argument", K(ret), K(size)); + } else if (OB_ISNULL(bind_params = reinterpret_cast(alloc_->alloc(sizeof(ObBindParam) * size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("out of memory, alloc mem for mysql_bind error", K(ret)); + } else { + MEMSET(bind_params, 0, sizeof(ObBindParam) * size); + } + return ret; +} + +int ObMySQLPreparedStatement::get_bind_param_by_idx(const int64_t idx, + ObBindParam *¶m) +{ + int ret = OB_SUCCESS; + param = nullptr; + if (idx >= stmt_param_count_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid index", K(ret), K(idx), K(stmt_param_count_)); + } else { + param = &(bind_params_[idx]); + } + return ret; +} + +int ObMySQLPreparedStatement::get_bind_result_param_by_idx(const int64_t idx, + ObBindParam *¶m) +{ + int ret = OB_SUCCESS; + param = nullptr; + if (idx >= result_column_count_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid index", K(ret), K(idx), K(result_column_count_)); + } else { + param = &(result_params_[idx]); + } + return ret; +} + +int ObMySQLPreparedStatement::get_mysql_type(ObObjType ob_type, obmysql::EMySQLFieldType &mysql_type) const +{ + int ret = OB_SUCCESS; + if (ob_type < ObNullType || ob_type >= ObMaxType) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid type", K(ret), K(ob_type)); + } else { + mysql_type = static_cast(ob_type_to_mysql_type[ob_type]); + } + return ret; +} + +int ObMySQLPreparedStatement::get_ob_type(ObObjType &ob_type, obmysql::EMySQLFieldType mysql_type) const +{ + int ret = OB_SUCCESS; + switch (mysql_type) { + case obmysql::EMySQLFieldType::MYSQL_TYPE_NULL: + ob_type = ObNullType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_TINY: + ob_type = ObTinyIntType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_SHORT: + ob_type = ObSmallIntType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_LONG: + ob_type = ObInt32Type; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_LONGLONG: + ob_type = ObIntType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_FLOAT: + ob_type = ObFloatType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_DOUBLE: + ob_type = ObDoubleType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_TIMESTAMP: + ob_type = ObTimestampType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_DATETIME: + ob_type = ObDateTimeType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_TIME: + ob_type = ObTimeType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_DATE: + ob_type = ObDateType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_YEAR: + ob_type = ObYearType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_VARCHAR: + case obmysql::EMySQLFieldType::MYSQL_TYPE_VAR_STRING: + ob_type = ObVarcharType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_STRING: + ob_type = ObCharType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_TINY_BLOB: + ob_type = ObTinyTextType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_BLOB: + ob_type = ObTextType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_MEDIUM_BLOB: + ob_type = ObMediumTextType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_LONG_BLOB: + ob_type = ObLongTextType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_WITH_TIME_ZONE: + ob_type = ObTimestampTZType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_WITH_LOCAL_TIME_ZONE: + ob_type = ObTimestampLTZType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_TIMESTAMP_NANO: + ob_type = ObTimestampNanoType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_RAW: + ob_type = ObRawType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_NEWDECIMAL: + ob_type = ObNumberType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NUMBER_FLOAT: + ob_type = ObNumberFloatType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_JSON: + ob_type = ObJsonType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_GEOMETRY: + ob_type = ObGeometryType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_BIT: + ob_type = ObBitType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_ENUM: + ob_type = ObEnumType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_SET: + ob_type = ObSetType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_INTERVAL_YM: + ob_type = ObIntervalYMType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_INTERVAL_DS: + ob_type = ObIntervalDSType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NVARCHAR2: + ob_type = ObNVarchar2Type; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_NCHAR: + ob_type = ObNCharType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_COMPLEX: + ob_type = ObExtendType; + break; + case obmysql::EMySQLFieldType::MYSQL_TYPE_OB_UROWID: + ob_type = ObURowIDType; + break; + default: + LOG_WARN("unsupport MySQL type", K(ret), K(mysql_type)); + ret = OB_OBJ_TYPE_ERROR; + } + return ret; +} + int ObMySQLPreparedStatement::init(ObMySQLConnection &conn, const char *sql) { int ret = OB_SUCCESS; - // will be used by param_ and result_ conn_ = &conn; - if (OB_ISNULL(sql)) { ret = OB_INVALID_ARGUMENT; LOG_WARN("invalid sql", KP(sql), K(ret)); @@ -79,8 +950,14 @@ int ObMySQLPreparedStatement::init(ObMySQLConnection &conn, const char *sql) LOG_WARN("fail to init prepared result", K(ret)); } else if (OB_FAIL(result_.init())) { LOG_WARN("fail to init prepared result", K(ret)); + } else if (FALSE_IT(stmt_param_count_ = param_.get_stmt_param_count())) { + } else if (FALSE_IT(result_column_count_ = result_.get_result_column_count())) { + } else if (stmt_param_count_ > 0 && OB_FAIL(alloc_bind_params(stmt_param_count_, bind_params_))) { + LOG_WARN("fail to alloc stmt bind params", K(ret)); + } else if (result_column_count_ > 0 && OB_FAIL(alloc_bind_params(result_column_count_, result_params_))) { + LOG_WARN("fail to alloc result bind params", K(ret)); } else { - LOG_INFO("conn_handler", "handler", conn_->get_handler(), K_(stmt)); + LOG_INFO("conn_handler", "handler", conn_->get_handler(), K_(stmt), K_(stmt_param_count), K_(result_column_count)); } return ret; } @@ -88,19 +965,143 @@ int ObMySQLPreparedStatement::init(ObMySQLConnection &conn, const char *sql) int ObMySQLPreparedStatement::close() { int ret = OB_SUCCESS; - - if (OB_ISNULL(stmt_)) { - ret = OB_ERR_UNEXPECTED; - LOG_ERROR("stmt handler is null", K(ret)); - } else if (0 != mysql_stmt_close(stmt_)) { - ret = -mysql_errno(conn_->get_handler()); - LOG_WARN("fail to close stmt", "info", mysql_error(conn_->get_handler()), K(ret)); + if (nullptr != stmt_) { + if (0 != mysql_stmt_close(stmt_)) { + ret = -mysql_errno(conn_->get_handler()); + LOG_WARN("fail to close stmt", "info", mysql_error(conn_->get_handler()), K(ret)); + } } stmt_param_count_ = 0; + result_column_count_ = 0; + bind_params_ = NULL; + result_params_ = NULL; return ret; } +int ObMySQLPreparedStatement::bind_param(const ObBindParam &bind_param) +{ + int ret = OB_SUCCESS; + if (bind_param.col_idx_ >= stmt_param_count_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid index", K(ret), K(bind_param), K(stmt_param_count_)); + } else { + ObBindParam ¶m = bind_params_[bind_param.col_idx_]; + if (OB_FAIL(param.assign(bind_param))) { + LOG_WARN("fail to assing bind param", K(ret)); + } else if (OB_FAIL(param_.bind_param(param))) { + LOG_WARN("fail to bind param", K(ret), K(bind_param)); + } + } + return ret; +} +int ObMySQLPreparedStatement::bind_result(const ObBindParam &bind_param) +{ + int ret = OB_SUCCESS; + if (bind_param.col_idx_ >= result_column_count_) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("invalid index", K(ret), K(bind_param), K(result_column_count_)); + } else { + ObBindParam ¶m = result_params_[bind_param.col_idx_]; + if (OB_FAIL(param.assign(bind_param))) { + LOG_WARN("fail to assing bind param", K(ret)); + } else if (OB_FAIL(result_.bind_result(param))) { + LOG_WARN("fail to bind param", K(ret), K(bind_param)); + } + } + return ret; +} + +int ObMySQLPreparedStatement::bind_param_int(const int64_t col_idx, int64_t *in_int_val) +{ + int ret = OB_SUCCESS; + ObBindParam *param = nullptr; + if (OB_FAIL(get_bind_param_by_idx(col_idx, param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(stmt_param_count_)); + } else if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(stmt_param_count_)); + } else { + param->col_idx_ = col_idx; + param->buffer_type_ = enum_field_types::MYSQL_TYPE_LONGLONG; + param->buffer_ = reinterpret_cast(in_int_val); + param->buffer_len_ = sizeof(int64_t); + if (OB_FAIL(bind_param(*param))) { + LOG_WARN("fail to bind int param", K(ret)); + } + } + return ret; +} + +int ObMySQLPreparedStatement::bind_param_varchar(const int64_t col_idx, char *in_str_val, + unsigned long in_str_len) +{ + int ret = OB_SUCCESS; + ObBindParam *param = nullptr; + if (OB_FAIL(get_bind_param_by_idx(col_idx, param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(stmt_param_count_)); + } else if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(stmt_param_count_)); + } else { + param->col_idx_ = col_idx; + param->buffer_type_ = enum_field_types::MYSQL_TYPE_STRING; + param->buffer_ = in_str_val; + param->buffer_len_ = 0; + param->length_ = in_str_len; + if (OB_FAIL(bind_param(*param))) { + LOG_WARN("fail to bind int param", K(ret)); + } + } + return ret; +} + +int ObMySQLPreparedStatement::bind_result_int(const int64_t col_idx, int64_t *out_buf) +{ + int ret = OB_SUCCESS; + ObBindParam *param = nullptr; + if (OB_FAIL(get_bind_result_param_by_idx(col_idx, param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(result_column_count_)); + } else if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get bind result param by idx", K(ret), K(col_idx), K(result_column_count_)); + } else { + param->col_idx_ = col_idx; + param->buffer_type_ = enum_field_types::MYSQL_TYPE_LONGLONG; + param->buffer_ = reinterpret_cast(out_buf); + param->buffer_len_ = sizeof(int64_t); + if (OB_FAIL(bind_result(*param))) { + LOG_WARN("fail to bind int result param", K(ret)); + } + } + return ret; +} + +int ObMySQLPreparedStatement::bind_result_varchar(const int64_t col_idx, + char *out_buf, + const int buf_len, + unsigned long *&res_len) +{ + int ret = OB_SUCCESS; + ObBindParam *param = nullptr; + if (OB_FAIL(get_bind_result_param_by_idx(col_idx, param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(result_column_count_)); + } else if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(result_column_count_)); + } else { + param->col_idx_ = col_idx; + param->buffer_type_ = enum_field_types::MYSQL_TYPE_STRING; + param->buffer_ = out_buf; + param->buffer_len_ = buf_len; + param->length_ = 0; + res_len = ¶m->length_; + if (OB_FAIL(bind_result(*param))) { + LOG_WARN("fail to bind varchar result param", K(ret)); + } + } + return ret; +} int ObMySQLPreparedStatement::execute_update() { @@ -141,68 +1142,127 @@ ObMySQLPreparedResult *ObMySQLPreparedStatement::execute_query() return result; } -int ObMySQLPreparedStatement::set_int(const int64_t col_idx, const int64_t int_val) -{ - // TODO - UNUSED(col_idx); - UNUSED(int_val); - LOG_WARN_RET(OB_NOT_IMPLEMENT, "call not implemented function."); - return OB_NOT_IMPLEMENT; -} - -int ObMySQLPreparedStatement::set_varchar(const int64_t col_idx, const ObString &varchar_val) -{ - // TODO - UNUSED(col_idx); - UNUSED(varchar_val); - LOG_WARN_RET(OB_NOT_IMPLEMENT, "call not implemented function."); - return OB_NOT_IMPLEMENT; -} - -int ObMySQLPreparedStatement::bind_param_int(const int64_t col_idx, int64_t *in_int_val) +int ObMySQLProcStatement::bind_param(const int64_t col_idx, + const bool is_output_param, + const ObTimeZoneInfo *tz_info, + ObObjParam ¶m, + const share::schema::ObRoutineInfo &routine_info, + ObIAllocator &allocator) { int ret = OB_SUCCESS; - unsigned long res_len = 0; - if (OB_FAIL(param_.bind_param(col_idx, enum_field_types::MYSQL_TYPE_LONGLONG, - reinterpret_cast(in_int_val), sizeof(int64_t), res_len))) { - LOG_WARN("fail to bind int result", K(col_idx), K(ret)); + ObBindParam *bind_param = nullptr; + const ObObjType obj_type = param.get_type(); + if (OB_FAIL(get_bind_param_by_idx(col_idx, bind_param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx)); + } else if (OB_ISNULL(bind_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K(stmt_param_count_)); + } else if (OB_FAIL(ObBindParamEncode::encode_map_[obj_type](col_idx, + is_output_param, + *tz_info, + param, + *bind_param, + allocator))) { + LOG_WARN("fail to encode param", K(ret)); + } else if (OB_FAIL(param_.bind_param(*bind_param))) { + LOG_WARN("failed to bind param", K(ret), KPC(bind_param)); } return ret; } -int ObMySQLPreparedStatement::bind_param_varchar(const int64_t col_idx, char *in_str_val, - unsigned long &in_str_len) +int ObMySQLProcStatement::bind_proc_param(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + common::ObIArray &basic_out_param, + const ObTimeZoneInfo *tz_info) { int ret = OB_SUCCESS; - if (OB_FAIL(param_.bind_param(col_idx, enum_field_types::MYSQL_TYPE_VAR_STRING, - in_str_val, 0, in_str_len))) { - LOG_WARN("fail to bind int result", K(col_idx), K(ret)); + for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); i++) { + ObObjParam ¶m = params.at(i); + const share::schema::ObRoutineParam *r_param = routine_info.get_routine_params().at(i); + bool is_output = false; + if (OB_ISNULL(r_param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param is null", K(ret), K(i)); + } else { + is_output = r_param->is_out_sp_param() || r_param->is_inout_sp_param(); + if (is_output && OB_FAIL(basic_out_param.push_back(i))) { + LOG_WARN("push back failed", K(ret), K(i)); + } else if (OB_FAIL(bind_param(i, is_output, tz_info, param, routine_info, allocator))) { + LOG_WARN("failed to bind param", K(ret)); + } + } } return ret; } -int ObMySQLPreparedStatement::bind_result_int(const int64_t col_idx, int64_t *out_buf) +int ObMySQLProcStatement::convert_proc_output_param_result(const ObTimeZoneInfo &tz_info, + const ObBindParam &bind_param, + ObObjParam ¶m, + const share::schema::ObRoutineInfo &routine_info, + ObIAllocator &allocator) { int ret = OB_SUCCESS; - unsigned long res_len = 0; - if (OB_FAIL(result_.bind_result(col_idx, enum_field_types::MYSQL_TYPE_LONGLONG, - reinterpret_cast(out_buf), sizeof(int64_t), res_len))) { - LOG_WARN("fail to bind int result", K(col_idx), K(ret)); + ObObjType obj_type = ObNullType; + if (OB_FAIL(get_ob_type(obj_type, static_cast(bind_param.buffer_type_)))) { + LOG_WARN("fail to get ob type", K(ret), K(bind_param)); + } else if (OB_FAIL(ObBindParamDecode::decode_map_[obj_type](bind_param.buffer_type_, + tz_info, + bind_param, + param, + allocator))) { + LOG_WARN("failed to decode param", K(ret)); } return ret; } -int ObMySQLPreparedStatement::bind_result_varchar(const int64_t col_idx, char *out_buf, const int buf_len, - unsigned long &res_len) +int ObMySQLProcStatement::process_proc_output_params(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + common::ObIArray &basic_out_param, + const ObTimeZoneInfo *tz_info) { int ret = OB_SUCCESS; - if (OB_FAIL(result_.bind_result(col_idx,enum_field_types::MYSQL_TYPE_VAR_STRING, - out_buf, buf_len, res_len))) { - LOG_WARN("fail to bind int result", K(col_idx), K(ret)); + const int64_t params_count = params.count(); + for (int64_t i = 0; OB_SUCC(ret) && i < basic_out_param.count(); i++) { + const int64_t col_idx = basic_out_param.at(i); + ObBindParam *bind_param = nullptr; + if (col_idx >= params_count || col_idx > stmt_param_count_) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("idx out of range", K(ret), K(col_idx), K(params_count)); + } else if (OB_FAIL(get_bind_param_by_idx(col_idx, bind_param))) { + LOG_WARN("fail to get bind param by idx", K(ret), K(col_idx), K_(stmt_param_count)); + } else if (OB_FAIL(convert_proc_output_param_result(*tz_info, *bind_param, params.at(col_idx), routine_info, allocator))) { + LOG_WARN("fail to convert proc output param result", K(ret)); + } + LOG_INFO("end process param", K(i), KPC(bind_param), K(ret)); } return ret; } +int ObMySQLProcStatement::execute_proc(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + const ObTimeZoneInfo *tz_info) +{ + int ret = OB_SUCCESS; + common::ObSEArray basic_out_param; + if (OB_ISNULL(tz_info)) { + ret = OB_INVALID_ARGUMENT; + LOG_WARN("tz info is null", K(ret)); + } else if (OB_FAIL(bind_proc_param(allocator, params, routine_info, basic_out_param, tz_info))) { + LOG_WARN("failed to bind proc param", K(ret)); + } else if (OB_FAIL(param_.bind_param())) { + LOG_WARN("failed to bind prepared input param", "info", mysql_error(conn_->get_handler()), K(ret)); + } else if (0 != mysql_stmt_execute(stmt_)) { + ret = -mysql_stmt_errno(stmt_); + LOG_WARN("fail to execute stmt", "info", mysql_stmt_error(stmt_), "info", mysql_error(conn_->get_handler()), K(ret)); + } else if (OB_FAIL(process_proc_output_params(allocator, params, routine_info, basic_out_param, tz_info))) { + LOG_WARN("fail to process proc output params", K(ret)); + } + return ret; +}; + } // end namespace sqlcient } // end namespace common } // end namespace oceanbase diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.h index 703912c05..679a56f42 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_prepared_statement.h @@ -26,34 +26,128 @@ namespace common { namespace sqlclient { +struct ObBindParam +{ + ObBindParam() : col_idx_(-1), buffer_type_(enum_field_types::MAX_NO_FIELD_TYPES), buffer_(nullptr), + buffer_len_(0), length_(0), is_unsigned_(0), is_null_(0) + { + } + ObBindParam(int64_t col_idx, enum_field_types buffer_type, + void *buffer, int64_t buffer_len, unsigned long length) + : col_idx_(col_idx), buffer_type_(buffer_type), buffer_(buffer), buffer_len_(buffer_len), + length_(length), is_unsigned_(0), is_null_(0) + { + } + ObBindParam(int64_t col_idx, enum_field_types buffer_type, + void *buffer, int64_t buffer_len, unsigned long length, + my_bool is_unsigned, my_bool is_null) + : col_idx_(col_idx), buffer_type_(buffer_type), buffer_(buffer), buffer_len_(buffer_len), + length_(length), is_unsigned_(is_unsigned), is_null_(is_null) + { + } + int assign(const ObBindParam &other); + TO_STRING_KV(K_(col_idx), + K_(buffer_type), + K_(buffer), + K_(buffer_len), + K_(length), + K_(is_unsigned), + K_(is_null)); + +public: + int64_t col_idx_; + enum_field_types buffer_type_; + void *buffer_; + int64_t buffer_len_; + unsigned long length_; + my_bool is_unsigned_; + my_bool is_null_; +}; + +class ObBindParamEncode +{ +public: + #define ENCODE_FUNC_ARG_DECL const int64_t col_idx, \ + const bool is_output_param, \ + const ObTimeZoneInfo &tz_info, \ + ObObjParam ¶m, \ + ObBindParam &bind_param, \ + ObIAllocator &allocator + #define DEF_ENCODE_FUNC(name) \ + static int encode_##name(ENCODE_FUNC_ARG_DECL); + using EncodeFunc = int (*)(ENCODE_FUNC_ARG_DECL); + + DEF_ENCODE_FUNC(null); + DEF_ENCODE_FUNC(int); + DEF_ENCODE_FUNC(uint); + DEF_ENCODE_FUNC(float); + DEF_ENCODE_FUNC(ufloat); + DEF_ENCODE_FUNC(double); + DEF_ENCODE_FUNC(udouble); + DEF_ENCODE_FUNC(number); + DEF_ENCODE_FUNC(unumber); + DEF_ENCODE_FUNC(datetime); + DEF_ENCODE_FUNC(date); + DEF_ENCODE_FUNC(time); + DEF_ENCODE_FUNC(year); + DEF_ENCODE_FUNC(string); + static int encode_not_supported(ENCODE_FUNC_ARG_DECL); + +public: + static const EncodeFunc encode_map_[ObMaxType + 1]; +}; + +class ObBindParamDecode +{ +public: + #define DECODE_FUNC_ARG_DECL const enum_field_types field_type, \ + const ObTimeZoneInfo &tz_info, \ + const ObBindParam &bind_param, \ + ObObjParam ¶m, \ + ObIAllocator &allocator + #define DEF_DECODE_FUNC(name) \ + static int decode_##name(DECODE_FUNC_ARG_DECL); + using DecodeFunc = int (*)(DECODE_FUNC_ARG_DECL); + + DEF_DECODE_FUNC(null); + DEF_DECODE_FUNC(int); + DEF_DECODE_FUNC(uint); + DEF_DECODE_FUNC(float); + DEF_DECODE_FUNC(ufloat); + DEF_DECODE_FUNC(double); + DEF_DECODE_FUNC(udouble); + DEF_DECODE_FUNC(number); + DEF_DECODE_FUNC(unumber); + DEF_DECODE_FUNC(datetime); + DEF_DECODE_FUNC(time); + DEF_DECODE_FUNC(year); + DEF_DECODE_FUNC(string); + static int decode_not_supported(DECODE_FUNC_ARG_DECL); + +public: + static const DecodeFunc decode_map_[ObMaxType + 1]; +}; + class ObMySQLPreparedStatement { public: ObMySQLPreparedStatement(); - ~ObMySQLPreparedStatement(); + virtual ~ObMySQLPreparedStatement(); ObIAllocator &get_allocator(); ObMySQLConnection *get_connection(); MYSQL_STMT *get_stmt_handler(); MYSQL *get_conn_handler(); - int init(ObMySQLConnection &conn, const char *sql); - /* - * close statement - */ int close(); - + int init(ObMySQLConnection &conn, const char *sql); + int bind_param(const ObBindParam ¶m); + int bind_result(const ObBindParam ¶m); int bind_param_int(const int64_t col_idx, int64_t *out_buf); - int bind_param_varchar(const int64_t col_idx, char *out_buf, unsigned long &res_len); + int bind_param_varchar(const int64_t col_idx, char *out_buf, unsigned long res_len); int bind_result_int(const int64_t col_idx, int64_t *out_buf); - int bind_result_varchar(const int64_t col_idx, char *out_buf, const int buf_len, unsigned long &res_len); - /* - * bind input param to sql - * must called before execute_update, execute_query - */ - int set_int(const int64_t col_idx, const int64_t int_val); - int set_varchar(const int64_t col_idx, const ObString &varchar); - // TODO: more types - + int bind_result_varchar(const int64_t col_idx, char *out_buf, const int buf_len, unsigned long *&res_len); + int64_t get_stmt_param_count() const { return stmt_param_count_; } + int64_t get_result_column_count() const { return result_column_count_; } /* * execute a SQL command, such as * - set @@session.ob_query_timeout=10 @@ -69,14 +163,64 @@ public: */ ObMySQLPreparedResult *execute_query(); -private: +protected: + int alloc_bind_params(const int64_t size, ObBindParam *&bind_params); + int get_bind_param_by_idx(const int64_t idx, + ObBindParam *¶m); + int get_bind_result_param_by_idx(const int64_t idx, + ObBindParam *¶m); + int get_mysql_type(ObObjType ob_type, obmysql::EMySQLFieldType &mysql_type) const; + int get_ob_type(ObObjType &ob_type, obmysql::EMySQLFieldType mysql_type) const; + +protected: ObMySQLConnection *conn_; - ObArenaAllocator arena_allocator_; // TODO: used right allocator? + ObArenaAllocator arena_allocator_; ObIAllocator *alloc_; // bind to arena_allocator_ ObMySQLPreparedParam param_; ObMySQLPreparedResult result_; int64_t stmt_param_count_; + int64_t result_column_count_; MYSQL_STMT *stmt_; + ObBindParam *bind_params_; + ObBindParam *result_params_; +}; + +class ObMySQLProcStatement : public ObMySQLPreparedStatement +{ +public: + ObMySQLProcStatement() + { + } + ~ObMySQLProcStatement() + { + } + int execute_proc(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + const ObTimeZoneInfo *tz_info); + +private: + int bind_proc_param(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + common::ObIArray &basic_out_param, + const ObTimeZoneInfo *tz_info); + int bind_param(const int64_t col_idx, + const bool is_output_param, + const ObTimeZoneInfo *tz_info, + ObObjParam &obj, + const share::schema::ObRoutineInfo &routine_info, + ObIAllocator &allocator); + int process_proc_output_params(ObIAllocator &allocator, + ParamStore ¶ms, + const share::schema::ObRoutineInfo &routine_info, + common::ObIArray &basic_out_param, + const ObTimeZoneInfo *tz_info); + int convert_proc_output_param_result(const ObTimeZoneInfo &tz_info, + const ObBindParam &bind_param, + ObObjParam ¶m, + const share::schema::ObRoutineInfo &routine_info, + ObIAllocator &allocator); }; } //namespace sqlclient } diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.cpp index 1bdc18c81..2398d3cf5 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.cpp @@ -615,6 +615,130 @@ int ObDbLinkProxy::dblink_write(ObISQLConnection *dblink_conn, int64_t &affected return ret; } +int ObDbLinkProxy::dblink_execute_proc(ObISQLConnection *dblink_conn) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn)); + } else if (OB_FAIL(dblink_conn->execute_proc())) { + LOG_WARN("execute_proc failed", K(ret)); + } + return ret; +} + + +int ObDbLinkProxy::dblink_prepare(sqlclient::ObISQLConnection *dblink_conn, const char *sql) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn) || OB_ISNULL(sql)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn), KP(sql)); + } else if (OB_FAIL(dblink_conn->prepare(sql))) { + LOG_WARN("prepare to dblink failed", K(ret), K(ObString(sql))); + } + return ret; +} + +int ObDbLinkProxy::dblink_bind_basic_type_by_pos(sqlclient::ObISQLConnection *dblink_conn, + uint64_t position, + void *param, + int64_t param_size, + int32_t datatype, + int32_t &indicator) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn)); + } else if (OB_FAIL(dblink_conn->bind_basic_type_by_pos(position, param, param_size, datatype, indicator))) { + LOG_WARN("bind_basic_type_by_pos to dblink failed", K(ret)); + } else { + LOG_DEBUG("succ to bind_basic_type_by_pos dblink", K(ret)); + } + return ret; +} + +int ObDbLinkProxy::dblink_bind_array_type_by_pos(sqlclient::ObISQLConnection *dblink_conn, + uint64_t position, + void *array, + int32_t *indicators, + int64_t ele_size, + int32_t ele_datatype, + uint64_t array_size, + uint32_t *out_valid_array_size) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn)); + } else if (OB_FAIL(dblink_conn->bind_array_type_by_pos(position, array, indicators, ele_size, ele_datatype, + array_size, out_valid_array_size))) { + LOG_WARN("bind_array_type_by_pos failed", K(ret)); + } else { + LOG_DEBUG("succ to bind_array_type_by_pos dblink", K(ret)); + } + return ret; +} + +int ObDbLinkProxy::dblink_get_server_major_version(sqlclient::ObISQLConnection *dblink_conn, + int64_t &major_version) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn)); + } else if (OB_FAIL(dblink_conn->get_server_major_version(major_version))) { + LOG_WARN("get server major version failed", K(ret)); + } + return ret; +} + +int ObDbLinkProxy::dblink_get_package_udts(common::sqlclient::ObISQLConnection *dblink_conn, + ObIAllocator &alloctor, + const common::ObString &database_name, + const common::ObString &package_name, + common::ObIArray &udts, + uint64_t dblink_id, + uint64_t &next_object_id) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn)); + } else if (OB_FAIL(dblink_conn->get_package_udts(alloctor, + database_name, + package_name, + udts, + dblink_id, + next_object_id))) { + LOG_WARN("get package udts failed", K(ret), K(database_name), K(package_name)); + } + return ret; +} + +int ObDbLinkProxy::dblink_execute_proc(const uint64_t tenant_id, + sqlclient::ObISQLConnection *dblink_conn, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) +{ + int ret = OB_SUCCESS; + if (OB_ISNULL(dblink_conn) || sql.empty()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null ptr", K(ret), KP(dblink_conn), K(sql)); + } else if (OB_FAIL(dblink_conn->execute_proc(tenant_id, allocator, params, sql, + routine_info, udts, tz_info))) { + LOG_WARN("call procedure to dblink failed", K(ret), K(dblink_conn), K(sql)); + } else { + LOG_DEBUG("succ to call procedure by dblink", K(sql)); + } + return ret; +} + int ObDbLinkProxy::rollback(ObISQLConnection *dblink_conn) { int ret = OB_SUCCESS; diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.h b/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.h index a4ba3210a..7e572ffba 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.h +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_proxy.h @@ -180,6 +180,39 @@ public: int release_dblink(sqlclient::DblinkDriverProto dblink_type, sqlclient::ObISQLConnection *dblink_conn); int dblink_read(sqlclient::ObISQLConnection *dblink_conn, ReadResult &result, const char *sql); int dblink_write(sqlclient::ObISQLConnection *dblink_conn, int64_t &affected_rows, const char *sql); + int dblink_execute_proc(sqlclient::ObISQLConnection *dblink_conn); + int dblink_execute_proc(const uint64_t tenant_id, + sqlclient::ObISQLConnection *dblink_conn, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info); + int dblink_prepare(sqlclient::ObISQLConnection *dblink_conn, const char *sql); + int dblink_bind_basic_type_by_pos(sqlclient::ObISQLConnection *dblink_conn, + uint64_t position, + void *param, + int64_t param_size, + int32_t datatype, + int32_t &indicator); + int dblink_bind_array_type_by_pos(sqlclient::ObISQLConnection *dblink_conn, + uint64_t position, + void *array, + int32_t *indicators, + int64_t ele_size, + int32_t ele_datatype, + uint64_t array_size, + uint32_t *out_valid_array_size); + int dblink_get_server_major_version(sqlclient::ObISQLConnection *dblink_conn, + int64_t &major_version); + int dblink_get_package_udts(common::sqlclient::ObISQLConnection *dblink_conn, + ObIAllocator &alloctor, + const common::ObString &database_name, + const common::ObString &package_name, + common::ObIArray &udts, + uint64_t dblink_id, + uint64_t &next_object_id); int rollback(sqlclient::ObISQLConnection *dblink_conn); int switch_dblink_conn_pool(sqlclient::DblinkDriverProto type, sqlclient::ObISQLConnectionPool *&dblink_conn_pool); int set_dblink_pool_charset(uint64_t dblink_id); diff --git a/deps/oblib/src/lib/mysqlclient/ob_mysql_statement.cpp b/deps/oblib/src/lib/mysqlclient/ob_mysql_statement.cpp index 513dd3853..af2cd08ac 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_mysql_statement.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_mysql_statement.cpp @@ -156,8 +156,8 @@ ObMySQLResult *ObMySQLStatement::execute_query(bool enable_use_result) char errmsg[256] = {0}; const char *srcmsg = mysql_error(stmt_); MEMCPY(errmsg, srcmsg, MIN(255, STRLEN(srcmsg))); - const int ER_LOCK_WAIT_TIMEOUT = -1205; - if (ER_LOCK_WAIT_TIMEOUT == ret) { + const int ERR_LOCK_WAIT_TIMEOUT = -1205; + if (ERR_LOCK_WAIT_TIMEOUT == ret) { LOG_INFO("fail to query server", "sessid", conn_->get_sessid(), "host", stmt_->host, "port", stmt_->port, "err_msg", errmsg, K(ret), K(sql_str_)); } else { diff --git a/deps/oblib/src/lib/mysqlclient/ob_single_connection_proxy.cpp b/deps/oblib/src/lib/mysqlclient/ob_single_connection_proxy.cpp index d1d006063..4c7c63d9d 100644 --- a/deps/oblib/src/lib/mysqlclient/ob_single_connection_proxy.cpp +++ b/deps/oblib/src/lib/mysqlclient/ob_single_connection_proxy.cpp @@ -81,8 +81,8 @@ int ObSingleConnectionProxy::read(ReadResult &res, LOG_WARN("check inner stat failed"); } else if (OB_FAIL(conn_->execute_read(tenant_id, sql, res))) { errno_ = ret; - const int ER_LOCK_WAIT_TIMEOUT = -1205; - if (ER_LOCK_WAIT_TIMEOUT == ret) { + const int ERR_LOCK_WAIT_TIMEOUT = -1205; + if (ERR_LOCK_WAIT_TIMEOUT == ret) { LOG_INFO("execute query failed", K(ret), KCSTRING(sql), K_(conn)); } else { LOG_WARN("execute query failed", K(ret), KCSTRING(sql), K_(conn)); @@ -103,8 +103,8 @@ int ObSingleConnectionProxy::read(ReadResult &res, LOG_WARN("check inner stat failed"); } else if (OB_FAIL(conn_->execute_read(cluster_id, tenant_id, sql, res))) { errno_ = ret; - const int ER_LOCK_WAIT_TIMEOUT = -1205; - if (ER_LOCK_WAIT_TIMEOUT == ret) { + const int ERR_LOCK_WAIT_TIMEOUT = -1205; + if (ERR_LOCK_WAIT_TIMEOUT == ret) { LOG_INFO("execute query failed", K(ret), K(sql), K_(conn), K(cluster_id)); } else { LOG_WARN("execute query failed", K(ret), K(sql), K_(conn), K(cluster_id)); diff --git a/deps/oblib/src/lib/ob_define.h b/deps/oblib/src/lib/ob_define.h index 5d6f1c1c6..03a0e6332 100644 --- a/deps/oblib/src/lib/ob_define.h +++ b/deps/oblib/src/lib/ob_define.h @@ -1304,6 +1304,8 @@ const uint64_t OB_MOCK_TRIGGER_PACKAGE_ID_MASK = 0x4000000000000000; const uint64_t OB_MOCK_OBJECT_PACAKGE_ID_MASK = 0x2000000000000000; // 64bit : use for mock package spec/body mask, 0 means spec, 1 means body const uint64_t OB_MOCK_PACKAGE_BODY_ID_MASK = 0x8000000000000000; +// 61bit : use for mock dblink udt id +const uint64_t OB_MOCK_DBLINK_UDT_ID_MASK = 0x1000000000000000; /* low 21bits used as package type id */ #define OB_MOCK_MASK_SHIFT 40 #define OB_PACKAGE_ID_SHIFT 24 @@ -1311,7 +1313,8 @@ OB_INLINE uint64_t extract_package_id(uint64_t global_type_id) { uint64_t mask = OB_MOCK_PACKAGE_BODY_ID_MASK | OB_MOCK_TRIGGER_PACKAGE_ID_MASK | - OB_MOCK_OBJECT_PACAKGE_ID_MASK; + OB_MOCK_OBJECT_PACAKGE_ID_MASK | + OB_MOCK_DBLINK_UDT_ID_MASK; uint64_t mock_val = global_type_id & (mask >> OB_MOCK_MASK_SHIFT); uint64_t package_id = ((int64_t)global_type_id >> OB_PACKAGE_ID_SHIFT) | (mock_val << OB_MOCK_MASK_SHIFT); @@ -1320,14 +1323,15 @@ OB_INLINE uint64_t extract_package_id(uint64_t global_type_id) OB_INLINE int64_t extract_type_id(uint64_t global_type_id) { - return global_type_id & (~(UINT64_MAX << (OB_PACKAGE_ID_SHIFT - 3))); + return global_type_id & (~(UINT64_MAX << (OB_PACKAGE_ID_SHIFT - 4))); } OB_INLINE uint64_t combine_pl_type_id(uint64_t package_id, int64_t type_idx) { uint64_t mask = OB_MOCK_PACKAGE_BODY_ID_MASK | OB_MOCK_TRIGGER_PACKAGE_ID_MASK | - OB_MOCK_OBJECT_PACAKGE_ID_MASK; + OB_MOCK_OBJECT_PACAKGE_ID_MASK | + OB_MOCK_DBLINK_UDT_ID_MASK; type_idx |= ((uint64_t)(package_id & mask) >> OB_MOCK_MASK_SHIFT); return (package_id << OB_PACKAGE_ID_SHIFT | type_idx); } @@ -1348,6 +1352,13 @@ OB_INLINE bool is_inner_pl_object_id(const uint64_t object_id) && object_id < OB_MAX_SYS_PL_OBJECT_ID; } +OB_INLINE bool is_dblink_type_id(uint64_t type_id) +{ + return type_id != common::OB_INVALID_ID + && ((type_id << OB_MOCK_MASK_SHIFT) & OB_MOCK_DBLINK_UDT_ID_MASK) != 0; +} + + /* ################################################################################ */ const char* const OB_PRIMARY_INDEX_NAME = "PRIMARY"; diff --git a/src/observer/ob_inner_sql_connection.cpp b/src/observer/ob_inner_sql_connection.cpp index c69c514d0..c5e84824b 100644 --- a/src/observer/ob_inner_sql_connection.cpp +++ b/src/observer/ob_inner_sql_connection.cpp @@ -1403,6 +1403,19 @@ int ObInnerSQLConnection::execute_write(const uint64_t tenant_id, const ObString return ret; } +int ObInnerSQLConnection::execute_proc(const uint64_t tenant_id, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) +{ + UNUSEDx(tenant_id, allocator, params, sql, routine_info, udts, tz_info); + int ret = OB_SUCCESS; + return ret; +} + int ObInnerSQLConnection::execute_write_inner(const uint64_t tenant_id, const ObString &sql, int64_t &affected_rows, bool is_user_sql, const common::ObAddr *sql_exec_addr) { diff --git a/src/observer/ob_inner_sql_connection.h b/src/observer/ob_inner_sql_connection.h index 51e9c02b7..8d2a9ab53 100644 --- a/src/observer/ob_inner_sql_connection.h +++ b/src/observer/ob_inner_sql_connection.h @@ -156,6 +156,13 @@ public: virtual int execute_write(const uint64_t tenant_id, const ObString &sql, int64_t &affected_rows, bool is_user_sql = false, const common::ObAddr *sql_exec_addr = nullptr) override; + virtual int execute_proc(const uint64_t tenant_id, + ObIAllocator &allocator, + ParamStore ¶ms, + ObString &sql, + const share::schema::ObRoutineInfo &routine_info, + const common::ObIArray &udts, + const ObTimeZoneInfo *tz_info) override; virtual int start_transaction(const uint64_t &tenant_id, bool with_snap_shot = false) override; virtual int register_multi_data_source(const uint64_t &tenant_id, const share::ObLSID ls_id, diff --git a/src/pl/CMakeLists.txt b/src/pl/CMakeLists.txt index 88cf20391..f48e59993 100644 --- a/src/pl/CMakeLists.txt +++ b/src/pl/CMakeLists.txt @@ -53,4 +53,8 @@ ob_set_subtarget(ob_pl sys_package sys_package/ob_dbms_user_define_rule.cpp ) +ob_set_subtarget(ob_pl dblink + dblink/ob_pl_dblink_guard.cpp +) + ob_server_add_target(ob_pl) diff --git a/src/pl/dblink/ob_pl_dblink_guard.cpp b/src/pl/dblink/ob_pl_dblink_guard.cpp new file mode 100644 index 000000000..59942f89e --- /dev/null +++ b/src/pl/dblink/ob_pl_dblink_guard.cpp @@ -0,0 +1,444 @@ +/** + * 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 PL + +#include "ob_pl_dblink_guard.h" +#include "share/rc/ob_tenant_base.h" +#include "pl/ob_pl_type.h" +#include "sql/dblink/ob_dblink_utils.h" +#include "sql/session/ob_sql_session_info.h" +#include "pl/ob_pl_stmt.h" +#ifdef OB_BUILD_ORACLE_PL +#include "lib/oracleclient/ob_oci_metadata.h" +#include "pl/dblink/ob_pl_dblink_util.h" +#endif + +namespace oceanbase +{ +namespace pl +{ +typedef common::sqlclient::DblinkDriverProto DblinkDriverProto; + +int ObPLDbLinkGuard::get_routine_infos_with_synonym(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const ObString &dblink_name, + const ObString &part1, + const ObString &part2, + const ObString &part3, + common::ObIArray &routine_infos) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + const uint64_t tenant_id = MTL_ID(); + const ObDbLinkSchema *dblink_schema = NULL; + DblinkDriverProto link_type = common::sqlclient::DBLINK_UNKNOWN; + common::sqlclient::dblink_param_ctx param_ctx; + param_ctx.pool_type_ = common::sqlclient::DblinkPoolType::DBLINK_POOL_SCHEMA; + common::ObDbLinkProxy *dblink_proxy = NULL; + common::sqlclient::ObISQLConnection *dblink_conn = NULL; + ObString full_name; + ObString schema_name; + ObString object_name; + ObString sub_object_name; + int64_t object_type; + OZ (schema_guard.get_dblink_schema(tenant_id, dblink_name, dblink_schema), tenant_id, dblink_name); + OV (OB_NOT_NULL(dblink_schema), OB_DBLINK_NOT_EXIST_TO_ACCESS, dblink_name); + OX (link_type = static_cast(dblink_schema->get_driver_proto())); + OZ (ObPLDblinkUtil::init_dblink(dblink_proxy, dblink_conn, session_info, schema_guard, dblink_name)); + CK (OB_NOT_NULL(dblink_proxy)); + CK (OB_NOT_NULL(dblink_conn)); + OZ (ObPLDblinkUtil::print_full_name(alloc_, full_name, part1, part2, part3)); + OZ (dblink_name_resolve(dblink_proxy, + dblink_conn, + dblink_schema, + full_name, + schema_name, + object_name, + sub_object_name, + object_type, + alloc_)); + OZ (get_dblink_routine_infos(session_info, + schema_guard, + dblink_name, + schema_name, + object_name, + sub_object_name, + routine_infos)); +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_type_with_synonym(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const ObString &dblink_name, + const ObString &part1, + const ObString &part2, + const ObString &part3, + const pl::ObUserDefinedType *&udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + common::ObDbLinkProxy *dblink_proxy = NULL; + common::sqlclient::ObISQLConnection *dblink_conn = NULL; + OZ (ObPLDblinkUtil::init_dblink(dblink_proxy, dblink_conn, session_info, schema_guard, dblink_name)); + CK (OB_NOT_NULL(dblink_proxy)); + CK (OB_NOT_NULL(dblink_conn)); + if (OB_SUCC(ret)) { + ObString full_name; + ObString schema_name; + ObString object_name; + ObString sub_object_name; + int64_t object_type; + const ObDbLinkSchema *dblink_schema = NULL; + OZ (schema_guard.get_dblink_schema(MTL_ID(), dblink_name, dblink_schema), dblink_name); + OV (OB_NOT_NULL(dblink_schema), OB_ERR_UNEXPECTED, dblink_name); + OZ (ObPLDblinkUtil::print_full_name(alloc_, full_name, part1, part2, part3)); + OZ (dblink_name_resolve(dblink_proxy, + dblink_conn, + dblink_schema, + full_name, + schema_name, + object_name, + sub_object_name, + object_type, + alloc_)); + OV (static_cast(ObObjectType::PACKAGE) == object_type); + OZ (get_dblink_type_by_name(session_info, + schema_guard, + dblink_name, + schema_name, + object_name, + sub_object_name, + udt)); + } +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_routine_infos(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const ObString &dblink_name, + const ObString &db_name, + const ObString &pkg_name, + const ObString &routine_name, + common::ObIArray &routine_infos) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + routine_infos.reset(); + const uint64_t tenant_id = MTL_ID(); + uint64_t dblink_id = OB_INVALID_ID; + const share::schema::ObDbLinkSchema *dblink_schema = NULL; + const ObPLDbLinkInfo *dblink_info = NULL; + OZ (schema_guard.get_dblink_schema(tenant_id, dblink_name, dblink_schema)); + OX (dblink_id = dblink_schema->get_dblink_id()); + OV (OB_INVALID_ID != dblink_id, OB_DBLINK_NOT_EXIST_TO_ACCESS, dblink_id); + OZ (get_dblink_info(dblink_id, dblink_info)); + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(dblink_info)) { + ObPLDbLinkInfo *new_dblink_info = static_cast(alloc_.alloc(sizeof(ObPLDbLinkInfo))); + if (OB_ISNULL(new_dblink_info)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } else { + new_dblink_info = new (new_dblink_info)ObPLDbLinkInfo(); + new_dblink_info->set_dblink_id(dblink_id); + dblink_info = new_dblink_info; + OZ (dblink_infos_.push_back(dblink_info)); + } + } + OZ ((const_cast(dblink_info))->get_routine_infos(session_info, + schema_guard, + alloc_, + dblink_name, + db_name, + pkg_name, + routine_name, + routine_infos, + next_link_object_id_)); + if (OB_SUCC(ret)) { + bool is_all_func = true; + for (int64_t i = 0; OB_SUCC(ret) && i < routine_infos.count(); i++) { + const ObRoutineInfo *r = static_cast(routine_infos.at(i)); + CK (OB_NOT_NULL(r)); + if (OB_SUCC(ret) && ObRoutineType::ROUTINE_PROCEDURE_TYPE == r->get_routine_type()) { + is_all_func = false; + break; + } + } + if (OB_SUCC(ret) && is_all_func) { + ret = OB_ERR_NOT_VALID_ROUTINE_NAME; + LOG_WARN("ORA-06576: not a valid function or procedure name", K(ret), K(pkg_name), K(routine_name)); + } + } +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_routine_info(uint64_t dblink_id, + uint64_t pkg_id, + uint64_t routine_id, + const share::schema::ObRoutineInfo *&routine_info) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + const ObPLDbLinkInfo *dblink_info = NULL; + if (OB_FAIL(get_dblink_info(dblink_id, dblink_info))) { + LOG_WARN("get dblink info failed", K(ret), K(dblink_id)); + } else if (OB_ISNULL(dblink_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("dblink_info is null", K(ret), K(dblink_id)); + } else if (OB_FAIL(dblink_info->get_routine_info(pkg_id, routine_id, routine_info))) { + LOG_WARN("get routine info failed", K(ret), KP(dblink_info), K(pkg_id), K(routine_id)); + } +#endif + return ret; +} + +int ObPLDbLinkGuard::dblink_name_resolve(common::ObDbLinkProxy *dblink_proxy, + common::sqlclient::ObISQLConnection *dblink_conn, + const ObDbLinkSchema *dblink_schema, + const common::ObString &full_name, + common::ObString &schema, + common::ObString &object_name, + common::ObString &sub_object_name, + int64_t &object_type, + ObIAllocator &alloctor) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + /* + * dbms_utility.sql + * PROCEDURE NAME_RESOLVE (NAME IN VARCHAR2, + * CONTEXT IN NUMBER, + * SCHEMA1 OUT VARCHAR2, + * PART1 OUT VARCHAR2, + * PART2 OUT VARCHAR2, + * DBLINK OUT VARCHAR2, + * PART1_TYPE OUT NUMBER, + * OBJECT_NUMBER OUT NUMBER); + * + */ + const char *call_proc = "declare " + " object_number number; " + "begin " + " dbms_utility.name_resolve(:name, " + " :context, " + " :schema1, " + " :part1, " + " :part2, " + " :dblink, " + " :part1_type, " + " object_number); " + "end; "; + if (OB_ISNULL(dblink_proxy)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("dblink_proxy is NULL", K(ret)); + } else if (OB_FAIL(dblink_proxy->dblink_prepare(dblink_conn, call_proc))) { + LOG_WARN("prepare sql failed", K(ret), K(ObString(call_proc))); + } + if (OB_SUCC(ret)) { + ObString full_name_copy = full_name; + const int64_t ident_size = pl::OB_MAX_PL_IDENT_LENGTH + 1; + int context = 1; + char schema1[ident_size]; + char part1[ident_size]; + char part2[ident_size]; + char dblink[ident_size]; + int part1_type = -1; + int32_t indicator = 0; + memset(schema1, 0, ident_size); + memset(part1, 0, ident_size); + memset(part2, 0, ident_size); + memset(dblink, 0, ident_size); + int32_t oci_sql_str = static_cast(OciDataType::OCI_SQLT_STR); + int32_t oci_sql_int = static_cast(OciDataType::OCI_SQLT_INT); +#define BIND_BASIC_BY_POS(param_pos, param, param_size, param_type) \ + if (FAILEDx(dblink_proxy->dblink_bind_basic_type_by_pos(dblink_conn, \ + param_pos, \ + param, \ + param_size, \ + param_type, \ + indicator))) { \ + LOG_WARN("bind param failed", K(ret), K(param_pos), K(param_size), K(param_type)); \ + } + BIND_BASIC_BY_POS(1, full_name_copy.ptr(), static_cast(full_name_copy.length() + 1), oci_sql_str); + BIND_BASIC_BY_POS(2, &context, static_cast(sizeof(int)), oci_sql_int); + BIND_BASIC_BY_POS(3, schema1, ident_size, oci_sql_str); + BIND_BASIC_BY_POS(4, part1, ident_size, oci_sql_str); + BIND_BASIC_BY_POS(5, part2, ident_size, oci_sql_str); + BIND_BASIC_BY_POS(6, dblink, ident_size, oci_sql_str); + BIND_BASIC_BY_POS(7, &part1_type, static_cast(sizeof(int)), oci_sql_int); + if (FAILEDx(dblink_proxy->dblink_execute_proc(dblink_conn))) { + const DblinkDriverProto link_type = static_cast(dblink_schema->get_driver_proto()); + LOG_WARN("read link failed", K(ret), K(ObString(call_proc))); + } else { + switch (part1_type) { + case OracleObjectType::ORA_PROCEUDRE: + // procedure + object_type = static_cast(ObObjectType::PROCEDURE); + break; + case OracleObjectType::ORA_PACKAGE: + // package + object_type = static_cast(ObObjectType::PACKAGE); + break; + default: { + ret = OB_ERR_NOT_VALID_ROUTINE_NAME; + LOG_WARN("remote object type not support", K(ret), K(full_name)); + } + } + OZ (ob_write_string(alloctor, ObString(schema1), schema)); + OZ (ob_write_string(alloctor, ObString(part1), object_name)); + OZ (ob_write_string(alloctor, ObString(part2), sub_object_name)); + } +#undef BIND_BASIC_BY_POS + } + if ((NULL != dblink_conn)) { + int tmp_ret = OB_SUCCESS; + if (OB_SUCCESS != (tmp_ret = static_cast(dblink_conn)->free_oci_stmt())) { + LOG_WARN("failed to close oci result", K(tmp_ret)); + if (OB_SUCC(ret)) { + ret = tmp_ret; + } + } + } +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_type_by_name(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const common::ObString &dblink_name, + const common::ObString &db_name, + const common::ObString &pkg_name, + const common::ObString &udt_name, + const pl::ObUserDefinedType *&udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + const uint64_t tenant_id = MTL_ID(); + uint64_t dblink_id = OB_INVALID_ID; + const share::schema::ObDbLinkSchema *dblink_schema = NULL; + const ObPLDbLinkInfo *dblink_info = NULL; + OZ (schema_guard.get_dblink_schema(tenant_id, dblink_name, dblink_schema)); + OV (OB_NOT_NULL(dblink_schema), OB_DBLINK_NOT_EXIST_TO_ACCESS, dblink_name); + OV (OB_INVALID_ID != (dblink_id = dblink_schema->get_dblink_id()), OB_DBLINK_NOT_EXIST_TO_ACCESS, dblink_id); + OZ (get_dblink_info(dblink_id, dblink_info)); + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(dblink_info)) { + ObPLDbLinkInfo *new_dblink_info = static_cast(alloc_.alloc(sizeof(ObPLDbLinkInfo))); + if (OB_ISNULL(new_dblink_info)) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("allocate memory failed", K(ret)); + } else { + new_dblink_info = new (new_dblink_info)ObPLDbLinkInfo(); + new_dblink_info->set_dblink_id(dblink_id); + dblink_info = new_dblink_info; + OZ (dblink_infos_.push_back(dblink_info)); + } + } + OZ ((const_cast(dblink_info))->get_udt_by_name(session_info, + schema_guard, alloc_, dblink_name, db_name, pkg_name, + udt_name, udt, next_link_object_id_)); +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_type_by_id(const uint64_t mask_dblink_id, + const uint64_t udt_id, + const pl::ObUserDefinedType *&udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + uint64_t dblink_id = mask_dblink_id & ~common::OB_MOCK_DBLINK_UDT_ID_MASK; + const ObPLDbLinkInfo *dblink_info = NULL; + for (int64_t i = 0; OB_SUCC(ret) && OB_ISNULL(dblink_info) && i < dblink_infos_.count(); i++) { + if (OB_ISNULL(dblink_infos_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("dblink_info is null", K(ret), K(i)); + } else if (dblink_id == dblink_infos_.at(i)->get_dblink_id()) { + dblink_info = dblink_infos_.at(i); + OZ (dblink_info->get_udt_by_id(udt_id, udt)); + } + } +#endif + return ret; +} + +int ObPLDbLinkGuard::get_dblink_type_by_name(const uint64_t dblink_id, + const common::ObString &db_name, + const common::ObString &pkg_name, + const common::ObString &udt_name, + const pl::ObUserDefinedType *&udt) +{ + int ret = OB_SUCCESS; +#ifndef OB_BUILD_ORACLE_PL + ret = OB_NOT_SUPPORTED; + LOG_USER_ERROR(OB_NOT_SUPPORTED, "PL dblink"); +#else + const ObPLDbLinkInfo *dblink_info = NULL; + for (int64_t i = 0; OB_SUCC(ret) && i < dblink_infos_.count(); i++) { + if (OB_ISNULL(dblink_infos_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("dblink_info is null", K(ret), K(i)); + } else if (dblink_id == dblink_infos_.at(i)->get_dblink_id()) { + dblink_info = dblink_infos_.at(i); + bool find_pkg = false; + OZ (dblink_info->get_udt_from_cache(db_name, pkg_name, udt_name, udt, find_pkg)); + break; + } + } +#endif + return ret; +} + +#ifdef OB_BUILD_ORACLE_PL +int ObPLDbLinkGuard::get_dblink_info(const uint64_t dblink_id, + const ObPLDbLinkInfo *&dblink_info) +{ + int ret = OB_SUCCESS; + for (int64_t i = 0; OB_SUCC(ret) && OB_ISNULL(dblink_info) && i < dblink_infos_.count(); i++) { + if (OB_ISNULL(dblink_infos_.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("dblink_info is null", K(ret), K(i)); + } else { + dblink_info = dblink_infos_.at(i); + } + } + return ret; +} +#endif + +} +} diff --git a/src/pl/dblink/ob_pl_dblink_guard.h b/src/pl/dblink/ob_pl_dblink_guard.h new file mode 100644 index 000000000..4a33d0692 --- /dev/null +++ b/src/pl/dblink/ob_pl_dblink_guard.h @@ -0,0 +1,141 @@ +/** + * 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. + */ + +#ifndef SRC_PL_OB_PL_DBLINK_GUARD_H_ +#define SRC_PL_OB_PL_DBLINK_GUARD_H_ + +#include "share/schema/ob_routine_info.h" +#include "share/schema/ob_schema_struct.h" +#include "share/schema/ob_schema_utils.h" +#include "pl/ob_pl_user_type.h" +#include "lib/string/ob_string.h" +#include "lib/container/ob_se_array.h" +#include "share/schema/ob_schema_getter_guard.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/dblink/ob_pl_dblink_info.h" +#endif + +namespace oceanbase +{ +using namespace sql; +namespace share +{ +namespace schema +{ +class ObRoutineInfo; +class ObIRoutineInfo; +class ObDbLinkSchema; +} +} +namespace pl +{ + +typedef share::schema::ObDbLinkSchema ObDbLinkSchema; +typedef share::schema::ObObjectType ObObjectType; +typedef share::schema::ObIRoutineInfo ObIRoutineInfo; +typedef share::schema::ObRoutineInfo ObRoutineInfo; +typedef share::schema::ObRoutineType ObRoutineType; +typedef share::schema::ObRoutineParam ObRoutineParam; +typedef share::schema::ObSchemaUtils ObSchemaUtils; +typedef oceanbase::common::ObSqlString ObSqlString; +class ObPLDbLinkGuard +{ +public: + ObPLDbLinkGuard(common::ObArenaAllocator &alloc) : alloc_(alloc) + { + reset(); + } + ~ObPLDbLinkGuard() + { + reset(); + } + void reset() + { +#ifdef OB_BUILD_ORACLE_PL + dblink_infos_.reset(); +#endif + next_link_object_id_ = 1; + } + int get_routine_infos_with_synonym(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const common::ObString &dblink_name, + const common::ObString &part1, + const common::ObString &part2, + const common::ObString &part3, + common::ObIArray &routine_infos); + int get_dblink_type_with_synonym(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const common::ObString &dblink_name, + const common::ObString &part1, + const common::ObString &part2, + const common::ObString &part3, + const pl::ObUserDefinedType *&udt); + + int get_dblink_routine_info(uint64_t dblink_id, + uint64_t pkg_id, + uint64_t routine_id, + const share::schema::ObRoutineInfo *&routine_info); + + int get_dblink_type_by_id(const uint64_t mask_dblink_id, + const uint64_t udt_id, + const pl::ObUserDefinedType *&udt); + + int get_dblink_type_by_name(const uint64_t dblink_id, + const common::ObString &db_name, + const common::ObString &pkg_name, + const common::ObString &udt_name, + const pl::ObUserDefinedType *&udt); +#ifdef OB_BUILD_ORACLE_PL + int get_dblink_info(const uint64_t dblink_id, + const ObPLDbLinkInfo *&dblink_info); +#endif + +private: + int dblink_name_resolve(common::ObDbLinkProxy *dblink_proxy, + common::sqlclient::ObISQLConnection *dblink_conn, + const ObDbLinkSchema *dblink_schema, + const common::ObString &full_name, + common::ObString &schema, + common::ObString &object_name, + common::ObString &sub_object_name, + int64_t &object_type, + ObIAllocator &alloctor); + + int get_dblink_routine_infos(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const common::ObString &dblink_name, + const common::ObString &db_name, + const common::ObString &pkg_name, + const common::ObString &routine_name, + common::ObIArray &routine_infos); + + int get_dblink_type_by_name(sql::ObSQLSessionInfo &session_info, + share::schema::ObSchemaGetterGuard &schema_guard, + const common::ObString &dblink_name, + const common::ObString &db_name, + const common::ObString &pkg_name, + const common::ObString &udt_name, + const pl::ObUserDefinedType *&udt); + +private: + uint64_t next_link_object_id_; + common::ObArenaAllocator &alloc_; +#ifdef OB_BUILD_ORACLE_PL + common::ObSEArray dblink_infos_; +#endif +}; + + +} +} + +#endif diff --git a/src/pl/ob_pl.cpp b/src/pl/ob_pl.cpp index 518c92701..d9607bb48 100644 --- a/src/pl/ob_pl.cpp +++ b/src/pl/ob_pl.cpp @@ -48,7 +48,7 @@ #include "pl/debug/ob_pl_debugger_manager.h" #endif #include "pl/pl_cache/ob_pl_cache_mgr.h" -#include "src/sql/engine/dml/ob_trigger_handler.h" +#include "sql/engine/dml/ob_trigger_handler.h" namespace oceanbase { using namespace common; @@ -239,7 +239,8 @@ int ObPL::execute_proc(ObPLExecCtx &ctx, uint64_t loc, int64_t argc, common::ObObjParam **argv, - int64_t *nocopy_argv) + int64_t *nocopy_argv, + uint64_t dblink_id) { int ret = OB_SUCCESS; lib::MemoryContext mem_context; @@ -253,7 +254,7 @@ int ObPL::execute_proc(ObPLExecCtx &ctx, || (NULL != subprogram_path && 0 == path_length) || (NULL == nocopy_argv && argc > 0)) { ret = OB_ERR_UNEXPECTED; - LOG_WARN("argument is NULL", + LOG_WARN("argument is NULL", K(GCTX.schema_service_), K(ctx.exec_ctx_), K(ctx.result_), @@ -298,7 +299,21 @@ int ObPL::execute_proc(ObPLExecCtx &ctx, } } } - if (OB_SUCC(ret)) { + if (OB_FAIL(ret)) { +#ifdef OB_BUILD_ORACLE_PL + } else if (OB_INVALID_ID != dblink_id) { + if (OB_FAIL(ObSPIService::spi_execute_dblink(&ctx, dblink_id, package_id, proc_id, proc_params))) { + LOG_WARN("execute dblink routine failed", K(ret)); + } + if (OB_SUCC(ret)) { + if (NULL != argv && argc > 0) { + for (int64_t i = 0; OB_SUCC(ret) && i < argc; ++i) { + *argv[i] = proc_params.at(i); + } + } + } +#endif + } else { share::schema::ObSchemaGetterGuard schema_guard; const uint64_t tenant_id = ctx.exec_ctx_->get_my_session()->get_effective_tenant_id(); if (OB_FAIL(GCTX.schema_service_->get_tenant_schema_guard(tenant_id, schema_guard))) { diff --git a/src/pl/ob_pl.h b/src/pl/ob_pl.h index 9fa16bdcf..a44d88f9d 100644 --- a/src/pl/ob_pl.h +++ b/src/pl/ob_pl.h @@ -1182,7 +1182,8 @@ public: uint64_t line_num, /* call position line number, for call_stack info*/ int64_t argc, common::ObObjParam **argv, - int64_t *nocopy_argv); + int64_t *nocopy_argv, + uint64_t dblink_id); static int set_user_type_var(ObPLExecCtx *ctx, int64_t var_index, diff --git a/src/pl/ob_pl_code_generator.cpp b/src/pl/ob_pl_code_generator.cpp index 8b976bcda..cce567989 100644 --- a/src/pl/ob_pl_code_generator.cpp +++ b/src/pl/ob_pl_code_generator.cpp @@ -2755,6 +2755,10 @@ int ObPLCodeGenerateVisitor::visit(const ObPLCallStmt &s) LOG_WARN("failed to get int64_t array", K(ret)); } else if (OB_FAIL(args.push_back(nocopy_array_value))) { LOG_WARN("failed to push back", K(ret)); + } else if (OB_FAIL(generator_.get_helper().get_int64(s.get_dblink_id(), int_value))) { + LOG_WARN("failed to get int64", K(ret)); + } else if (OB_FAIL(args.push_back(int_value))) { //PL的dblink id + LOG_WARN("push_back error", K(ret)); } else { ObLLVMValue result; if (NULL == generator_.get_current_exception()) { @@ -3574,6 +3578,8 @@ int ObPLCodeGenerator::init() LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(arg_types.push_back(int64_pointer_type))) { //int64_t* nocopy params LOG_WARN("push_back error", K(ret)); + } else if (OB_FAIL(arg_types.push_back(int64_type))) { //int64_t dblink id + LOG_WARN("push_back error", K(ret)); } else if (OB_FAIL(ObLLVMFunctionType::get(int32_type, arg_types, ft))) { LOG_WARN("failed to get function type", K(ret)); } else if (OB_FAIL(helper_.create_function(ObString("pl_execute"), ft, pl_execute_))) { diff --git a/src/pl/ob_pl_package_guard.h b/src/pl/ob_pl_package_guard.h index df20a257e..2d938a0e6 100644 --- a/src/pl/ob_pl_package_guard.h +++ b/src/pl/ob_pl_package_guard.h @@ -14,6 +14,7 @@ #define SRC_PL_OB_PL_PACKAGE_GUARD_H_ #include "sql/plan_cache/ob_cache_object_factory.h" +#include "pl/dblink/ob_pl_dblink_guard.h" namespace oceanbase { @@ -23,7 +24,7 @@ namespace pl class ObPLPackageGuard { public: - ObPLPackageGuard(uint64_t tenant_id) : alloc_() + ObPLPackageGuard(uint64_t tenant_id) : alloc_(), dblink_guard_(alloc_) { lib::ObMemAttr attr; attr.label_ = "PLPKGGuard"; @@ -44,6 +45,7 @@ public: return map_.get_refactored(package_id, package); } common::ObArenaAllocator alloc_; + ObPLDbLinkGuard dblink_guard_; private: common::hash::ObHashMap map_; }; diff --git a/src/pl/ob_pl_resolver.cpp b/src/pl/ob_pl_resolver.cpp index 6dc877d26..8d46eea11 100644 --- a/src/pl/ob_pl_resolver.cpp +++ b/src/pl/ob_pl_resolver.cpp @@ -37,6 +37,7 @@ #include "pl/ob_pl_warning.h" #include "pl/ob_pl_udt_object_manager.h" #include "pl/sys_package/ob_json_pl_utils.h" +#include "pl/dblink/ob_pl_dblink_util.h" #endif namespace oceanbase { @@ -3211,6 +3212,44 @@ int ObPLResolver::adjust_routine_param_type(ObPLDataType &type) return ret; } +int ObPLResolver::resolve_dblink_type(const ParseNode *node, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type) +{ + int ret = OB_SUCCESS; + ParseNode *access_node = NULL; + ObString db_name; + ObString pkg_name; + ObString udt_name; + ObString dblink_name; + const ObUserDefinedType *udt = NULL; + CK (OB_LIKELY(2 == node->num_child_)); + CK (OB_LIKELY(OB_NOT_NULL(node->children_[0])) && OB_LIKELY(OB_NOT_NULL(node->children_[1]))); + CK (OB_LIKELY(T_SP_OBJ_ACCESS_REF == node->children_[0]->type_)); + CK (OB_LIKELY(T_USER_VARIABLE_IDENTIFIER == node->children_[1]->type_)); + CK (2 == node->children_[0]->num_child_); + CK (OB_NOT_NULL(access_node = node->children_[0]->children_[0])); + CK (T_SP_ACCESS_NAME == access_node->type_); + // access_node must be a package type. + CK (3 == access_node->num_child_); + CK (OB_NOT_NULL(access_node->children_[1]) && OB_NOT_NULL(access_node->children_[2])) + if (OB_SUCC(ret)) { + dblink_name.assign_ptr(node->children_[1]->str_value_, + static_cast(node->children_[1]->str_len_)); + pkg_name.assign_ptr(access_node->children_[1]->str_value_, + static_cast(access_node->children_[1]->str_len_)); + udt_name.assign_ptr(access_node->children_[2]->str_value_, + static_cast(access_node->children_[2]->str_len_)); + if (OB_NOT_NULL(access_node->children_[0])) { + db_name.assign_ptr(access_node->children_[0]->str_value_, + static_cast(access_node->children_[0]->str_len_)); + } + } + + OZ (resolve_dblink_type(dblink_name, db_name, pkg_name, udt_name, func, pl_type)); + return ret; +} + // for example : 'insert into tbl values (:NEW.rowid);' // this stmt may inside a trigger mock function body, :NEW is a type like tbl%ROWTYPE // in this case, we have to including the rowid psedocolumn in the result, regardless of @@ -3236,6 +3275,8 @@ int ObPLResolver::resolve_sp_data_type(const ParseNode *sp_data_type_node, } else if (T_SP_TYPE == sp_data_type_node->type_ || T_SP_ROWTYPE == sp_data_type_node->type_) { OZ (resolve_sp_row_type(sp_data_type_node, func, data_type, extern_type_info, with_rowid)); + } else if (T_SP_DBLINK_TYPE == sp_data_type_node->type_) { + OZ (resolve_dblink_type(sp_data_type_node, func, data_type)); } else { OZ (resolve_sp_scalar_type(resolve_ctx_.allocator_, sp_data_type_node, @@ -6579,13 +6620,14 @@ int ObPLResolver::resolve_call(const ObStmtNodeTree *parse_tree, ObPLCallStmt *s ObString package_name; ObString sp_name; ObArray expr_params; + ObString dblink_name; if (T_SP_ACCESS_NAME != name_node->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid procedure name node", K(name_node->type_), K(ret)); } else if (OB_FAIL(ObResolverUtils::resolve_sp_access_name(schema_checker, resolve_ctx_.session_info_.get_effective_tenant_id(), resolve_ctx_.session_info_.get_database_name(), - *name_node, db_name, package_name, sp_name))) { + *name_node, db_name, package_name, sp_name, dblink_name))) { LOG_WARN("resolve sp name failed", K(ret)); } if (OB_SUCC(ret) && OB_NOT_NULL(params_node)) { @@ -6818,12 +6860,24 @@ int ObPLResolver::check_in_param_type_legal(const ObIRoutineParam *param_info, if (OB_SUCC(ret)) { if (param_info->is_schema_routine_param()) { const ObRoutineParam* iparam = static_cast(param_info); - OZ (pl::ObPLDataType::transform_from_iparam(iparam, - resolve_ctx_.schema_guard_, - resolve_ctx_.session_info_, - resolve_ctx_.allocator_, - resolve_ctx_.sql_proxy_, - expected_type)); + if (ObParamExternType::SP_EXTERN_DBLINK == iparam->get_extern_type_flag()) { + const ObUserDefinedType *udt = NULL; + CK (iparam->get_extended_type_info().count() > 0); + OZ (resolve_ctx_.package_guard_.dblink_guard_.get_dblink_type_by_name( + iparam->get_type_owner(), iparam->get_extended_type_info().at(0), + iparam->get_type_subname(), iparam->get_type_name(), udt)); + CK (OB_NOT_NULL(udt)); + OX (expected_type.set_user_type_id(udt->get_type(), udt->get_user_type_id())); + OX (expected_type.set_type_from(ObPLTypeFrom::PL_TYPE_DBLINK)); + OZ (expected_type.set_type_info(iparam->get_extended_type_info())); + } else { + OZ (pl::ObPLDataType::transform_from_iparam(iparam, + resolve_ctx_.schema_guard_, + resolve_ctx_.session_info_, + resolve_ctx_.allocator_, + resolve_ctx_.sql_proxy_, + expected_type)); + } } else { const ObPLRoutineParam* iparam = static_cast(param_info); OX (expected_type = iparam->get_type()); @@ -10176,59 +10230,66 @@ int ObPLResolver::resolve_inner_call( int ret = OB_SUCCESS; CK (OB_NOT_NULL(parse_tree)); CK (OB_LIKELY(T_SP_INNER_CALL_STMT == parse_tree->type_)); - CK (OB_LIKELY(1 == parse_tree->num_child_)); + CK (OB_LIKELY(1 == parse_tree->num_child_) || (3 == parse_tree->num_child_)); if (OB_SUCC(ret)) { ObArray obj_access_idents; ObArray access_idxs; ObArray self_access_idxs; ObArray expr_params; - OZ (resolve_obj_access_idents(*parse_tree->children_[0], obj_access_idents, func)); - OZ (init_udf_info_of_accessidents(obj_access_idents)); - for (int64_t i = 0; OB_SUCC(ret) && i < obj_access_idents.count(); ++i) { - // TODO: distinguish coll(idx).proc() and func(arg1).proc() - bool is_routine = obj_access_idents.at(i).is_pl_udf() - || (obj_access_idents.at(i).params_.count() != 1 && obj_access_idents.at(i).has_brackets_); - if (i == obj_access_idents.count() - 1) { - if (access_idxs.count() > 0) { - if (access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_DB_NS - || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_PKG_NS - || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_LABEL_NS - || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_UDT_NS) { + if (1 == parse_tree->num_child_) { + OZ (resolve_obj_access_idents(*parse_tree->children_[0], obj_access_idents, func)); + OZ (init_udf_info_of_accessidents(obj_access_idents)); + for (int64_t i = 0; OB_SUCC(ret) && i < obj_access_idents.count(); ++i) { + // TODO: distinguish coll(idx).proc() and func(arg1).proc() + bool is_routine = obj_access_idents.at(i).is_pl_udf() + || (obj_access_idents.at(i).params_.count() != 1 && obj_access_idents.at(i).has_brackets_); + if (i == obj_access_idents.count() - 1) { + if (access_idxs.count() > 0) { + if (access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_DB_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_PKG_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_LABEL_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_UDT_NS + || access_idxs.at(access_idxs.count() - 1).access_type_ == ObObjAccessIdx::IS_DBLINK_PKG_NS) { + is_routine = true; + } + } else { is_routine = true; } } else { - is_routine = true; + obj_access_idents.at(i).set_pl_udf(); + } + int64_t idx_cnt = access_idxs.count(); + OZ (resolve_access_ident(obj_access_idents.at(i), + current_block_->get_namespace(), + expr_factory_, + &resolve_ctx_.session_info_, + access_idxs, + func, + is_routine), + K(access_idxs), K(i)); + OZ (obj_access_idents.at(i).extract_params(0, expr_params)); + OX (idx_cnt = (idx_cnt >= access_idxs.count()) ? 0 : idx_cnt); + if (OB_SUCC(ret) + && (expr_params.count() > 0 || obj_access_idents.at(i).has_brackets_) + && !access_idxs.at(idx_cnt).is_procedure() + && !access_idxs.at(idx_cnt).is_udf_type() + && !access_idxs.at(idx_cnt).is_system_procedure() + && !access_idxs.at(idx_cnt).is_type_method() + && (!access_idxs.at(idx_cnt).var_type_.is_composite_type() || 0 == expr_params.count())) { + ret = OB_ERR_OUT_OF_SCOPE; + LOG_WARN("PLS-00225: subprogram or cursor reference is out of scope", K(ret), K(access_idxs.at(access_idxs.count()-1))); + LOG_USER_ERROR(OB_ERR_OUT_OF_SCOPE, obj_access_idents.at(i).access_name_.length(), obj_access_idents.at(i).access_name_.ptr()); + } + if (OB_SUCC(ret) + && obj_access_idents.count() >= 2 + && i == (obj_access_idents.count() - 2)) { + OZ (self_access_idxs.assign(access_idxs)); } - } else { - obj_access_idents.at(i).set_pl_udf(); - } - int64_t idx_cnt = access_idxs.count(); - OZ (resolve_access_ident(obj_access_idents.at(i), - current_block_->get_namespace(), - expr_factory_, - &resolve_ctx_.session_info_, - access_idxs, - func, - is_routine), - K(obj_access_idents), K(access_idxs), K(i)); - OZ (obj_access_idents.at(i).extract_params(0, expr_params)); - OX (idx_cnt = (idx_cnt >= access_idxs.count()) ? 0 : idx_cnt); - if (OB_SUCC(ret) - && (expr_params.count() > 0 || obj_access_idents.at(i).has_brackets_) - && !access_idxs.at(idx_cnt).is_procedure() - && !access_idxs.at(idx_cnt).is_udf_type() - && !access_idxs.at(idx_cnt).is_system_procedure() - && !access_idxs.at(idx_cnt).is_type_method() - && (!access_idxs.at(idx_cnt).var_type_.is_composite_type() || 0 == expr_params.count())) { - ret = OB_ERR_OUT_OF_SCOPE; - LOG_WARN("PLS-00225: subprogram or cursor reference is out of scope", K(ret), K(access_idxs.at(access_idxs.count()-1))); - LOG_USER_ERROR(OB_ERR_OUT_OF_SCOPE, obj_access_idents.at(i).access_name_.length(), obj_access_idents.at(i).access_name_.ptr()); - } - if (OB_SUCC(ret) - && obj_access_idents.count() >= 2 - && i == (obj_access_idents.count() - 2)) { - OZ (self_access_idxs.assign(access_idxs)); } + } else { + OZ (resolve_dblink_idents(*parse_tree, obj_access_idents, func, access_idxs)); + // PLFunction with dblink call statement cannot be added to plan cache + OX (func.set_can_cached(false)); } if (OB_SUCC(ret)) { @@ -10369,6 +10430,7 @@ int ObPLResolver::resolve_inner_call( = static_cast(access_idxs.at(idx_cnt - 1).routine_info_); CK (OB_NOT_NULL(schema_routine_info)); OX (call_stmt->set_package_id(schema_routine_info->get_package_id())); + OX (call_stmt->set_dblink_id(schema_routine_info->get_dblink_id())); if (OB_FAIL(ret)) { } else if (OB_INVALID_ID == schema_routine_info->get_package_id()) { call_stmt->set_proc_id(schema_routine_info->get_routine_id()); @@ -10765,6 +10827,192 @@ int ObPLResolver::resolve_obj_access_idents(const ParseNode &node, return ret; } +int ObPLResolver::resolve_dblink_idents(const ParseNode &node, + common::ObIArray &obj_access_idents, + ObPLCompileUnitAST &func, + common::ObIArray &access_idexs) +{ + int ret = OB_SUCCESS; + UNUSED(func); + ObString dblink_name; + CK (OB_LIKELY(3 == node.num_child_)); + CK (OB_LIKELY(OB_NOT_NULL(node.children_[0])) && OB_LIKELY(OB_NOT_NULL(node.children_[1]))); + CK (OB_LIKELY(T_SP_ACCESS_NAME == node.children_[0]->type_)); + CK (OB_LIKELY(T_DBLINK_NAME == node.children_[1]->type_)); + for (int64_t i = 0; OB_SUCC(ret) && i < node.children_[0]->num_child_; i++) { + if (OB_NOT_NULL(node.children_[0]->children_[i])) { + ObString ident_name(static_cast(node.children_[0]->children_[i]->str_len_), + node.children_[0]->children_[i]->str_value_); + ObObjAccessIdent access_ident(ident_name); + if (OB_FAIL(obj_access_idents.push_back(access_ident))) { + LOG_WARN("push back access ident failed", K(ret)); + } + } + } + CK (obj_access_idents.count() >= 1 && obj_access_idents.count() <= 3); + CK (1 == node.children_[1]->num_child_ && OB_NOT_NULL(node.children_[1]->children_[0])); + OX (dblink_name.assign_ptr(node.children_[1]->children_[0]->str_value_, + static_cast(node.children_[1]->children_[0]->str_len_))); + if (OB_SUCC(ret) && OB_NOT_NULL(node.children_[2])) { + ParseNode *params_node = node.children_[2]; + ObObjAccessIdent param_access; + for (int64_t param_idx = 0; OB_SUCC(ret) && param_idx < params_node->num_child_; ++param_idx) { + ObRawExpr *expr = NULL; + if (OB_FAIL(resolve_expr(params_node->children_[param_idx], func, expr, + combine_line_and_col(params_node->children_[param_idx]->stmt_loc_)))) { + LOG_WARN("failed to resolve expr", K(ret)); + } else { + std::pair param(expr, 0); + if (T_IDENT == node.children_[0]->type_ + || T_SP_ACCESS_NAME == node.children_[0]->type_) { + if (OB_FAIL(obj_access_idents.at(obj_access_idents.count()-1).params_.push_back(param))) { + LOG_WARN("push back access ident failed", K(ret)); + } + } else { + if (OB_FAIL(param_access.params_.push_back(param))) { + LOG_WARN("push back access ident failed", K(ret)); + } + } + } + } + if (OB_SUCC(ret) && !param_access.params_.empty()) { + if (OB_FAIL(obj_access_idents.push_back(param_access))) { + LOG_WARN("push back access ident failed", K(ret)); + } + } + } + + if (OB_SUCC(ret)) { + uint64_t dblink_id; + uint64_t cnt = obj_access_idents.count(); + uint64_t tenant_id = resolve_ctx_.session_info_.get_effective_tenant_id(); + common::ObArray expr_params; + const ObIRoutineInfo *routine_info = NULL; + ObString empty_str(""); + ObString &routine_name = obj_access_idents.at(cnt - 1).access_name_; + ObString &pkg_name = (cnt >= 2 ? obj_access_idents.at(cnt - 2).access_name_ : empty_str); + ObString &db_name = (cnt == 3 ? obj_access_idents.at(0).access_name_ : empty_str); + OZ (obj_access_idents.at(cnt - 1).extract_params(0, expr_params)); + // OZ (resolve_ctx_.schema_guard_.get_dblink_id(tenant_id, dblink_name, dblink_id)); + // OV (OB_INVALID_ID != dblink_id, OB_DBLINK_NOT_EXIST_TO_ACCESS, dblink_id); + // OZ (resolve_ctx_.schema_guard_.get_dblink_user(tenant_id, dblink_name, db_name, resolve_ctx_.allocator_)); + OZ (resolve_dblink_routine(resolve_ctx_, dblink_name, db_name, pkg_name, + routine_name, expr_params, routine_info)); + if (OB_SUCC(ret) && OB_NOT_NULL(routine_info)) { + ObPLDataType proc_pl_data_type; + ObObjAccessIdx::AccessType proc_type = ObObjAccessIdx::AccessType::IS_EXTERNAL_PROC; + int64_t access_value = reinterpret_cast(routine_info); + ObObjAccessIdx access_idx; + new (&access_idx)ObObjAccessIdx(proc_pl_data_type, proc_type, routine_name, proc_pl_data_type, access_value); + OZ (access_idexs.push_back(access_idx)); + } + } + + return ret; +} + +int ObPLResolver::resolve_dblink_routine(ObPLResolveCtx &resolve_ctx, + const ObString &dblink_name, + const ObString &db_name, + const ObString &pkg_name, + const ObString &routine_name, + const common::ObIArray &expr_params, + const ObIRoutineInfo *&routine_info) +{ + int ret = OB_SUCCESS; + ObSEArray routine_infos; + const share::schema::ObIRoutineInfo *i_routine_info = NULL; + OZ (resolve_ctx.package_guard_.dblink_guard_.get_routine_infos_with_synonym(resolve_ctx.session_info_, + resolve_ctx.schema_guard_, dblink_name, db_name, pkg_name, routine_name, routine_infos)); + + if (OB_SUCC(ret) && routine_infos.count() > 0) { + OZ (ObResolverUtils::pick_routine(resolve_ctx, expr_params, routine_infos, i_routine_info)); + // OX (routine_info = static_cast(i_routine_info)); + LOG_DEBUG("debug for pick routine info", K(ret), K(db_name), K(pkg_name), + K(routine_name), K(expr_params), KPC(routine_info)); + if (OB_SUCC(ret)) { + routine_info = i_routine_info; + } + } + if (OB_SUCC(ret) && OB_ISNULL(routine_info)) { + ret = OB_ERR_NOT_VALID_ROUTINE_NAME; + LOG_WARN("not a valid function or procedure name", K(ret), K(dblink_name), + K(db_name), K(pkg_name), K(routine_name)); + } + return ret; +} + +int ObPLResolver::resolve_dblink_routine_with_synonym(ObPLResolveCtx &resolve_ctx, + const uint64_t pkg_syn_id, + const ObString &routine_name, + const common::ObIArray &expr_params, + const ObIRoutineInfo *&routine_info) +{ + int ret = OB_SUCCESS; +#ifdef OB_BUILD_ORACLE_PL + ObString dblink_name; + ObString db_name; + ObString pkg_name; + OZ (ObPLDblinkUtil::separate_name_from_synonym(resolve_ctx.schema_guard_, resolve_ctx.allocator_, + resolve_ctx.session_info_.get_effective_tenant_id(), + pkg_syn_id, dblink_name, db_name, pkg_name)); + OZ (ObPLResolver::resolve_dblink_routine(resolve_ctx, dblink_name, db_name, pkg_name, + routine_name, expr_params, routine_info), + dblink_name, db_name, pkg_name); +#endif + return ret; +} + +int ObPLResolver::resolve_dblink_type_with_synonym(const uint64_t pkg_syn_id, + const ObString &type_name, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type) +{ + int ret = OB_SUCCESS; +#ifdef OB_BUILD_ORACLE_PL + ObString dblink_name; + ObString db_name; + ObString pkg_name; + OZ (ObPLDblinkUtil::separate_name_from_synonym(resolve_ctx_.schema_guard_, resolve_ctx_.allocator_, + resolve_ctx_.session_info_.get_effective_tenant_id(), + pkg_syn_id, dblink_name, db_name, pkg_name)); + OZ (resolve_dblink_type(dblink_name, db_name, pkg_name, type_name, func, pl_type)); +#endif + return ret; +} + +int ObPLResolver::resolve_dblink_type(const ObString &dblink_name, + const ObString &db_name, + const ObString &pkg_name, + const ObString &udt_name, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type) +{ + int ret = OB_SUCCESS; + const ObUserDefinedType *udt = NULL; + OZ (resolve_ctx_.package_guard_.dblink_guard_.get_dblink_type_with_synonym(resolve_ctx_.session_info_, + resolve_ctx_.schema_guard_, dblink_name, db_name, pkg_name, udt_name, udt)); + OZ (current_block_->get_namespace().get_type_table()->add_external_type(udt)); + OX (func.set_can_cached(false)); + if (OB_SUCC(ret) && udt->is_collection_type()) { + const ObCollectionType *coll_type = static_cast(udt); + if (OB_NOT_NULL(coll_type) && coll_type->get_element_type().is_record_type()) { + const ObUserDefinedType *udt2 = NULL; + uint64_t user_type_id = coll_type->get_element_type().get_user_type_id(); + OZ (resolve_ctx_.package_guard_.dblink_guard_.get_dblink_type_by_id( + extract_package_id(user_type_id), user_type_id, udt2)); + OZ (current_block_->get_namespace().get_type_table()->add_external_type(udt2)); + } + } + if (OB_SUCC(ret) && OB_NOT_NULL(udt)) { + pl_type.set_user_type_id(udt->get_type(), udt->get_user_type_id()); + pl_type.set_type_from(PL_TYPE_PACKAGE); + pl_type.set_type_from_orgin(PL_TYPE_PACKAGE); + } + return ret; +} + + int ObPLResolver::resolve_qualified_identifier(ObQualifiedName &q_name, ObIArray &columns, ObIArray &real_exprs, @@ -13016,7 +13264,8 @@ int ObPLResolver::get_names_by_access_ident(ObObjAccessIdent &access_ident, // do nothing ... } else if (ObObjAccessIdx::IS_PKG_NS == access_idxs.at(cnt - 1).access_type_ || ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt - 1).access_type_ - || ObObjAccessIdx::IS_LABEL_NS == access_idxs.at(cnt - 1).access_type_) { + || ObObjAccessIdx::IS_LABEL_NS == access_idxs.at(cnt - 1).access_type_ + || ObObjAccessIdx::IS_DBLINK_PKG_NS == access_idxs.at(cnt-1).access_type_) { package_name = access_idxs.at(cnt - 1).var_name_; if (cnt >= 2) { OV (2 == cnt, OB_ERR_UNEXPECTED, K(cnt)); @@ -13111,7 +13360,10 @@ int ObPLResolver::resolve_routine(ObObjAccessIdent &access_ident, const ObIRoutineInfo *routine_info = NULL; ObSEArray expr_params; ObProcType routine_type = access_ident.is_pl_udf() ? STANDALONE_FUNCTION : STANDALONE_PROCEDURE; - + bool is_dblink_pkg_ns = false; + if (access_idxs.count() > 0) { + is_dblink_pkg_ns = (ObObjAccessIdx::IS_DBLINK_PKG_NS == access_idxs.at(access_idxs.count()-1).access_type_); + } OZ (get_names_by_access_ident( access_ident, access_idxs, database_name, package_name, routine_name)); @@ -13141,13 +13393,23 @@ int ObPLResolver::resolve_routine(ObObjAccessIdent &access_ident, { ObPLMockSelfArg self(access_idxs, expr_params, expr_factory_, resolve_ctx_.session_info_); OZ (self.mock()); - OZ (ns.resolve_routine(resolve_ctx_, - database_name, - package_name, - routine_name, - expr_params, - routine_type, - routine_info)); + if (!is_dblink_pkg_ns) { + OZ (ns.resolve_routine(resolve_ctx_, + database_name, + package_name, + routine_name, + expr_params, + routine_type, + routine_info)); + if (OB_SUCC(ret) && OB_INVALID_ID != routine_info->get_dblink_id()) { + func.set_can_cached(false); + } + } else { + OZ (ObPLResolver::resolve_dblink_routine_with_synonym(resolve_ctx_, + static_cast(access_idxs.at(access_idxs.count()-1).var_index_), + routine_name, expr_params, routine_info)); + OX (func.set_can_cached(false)); + } } if (OB_FAIL(ret) @@ -13686,6 +13948,7 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 || ObObjAccessIdx::IS_TABLE_NS == access_idxs.at(cnt - 1).access_type_ || ObObjAccessIdx::IS_LABEL_NS == access_idxs.at(cnt - 1).access_type_ || ObObjAccessIdx::IS_UDT_NS == access_idxs.at(cnt - 1).access_type_ + || ObObjAccessIdx::IS_DBLINK_PKG_NS == access_idxs.at(cnt-1).access_type_ || is_routine) { bool label_symbol = false; if (cnt != 0) { @@ -13712,6 +13975,11 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 ObPLExternalNS::ExternalType::SUBPROGRAM_VAR == type ? reinterpret_cast(access_idxs.at(cnt - 1).label_ns_) : access_idxs.at(cnt - 1).label_ns_->get_package_id()); + } else if (0 != cnt + && ObObjAccessIdx::IS_DBLINK_PKG_NS == access_idxs.at(cnt-1).access_type_ && !is_routine) { + OZ (resolve_dblink_type_with_synonym(parent_id, access_ident.access_name_, func, pl_data_type)); + OX (type = ObPLExternalNS::PKG_TYPE); + OX (var_index = pl_data_type.get_user_type_id()); } else { if (access_ident.is_pl_var() && access_ident.access_name_.empty()) { // questionmark variable const ObPLSymbolTable *sym_tbl = ns.get_symbol_table(); @@ -13752,7 +14020,8 @@ int ObPLResolver::resolve_access_ident(ObObjAccessIdent &access_ident, // 当前 || (ObPLExternalNS::LOCAL_VAR == type && is_routine) || (ObPLExternalNS::TABLE_NS == type && is_routine) || (ObPLExternalNS::LABEL_NS == type && is_routine) - || (ObPLExternalNS::DB_NS == type && is_routine)) { + || (ObPLExternalNS::DB_NS == type && is_routine) + || (ObPLExternalNS::DBLINK_PKG_NS == type && is_routine)) { if (is_routine) { OZ (resolve_routine(access_ident, ns, access_idxs, func), K(access_ident), K(access_idxs)); @@ -14207,6 +14476,7 @@ int ObPLResolver::resolve_condition(const ObStmtNodeTree *parse_tree, ObString db_name; ObString package_name; ObString condition_name; + ObString dblink_name; OZ (schema_checker.init(resolve_ctx_.schema_guard_, resolve_ctx_.session_info_.get_sessid())); OZ (ObResolverUtils::resolve_sp_access_name(schema_checker, resolve_ctx_.session_info_.get_effective_tenant_id(), @@ -14214,7 +14484,8 @@ int ObPLResolver::resolve_condition(const ObStmtNodeTree *parse_tree, *parse_tree, db_name, package_name, - condition_name)); + condition_name, + dblink_name)); if (OB_FAIL(ret)) { } else if (package_name.empty()) { if (!db_name.empty() @@ -14906,11 +15177,12 @@ int ObPLResolver::resolve_cursor( ObString db_name; ObString package_name; ObString cursor_name; + ObString dblink_name; OZ (schema_checker.init(resolve_ctx_.schema_guard_, resolve_ctx_.session_info_.get_sessid())); OZ (ObResolverUtils::resolve_sp_access_name( schema_checker, resolve_ctx_.session_info_.get_effective_tenant_id(), resolve_ctx_.session_info_.get_database_name(), - *parse_tree, db_name, package_name, cursor_name)); + *parse_tree, db_name, package_name, cursor_name, dblink_name)); if (OB_FAIL(ret)) { } else if (package_name.empty()) { if (!db_name.empty() @@ -16108,7 +16380,9 @@ int ObPLResolver::resolve_routine_def(const ObStmtNodeTree *parse_tree, OX (routine_info->set_routine_body(routine_body)); OZ (routine_table.set_routine_ast(idx, routine_ast)); OX (unit_ast.add_dependency_objects(routine_ast->get_dependency_table())); - OX (unit_ast.set_can_cached(routine_ast->get_can_cached())); + if (OB_SUCC(ret) && unit_ast.get_can_cached()) { + OX (unit_ast.set_can_cached(routine_ast->get_can_cached())); + } if (OB_SUCC(ret)) { if (unit_ast.is_modifies_sql_data()) { // do nothing @@ -16689,10 +16963,16 @@ int ObPLResolveCtx::get_user_type(uint64_t type_id, const ObUserDefinedType *&us && extract_package_id(type_id) != OB_INVALID_ID) { // 最后尝试下是不是PackageType ret = OB_SUCCESS; const ObUserDefinedType *package_user_type = NULL; - ObPLPackageManager &package_manager = session_info_.get_pl_engine()->get_package_manager(); - ObPLDataType *copy_pl_type = NULL; - OZ (package_manager.get_package_type(*this, extract_package_id(type_id), type_id, package_user_type), K(type_id)); - CK (OB_NOT_NULL(user_type = static_cast(package_user_type))); + if (!common::is_dblink_type_id(type_id)) { + ObPLPackageManager &package_manager = session_info_.get_pl_engine()->get_package_manager(); + ObPLDataType *copy_pl_type = NULL; + OZ (package_manager.get_package_type(*this, extract_package_id(type_id), type_id, package_user_type), K(type_id)); + CK (OB_NOT_NULL(user_type = static_cast(package_user_type))); + } else { + OZ (package_guard_.dblink_guard_.get_dblink_type_by_id(extract_package_id(type_id), type_id, + package_user_type), type_id); + CK (OB_NOT_NULL(user_type = static_cast(package_user_type))); + } } } diff --git a/src/pl/ob_pl_resolver.h b/src/pl/ob_pl_resolver.h index 74aa559b2..a3df553f9 100644 --- a/src/pl/ob_pl_resolver.h +++ b/src/pl/ob_pl_resolver.h @@ -442,7 +442,7 @@ public: share::schema::ObIRoutineInfo *routine_info, ObProcType &routine_type, const ObPLDataType &ret_type); - + static int build_pl_integer_type(ObPLIntegerType type, ObPLDataType &data_type); int get_caller_accessor_item( const ObPLStmtBlock *caller, AccessorItem &caller_item); @@ -556,6 +556,28 @@ public: sql::ObUDFInfo &udf_info, ObIArray &access_idxs, ObPLCompileUnitAST &func); int construct_name(ObString &database_name, ObString &package_name, ObString &routine_name, ObSqlString &object_name); + static int resolve_dblink_routine(ObPLResolveCtx &resolve_ctx, + const ObString &dblink_name, + const ObString &db_name, + const ObString &pkg_name, + const ObString &routine_name, + const common::ObIArray &expr_params, + const ObIRoutineInfo *&routine_info); + static int resolve_dblink_routine_with_synonym(ObPLResolveCtx &resolve_ctx, + const uint64_t pkg_syn_id, + const ObString &routine_name, + const common::ObIArray &expr_params, + const ObIRoutineInfo *&routine_info); + int resolve_dblink_type_with_synonym(const uint64_t pkg_syn_id, + const ObString &type_name, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type); + int resolve_dblink_type(const ObString &dblink_name, + const ObString &db_name, + const ObString &pkg_name, + const ObString &udt_name, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type); private: int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLDeclareVarStmt *stmt, ObPLFunctionAST &func_ast); int resolve_declare_var(const ObStmtNodeTree *parse_tree, ObPLPackageAST &package_ast); @@ -587,6 +609,9 @@ private: ObPLDataType &pl_type, ObPLExternTypeInfo *extern_type_info = NULL, bool with_rowid = false); + int resolve_dblink_type(const ParseNode *node, + ObPLCompileUnitAST &func, + ObPLDataType &pl_type); int resolve_sp_composite_type(const ParseNode *sp_data_type_node, ObPLCompileUnitAST &func, ObPLDataType &data_type, @@ -917,6 +942,10 @@ private: int resolve_obj_access_idents(const ParseNode &node, common::ObIArray &obj_access_idents, ObPLCompileUnitAST &func); + int resolve_dblink_idents(const ParseNode &node, + common::ObIArray &obj_access_idents, + ObPLCompileUnitAST &func, + common::ObIArray &access_idexs); int build_collection_attribute_access(ObRawExprFactory &expr_factory, const ObSQLSessionInfo *session_info, const ObPLBlockNS &ns, @@ -951,7 +980,6 @@ private: int32_t upper, ObRawExpr *&expr); int add_pl_integer_checker_expr(ObRawExprFactory &expr_factory, ObRawExpr *&expr, bool &need_replace); - static int build_pl_integer_type(ObPLIntegerType type, ObPLDataType &data_type); int check_use_idx_illegal(ObRawExpr* expr, int64_t idx); diff --git a/src/pl/ob_pl_stmt.cpp b/src/pl/ob_pl_stmt.cpp index e6fcd53c2..75ffb3c90 100644 --- a/src/pl/ob_pl_stmt.cpp +++ b/src/pl/ob_pl_stmt.cpp @@ -1439,7 +1439,8 @@ int ObPLExternalNS::resolve_synonym(uint64_t object_db_id, const ObString &object_name, ExternalType &type, uint64_t &parent_id, - int64_t &var_idx) const + int64_t &var_idx, + const ObString &synonym_name) const { int ret = OB_SUCCESS; uint64_t object_id = OB_INVALID_ID; @@ -1459,8 +1460,32 @@ int ObPLExternalNS::resolve_synonym(uint64_t object_db_id, if (OB_FAIL(schema_guard.get_udt_id( tenant_id, object_db_id, OB_INVALID_ID/*package_id*/, object_name, object_id)) || OB_INVALID_ID == object_id) { - LOG_WARN("resolve synonym failed!", - K(ret), K(object_db_id), K(object_name)); + // try dblink synonym + ObString tmp_name; + uint64_t dblink_id = OB_INVALID_ID; + if (OB_FAIL(ob_write_string(resolve_ctx_.allocator_, object_name, tmp_name))) { + LOG_WARN("write string failed", K(ret)); + } else { + ObString full_object_name = tmp_name.split_on('@'); + bool exist = false; + if (!full_object_name.empty()) { + if (OB_FAIL(schema_guard.get_dblink_id(tenant_id, tmp_name, dblink_id)) + || OB_INVALID_ID == dblink_id) { + LOG_WARN("resolve synonym failed!", K(ret), K(object_db_id), K(tmp_name)); + } else if (OB_FAIL(schema_guard.check_synonym_exist_with_name(tenant_id, object_db_id, synonym_name, + exist, object_id))) { + LOG_WARN("check_synonym_exist_with_name failed", K(ret), + K(object_db_id), K(synonym_name), K(object_name)); + } else if (!exist || OB_INVALID_ID == object_id) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("synonym not exist", K(ret), K(tenant_id), K(object_db_id), K(object_name), K(synonym_name)); + } else { + type = DBLINK_PKG_NS; + } + } else { + LOG_WARN("resolve synonym failed!", K(ret), K(object_db_id), K(object_name)); + } + } } else { type = UDT_NS; } @@ -1659,7 +1684,7 @@ int ObPLExternalNS::resolve_external_symbol(const common::ObString &name, schema_checker, synonym_checker, tenant_id, db_id, name, object_db_id, object_name, exist)); if (exist) { - OZ (resolve_synonym(object_db_id, object_name, type, parent_id, var_idx)); + OZ (resolve_synonym(object_db_id, object_name, type, parent_id, var_idx, name)); } } // 尝试看是不是系统变量的特殊写法,如 set SQL_MODE='ONLY_FULL_GROUP_BY'; diff --git a/src/pl/ob_pl_stmt.h b/src/pl/ob_pl_stmt.h index 381e19303..5731fff60 100644 --- a/src/pl/ob_pl_stmt.h +++ b/src/pl/ob_pl_stmt.h @@ -40,6 +40,8 @@ OB_INLINE uint64_t get_tenant_id_by_object_id(uint64_t object_id) { object_id = object_id & ~(OB_MOCK_TRIGGER_PACKAGE_ID_MASK); object_id = object_id & ~(OB_MOCK_OBJECT_PACAKGE_ID_MASK); + object_id = object_id & ~(OB_MOCK_PACKAGE_BODY_ID_MASK); + object_id = object_id & ~(OB_MOCK_DBLINK_UDT_ID_MASK); return is_inner_pl_object_id(object_id) ? OB_SYS_TENANT_ID : MTL_ID(); } @@ -1151,6 +1153,7 @@ public: LOCAL_TYPE, // 本地的自定义类型 PKG_TYPE, // 包中的自定义类型 SELF_ATTRIBUTE, + DBLINK_PKG_NS, // dblink package }; ObPLExternalNS(const ObPLResolveCtx &resolve_ctx, const ObPLBlockNS *parent_ns) @@ -1162,7 +1165,8 @@ public: const ObString &object_name, ExternalType &type, uint64_t &parent_id, - int64_t &var_idx) const; + int64_t &var_idx, + const ObString &synonym_name) const; int resolve_external_symbol(const common::ObString &name, ExternalType &type, ObPLDataType &data_type, uint64_t &parent_id, int64_t &var_idx) const; int resolve_external_type_by_name(const ObString &db_name, @@ -2960,7 +2964,8 @@ public: subprogram_path_(allocator), params_(allocator), nocopy_params_(allocator), - route_sql_() {} + route_sql_(), + dblink_id_(common::OB_INVALID_ID) {} virtual ~ObPLCallStmt() {} int accept(ObPLStmtVisitor &visitor) const; @@ -2986,6 +2991,9 @@ public: inline uint64_t get_is_object_udf() const { return is_object_udf_; } inline const common::ObString &get_route_sql() const { return route_sql_; } inline void set_route_sql(const common::ObString &route_sql) { route_sql_ = route_sql; } + inline void set_dblink_id(uint64_t dblink_id) { dblink_id_ = dblink_id; } + inline uint64_t get_dblink_id() const { return dblink_id_; } + inline bool is_dblink_call() const { return common::OB_INVALID_ID == dblink_id_; } TO_STRING_KV(K_(type), K_(label), @@ -2994,7 +3002,8 @@ public: K_(is_object_udf), K_(params), K_(nocopy_params), - K_(route_sql)); + K_(route_sql), + K_(dblink_id)); private: uint64_t invoker_id_; @@ -3005,6 +3014,7 @@ private: ObPLSEArray params_; ObPLSEArray nocopy_params_; common::ObString route_sql_; + uint64_t dblink_id_; }; class ObPLInnerCallStmt : public ObPLStmt diff --git a/src/pl/ob_pl_type.cpp b/src/pl/ob_pl_type.cpp index 245411435..2ec36ecc1 100644 --- a/src/pl/ob_pl_type.cpp +++ b/src/pl/ob_pl_type.cpp @@ -25,6 +25,7 @@ #include "common/ob_smart_call.h" #include "sql/resolver/expr/ob_raw_expr_copier.h" #include "pl/ob_pl_user_type.h" +#include "dblink/ob_pl_dblink_guard.h" namespace oceanbase { using namespace common; @@ -255,7 +256,8 @@ int ObPLDataType::transform_from_iparam(const ObRoutineParam *iparam, ObIAllocator &allocator, common::ObMySQLProxy &sql_proxy, pl::ObPLDataType &pl_type, - ObSchemaObjVersion *obj_version) + ObSchemaObjVersion *obj_version, + ObPLDbLinkGuard *dblink_guard) { int ret = OB_SUCCESS; CK (OB_NOT_NULL(iparam)); @@ -395,6 +397,21 @@ int ObPLDataType::transform_from_iparam(const ObRoutineParam *iparam, } break; } +#ifdef OB_BUILD_ORACLE_PL + case SP_EXTERN_DBLINK :{ + const ObUserDefinedType *udt = NULL; + const ObRoutineParam *param = static_cast(iparam); + CK (OB_NOT_NULL(param)); + CK (OB_NOT_NULL(dblink_guard)); + CK (param->get_extended_type_info().count() > 0); + OZ (dblink_guard->get_dblink_type_by_name(param->get_type_owner(), param->get_extended_type_info().at(0), + param->get_type_subname(), param->get_type_name(), udt)); + CK (OB_NOT_NULL(udt)); + OX (pl_type.set_user_type_id(udt->get_type(), udt->get_user_type_id())); + OX (pl_type.set_type_from(ObPLTypeFrom::PL_TYPE_DBLINK)); + } + break; +#endif default: { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected extern type", K(ret), K(type)); @@ -1206,7 +1223,15 @@ int ObPLDataType::get_external_user_type(const ObPLResolveCtx &resolve_ctx, { int ret = OB_SUCCESS; uint64_t user_type_id = get_user_type_id(); - if (is_package_type()) { // other package type + if (common::is_dblink_type_id(user_type_id)) { + if (OB_FAIL(resolve_ctx.package_guard_.dblink_guard_.get_dblink_type_by_id( + extract_package_id(user_type_id), user_type_id, user_type))) { + LOG_WARN("failed to get dblink package id", K(ret), K(user_type_id)); + } else if (OB_ISNULL(user_type)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get dblink type is null", K(ret), K(user_type_id)); + } + } else if (is_package_type()) { // other package type ObPLPackageManager &pl_manager = resolve_ctx.session_info_.get_pl_engine()->get_package_manager(); uint64_t package_id = extract_package_id(user_type_id); uint64_t type_id = extract_type_id(user_type_id); diff --git a/src/pl/ob_pl_type.h b/src/pl/ob_pl_type.h index 38f7b2735..6920ad44a 100644 --- a/src/pl/ob_pl_type.h +++ b/src/pl/ob_pl_type.h @@ -77,6 +77,7 @@ class ObPLRoutineParam; class ObPLUserTypeTable; class ObUserDefinedType; class ObPLStmt; +class ObPLDbLinkGuard; enum ObProcType { @@ -196,6 +197,7 @@ enum ObPLTypeFrom PL_TYPE_ATTR_ROWTYPE, PL_TYPE_ATTR_TYPE, PL_TYPE_SYS_REFCURSOR, + PL_TYPE_DBLINK, }; enum ObPLTypeSize @@ -561,7 +563,8 @@ public: common::ObIAllocator &allocator, common::ObMySQLProxy &sql_proxy, pl::ObPLDataType &pl_type, - share::schema::ObSchemaObjVersion *obj_version = NULL); + share::schema::ObSchemaObjVersion *obj_version = NULL, + pl::ObPLDbLinkGuard *dblink_guard = NULL); static int transform_and_add_routine_param(const pl::ObPLRoutineParam *param, int64_t position, int64_t level, @@ -639,6 +642,8 @@ public: IS_UDF_NS = 20, IS_LOCAL_TYPE = 21, // 本地的自定义类型 IS_PKG_TYPE = 22, // 包中的自定义类型 + IS_SELF_ATTRIBUTE = 23, // self attribute for udt + IS_DBLINK_PKG_NS = 24, // dblink package }; ObObjAccessIdx() diff --git a/src/pl/ob_pl_user_type.cpp b/src/pl/ob_pl_user_type.cpp index 637f29050..8122995ac 100644 --- a/src/pl/ob_pl_user_type.cpp +++ b/src/pl/ob_pl_user_type.cpp @@ -3453,6 +3453,11 @@ int ObElemDesc::deserialize(const char* buf, const int64_t len, int64_t &pos) return ret; } +ObIAllocator* ObPLCollection::get_coll_allocator() +{ + return dynamic_cast(allocator_); +} + /* * 我们约定一个原则: * 1、所有Collection内部的data域的ObObj数组(包括sort域和key域的内存)的内存都必须由该Collection自己的allocator分配,而不允许是其他任何allocator; diff --git a/src/pl/ob_pl_user_type.h b/src/pl/ob_pl_user_type.h index b305b4ce9..3793da1f2 100644 --- a/src/pl/ob_pl_user_type.h +++ b/src/pl/ob_pl_user_type.h @@ -43,6 +43,7 @@ struct ObPLExecCtx; class ObPLResolveCtx; class ObPLResolver; class ObPLStmt; +class ObPLCollAllocator; class ObUserDefinedType : public ObPLDataType { @@ -968,6 +969,7 @@ public: first_(OB_INVALID_INDEX), last_(OB_INVALID_INDEX), data_(NULL) {} + common::ObIAllocator *get_coll_allocator(); inline common::ObIAllocator *get_allocator() { return allocator_; } inline void set_allocator(common::ObIAllocator *allocator) { allocator_ = allocator; } inline const ObElemDesc &get_element_desc() const { return element_; } diff --git a/src/share/schema/ob_routine_info.cpp b/src/share/schema/ob_routine_info.cpp index fe36167b4..b80074a34 100644 --- a/src/share/schema/ob_routine_info.cpp +++ b/src/share/schema/ob_routine_info.cpp @@ -297,6 +297,7 @@ ObRoutineInfo &ObRoutineInfo::operator =(const ObRoutineInfo &src_schema) comp_flag_ = src_schema.comp_flag_; type_id_ = src_schema.type_id_; tg_timing_event_ = src_schema.tg_timing_event_; + dblink_id_ = src_schema.dblink_id_; if (OB_FAIL(deep_copy_str(src_schema.routine_name_, routine_name_))) { LOG_WARN("deep copy name failed", K(ret), K_(src_schema.routine_name)); } else if (OB_FAIL(deep_copy_str(src_schema.priv_user_, priv_user_))) { @@ -308,9 +309,13 @@ ObRoutineInfo &ObRoutineInfo::operator =(const ObRoutineInfo &src_schema) } else if (OB_FAIL(deep_copy_str(src_schema.comment_, comment_))) { LOG_WARN("deep copy comment failed", K(ret), K_(src_schema.comment)); } else if (OB_FAIL(deep_copy_str(src_schema.route_sql_, route_sql_))) { - LOG_WARN("deep copy comment failed", K(ret), K_(src_schema.route_sql)); + LOG_WARN("deep copy route sql failed", K(ret), K_(src_schema.route_sql)); } else if (OB_FAIL(routine_params_.reserve(src_schema.routine_params_.count()))) { LOG_WARN("failed to reserve routine params size", K(ret), K(src_schema)); + } else if (OB_FAIL(deep_copy_str(src_schema.dblink_db_name_, dblink_db_name_))) { + LOG_WARN("deep copy dblink database name failed", K(ret), K(src_schema.dblink_db_name_)); + } else if (OB_FAIL(deep_copy_str(src_schema.dblink_pkg_name_, dblink_pkg_name_))) { + LOG_WARN("deep copy dblink pkg name failed", K(ret), K(src_schema.dblink_pkg_name_)); } for (int64_t i = 0; OB_SUCC(ret) && i < src_schema.routine_params_.count(); ++i) { if (OB_ISNULL(src_schema.routine_params_.at(i))) { @@ -382,6 +387,9 @@ void ObRoutineInfo::reset() routine_params_.reset(); ObSchema::reset(); tg_timing_event_ = TgTimingEvent::TG_TIMING_EVENT_INVALID; + dblink_id_ = OB_INVALID_ID; + reset_string(dblink_db_name_); + reset_string(dblink_pkg_name_); // routine_params_.set_allocator(get_allocator()); // routine_params_.set_capacity(OB_MAX_PROC_PARAM_COUNT+1); //one more ret type param for function } @@ -398,6 +406,8 @@ int64_t ObRoutineInfo::get_convert_size() const len += route_sql_.length() + 1; len += (routine_params_.count()+1) * sizeof(ObRoutineParam *); len += routine_params_.get_data_size(); + len += dblink_db_name_.length() + 1; + len += dblink_pkg_name_.length() + 1; ARRAY_FOREACH_NORET(routine_params_, i) { if (routine_params_.at(i) != NULL) { len += routine_params_.at(i)->get_convert_size(); @@ -523,6 +533,18 @@ int ObRoutineInfo::find_param_by_name(const ObString &name, int64_t &position) c return ret; } +int64_t ObRoutineInfo::get_out_param_count() const +{ + int64_t count = 0; + for (uint64_t i = 0; i < get_routine_params().count(); i++) { + if (get_routine_params().at(i)->is_out_sp_param() + || get_routine_params().at(i)->is_inout_sp_param()) { + count++; + } + } + return count; +} + OB_DEF_SERIALIZE(ObRoutineInfo) { int ret = OB_SUCCESS; @@ -546,7 +568,9 @@ OB_DEF_SERIALIZE(ObRoutineInfo) route_sql_, type_id_, param_cnt, - tg_timing_event_); + tg_timing_event_, + dblink_db_name_, + dblink_pkg_name_); for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) { if (OB_ISNULL(routine_params_.at(i))) { ret = OB_ERR_UNEXPECTED; @@ -583,7 +607,9 @@ OB_DEF_DESERIALIZE(ObRoutineInfo) route_sql_, type_id_, param_cnt, - tg_timing_event_); + tg_timing_event_, + dblink_db_name_, + dblink_pkg_name_); for (int64_t i = 0; OB_SUCC(ret) && i < param_cnt; ++i) { routine_param.reset(); if (OB_FAIL(routine_param.deserialize(buf, data_len, pos))) { @@ -618,7 +644,9 @@ OB_DEF_SERIALIZE_SIZE(ObRoutineInfo) route_sql_, type_id_, param_cnt, - tg_timing_event_); + tg_timing_event_, + dblink_db_name_, + dblink_pkg_name_); for (int64_t i = 0; i < param_cnt; ++i) { if (routine_params_.at(i) != NULL) { len += routine_params_.at(i)->get_serialize_size(); diff --git a/src/share/schema/ob_routine_info.h b/src/share/schema/ob_routine_info.h index 02bd67c59..cdf91df6b 100644 --- a/src/share/schema/ob_routine_info.h +++ b/src/share/schema/ob_routine_info.h @@ -44,6 +44,7 @@ enum ObParamExternType SP_EXTERN_PKGVAR_OR_TABCOL, // package.var%type or table.col%type SP_EXTERN_LOCAL_VAR, // declare v number; function f return is v%type; SP_EXTERN_SYS_REFCURSOR, + SP_EXTERN_DBLINK, }; enum ObRoutineParamInOut @@ -169,6 +170,8 @@ public: virtual void set_external_state() = 0; virtual int64_t get_param_start_idx() const { return 0; } virtual const common::ObString &get_routine_name() const = 0; + virtual uint64_t get_dblink_id() const { return OB_INVALID_ID; } + TO_STRING_EMPTY(); }; @@ -273,6 +276,7 @@ public: { return SP_EXTERN_SYS_REFCURSOR == get_extern_type_flag(); } + OB_INLINE bool is_dblink_type() const { return SP_EXTERN_DBLINK == get_extern_type_flag(); } OB_INLINE bool is_pl_integer_type() const { @@ -414,6 +418,7 @@ public: int get_routine_param(int64_t idx, ObIRoutineParam*& param) const; const ObIRoutineParam* get_ret_info() const; // getter + int64_t get_out_param_count() const; OB_INLINE uint64_t get_tenant_id() const { return tenant_id_; } OB_INLINE uint64_t get_database_id() const { return database_id_; } OB_INLINE uint64_t get_package_id() const { return package_id_; } @@ -439,6 +444,9 @@ public: OB_INLINE common::ObIArray &get_routine_params() { return routine_params_; } OB_INLINE int64_t get_type_id() const { return type_id_; } OB_INLINE TgTimingEvent get_tg_timing_event() const { return tg_timing_event_; } + OB_INLINE uint64_t get_dblink_id() const { return dblink_id_; } + OB_INLINE const common::ObString &get_dblink_db_name() const { return dblink_db_name_; } + OB_INLINE const common::ObString &get_dblink_pkg_name() const { return dblink_pkg_name_; } // setter OB_INLINE void set_tenant_id(uint64_t tenant_id) { tenant_id_ = tenant_id; } @@ -465,7 +473,10 @@ public: OB_INLINE int64_t get_param_start_idx() const { return is_procedure()?0:1; } OB_INLINE void set_type_id(int64_t type_id) { type_id_ = type_id; } OB_INLINE void set_tg_timing_event(TgTimingEvent tg) { tg_timing_event_ = tg; } - + OB_INLINE void set_dblink_id(uint64_t dblink_id) { dblink_id_ = dblink_id; } + OB_INLINE int set_dblink_db_name(const common::ObString &db_name) { return deep_copy_str(db_name, dblink_db_name_); } + OB_INLINE int set_dblink_pkg_name(const common::ObString &pkg_name) + { return deep_copy_str(pkg_name, dblink_pkg_name_); } OB_INLINE void set_routine_invalid() { flag_ |= SP_FLAG_INVALID; } OB_INLINE void set_noneditionable() { flag_ |= SP_FLAG_NONEDITIONABLE; } OB_INLINE void set_deterministic() { flag_ |= SP_FLAG_DETERMINISTIC; } @@ -609,6 +620,9 @@ private: common::ObSEArray routine_params_; //set by user, for function, idx 0 param is ret type TgTimingEvent tg_timing_event_; + uint64_t dblink_id_; + common::ObString dblink_db_name_; + common::ObString dblink_pkg_name_; }; } // namespace schema } // namespace share diff --git a/src/sql/engine/cmd/ob_routine_executor.cpp b/src/sql/engine/cmd/ob_routine_executor.cpp index b8df360e3..8c768cc30 100644 --- a/src/sql/engine/cmd/ob_routine_executor.cpp +++ b/src/sql/engine/cmd/ob_routine_executor.cpp @@ -202,20 +202,30 @@ int ObCallProcedureExecutor::execute(ObExecContext &ctx, ObCallProcedureStmt &st ObObj result; int64_t pkg_id = call_proc_info->is_udt_routine() ? share::schema::ObUDTObjectType::mask_object_id(package_id) : package_id; - if (OB_FAIL(ctx.get_pl_engine()->execute(ctx, - ctx.get_allocator(), - pkg_id, - routine_id, - path, - params, - nocopy_params, - result))) { - LOG_WARN("failed to execute pl", K(package_id), K(routine_id), K(ret), K(pkg_id)); - if (OB_READ_NOTHING == ret - && lib::is_oracle_mode() - && !ObTriggerInfo::is_trigger_package_id(package_id)) { - ret = OB_SUCCESS; + if (OB_ISNULL(stmt.get_dblink_routine_info())) { + if (OB_FAIL(ctx.get_pl_engine()->execute(ctx, + ctx.get_allocator(), + pkg_id, + routine_id, + path, + params, + nocopy_params, + result))) { + LOG_WARN("failed to execute pl", K(package_id), K(routine_id), K(ret), K(pkg_id)); } +#ifdef OB_BUILD_ORACLE_PL + } else if (OB_FAIL(ObSPIService::spi_execute_dblink(ctx, + ctx.get_allocator(), + NULL, + stmt.get_dblink_routine_info(), + params))) { + LOG_WARN("failed to execute dblink pl", K(ret), KP(stmt.get_dblink_routine_info())); +#endif + } + if (OB_READ_NOTHING == ret + && lib::is_oracle_mode() + && !ObTriggerInfo::is_trigger_package_id(package_id)) { + ret = OB_SUCCESS; } if (OB_FAIL(ret)) { } else if (call_proc_info->get_output_count() > 0) { diff --git a/src/sql/engine/cmd/ob_xa_executor.cpp b/src/sql/engine/cmd/ob_xa_executor.cpp index 748134527..6433f38d6 100644 --- a/src/sql/engine/cmd/ob_xa_executor.cpp +++ b/src/sql/engine/cmd/ob_xa_executor.cpp @@ -202,7 +202,7 @@ int ObPlXaEndExecutor::execute(ObExecContext &ctx, ObXaEndStmt &stmt) ObSQLSessionInfo::LockGuard session_query_guard(my_session->get_query_lock()); ObSQLSessionInfo::LockGuard data_lock_guard(my_session->get_thread_data_lock()); int64_t flags = stmt.get_flags(); - flags = my_session->has_tx_level_temp_table() ? (flags | ObXAFlag::TEMPTABLE) : flags; + flags = my_session->has_tx_level_temp_table() ? (flags | ObXAFlag::OBTEMPTABLE) : flags; my_session->get_raw_audit_record().trans_id_ = my_session->get_tx_id(); if (OB_FAIL(MTL(transaction::ObXAService*)->xa_end(xid, flags, my_session->get_tx_desc()))) { diff --git a/src/sql/ob_spi.cpp b/src/sql/ob_spi.cpp index bc2fd59b4..6a1251391 100644 --- a/src/sql/ob_spi.cpp +++ b/src/sql/ob_spi.cpp @@ -38,7 +38,10 @@ #include "storage/tx/ob_trans_service.h" #include "pl/sys_package/ob_dbms_sql.h" #include "pl/ob_pl.h" -#include "src/sql/dblink/ob_tm_service.h" +#include "sql/dblink/ob_tm_service.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/dblink/ob_pl_dblink_util.h" +#endif namespace oceanbase { @@ -8439,5 +8442,139 @@ int ObSPIService::spi_update_location(pl::ObPLExecCtx *ctx, uint64_t location) return ret; } +#ifdef OB_BUILD_ORACLE_PL +int ObSPIService::spi_execute_dblink(pl::ObPLExecCtx *ctx, + uint64_t dblink_id, + uint64_t package_id, + uint64_t proc_id, + ParamStore ¶ms) +{ + int ret = OB_SUCCESS; + ObExecContext *exec_ctx = NULL; + const ObRoutineInfo *routine_info = NULL; + const pl::ObPLDbLinkInfo *dblink_info = NULL; + CK (OB_NOT_NULL(ctx), ctx->valid()); + CK (OB_NOT_NULL(ctx->guard_)); + CK (OB_NOT_NULL(ctx->allocator_)); + CK (OB_NOT_NULL(exec_ctx = ctx->exec_ctx_)); + OZ (ctx->guard_->dblink_guard_.get_dblink_routine_info(dblink_id, package_id, proc_id, routine_info), + dblink_id, package_id, proc_id); + CK (OB_NOT_NULL(routine_info)); + OZ (ctx->guard_->dblink_guard_.get_dblink_info(dblink_id, dblink_info)); + CK (OB_NOT_NULL(dblink_info)); + OZ (spi_execute_dblink(*exec_ctx, *ctx->allocator_, dblink_info, routine_info, params)); + return ret; +} + +int ObSPIService::spi_execute_dblink(ObExecContext &exec_ctx, + ObIAllocator &allocator, + const pl::ObPLDbLinkInfo *dblink_info, + const ObRoutineInfo *routine_info, + ParamStore ¶ms) +{ + int ret = OB_SUCCESS; + sql::DblinkGetConnType conn_type = sql::DblinkGetConnType::DBLINK_POOL; + ObSQLSessionInfo *session = NULL; + uint64_t tenant_id = OB_INVALID_ID; + common::ObDbLinkProxy *dblink_proxy = NULL; + common::sqlclient::ObISQLConnection *dblink_conn = NULL; + ObString call_stmt; + typedef common::sqlclient::DblinkDriverProto DbLinkType; + DbLinkType link_type = DBLINK_UNKNOWN; + int64_t affected_rows; + transaction::ObTransID tx_id; + CK (OB_NOT_NULL(session = exec_ctx.get_my_session())); + CK (OB_NOT_NULL(routine_info)); + CK (OB_NOT_NULL(dblink_proxy = GCTX.dblink_proxy_)); + OX (tenant_id = session->get_effective_tenant_id()); + OZ (ObPLDblinkUtil::init_dblink(dblink_proxy, dblink_conn, routine_info->get_dblink_id(), *session, link_type)); + CK (OB_NOT_NULL(dblink_conn)); + if (DBLINK_DRV_OB == link_type) { + OZ (ObPLDblinkUtil::print_dblink_call_stmt(allocator, *session, call_stmt, params, routine_info)); + OZ (dblink_proxy->dblink_write(dblink_conn, affected_rows, call_stmt.ptr()), call_stmt); + } else { + const int64_t out_param_cnt = routine_info->get_out_param_count(); + int64_t out_param_idx[out_param_cnt]; + for (int64_t i = 0; i < out_param_cnt; i++) { + out_param_idx[i] = 0; + } + common::ObSEArray udts; + ParamStore exec_params((ObWrapperAllocator(allocator))); + for (int64_t i = 0; OB_SUCC(ret) && i < params.count(); i++) { + ObObjParam param_value; + if (params.at(i).is_pl_extend()) { + OZ (ObUserDefinedType::deep_copy_obj(allocator, params.at(i), param_value)); + } else { + OZ (deep_copy_obj(allocator, params.at(i), param_value)); + } + OX (param_value.set_is_pl_mock_default_param(params.at(i).is_pl_mock_default_param())); + OX (param_value.set_param_meta()); + OX (param_value.set_accuracy(params.at(i).get_accuracy())); + OZ (exec_params.push_back(param_value)); + } + OZ (ObPLDblinkUtil::print_dblink_ps_call_stmt(allocator, dblink_info, + call_stmt, params, routine_info, + udts, out_param_idx, out_param_cnt)); + OZ (ObTMService::tm_rm_start(exec_ctx, link_type, dblink_conn, tx_id)); + OZ (dblink_proxy->dblink_execute_proc(OB_INVALID_TENANT_ID, dblink_conn, allocator, + exec_params, call_stmt, *routine_info, udts, + session->get_timezone_info()), call_stmt); + OZ (spi_after_execute_dblink(session, routine_info, allocator, params, exec_params)); + } + + if (OB_NOT_NULL(dblink_conn)) { + int tmp_ret = OB_SUCCESS; + if (OB_SUCCESS != (tmp_ret = dblink_proxy->release_dblink(link_type, dblink_conn))) { + LOG_WARN("failed to relese connection", K(tmp_ret)); + } + } + return ret; +} + +int ObSPIService::spi_after_execute_dblink(ObSQLSessionInfo *session, + const ObRoutineInfo *routine_info, + ObIAllocator &allocator, + ParamStore ¶ms, + ParamStore &exec_params) +{ + int ret = OB_SUCCESS; + CK (OB_NOT_NULL(routine_info)); + for (int64_t i = 0; OB_SUCC(ret) && i < routine_info->get_routine_params().count(); i++) { + ObRoutineParam *param = routine_info->get_routine_params().at(i); + if (OB_ISNULL(param)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("param is NULL", K(ret), K(i)); + } else if (param->is_out_sp_param() || param->is_inout_sp_param()) { + if (ob_is_string_or_lob_type(exec_params.at(i).get_type()) + && (0 == exec_params.at(i).get_varchar().case_compare(""))) { + params.at(i).set_null(); + } else { + if (ob_is_extend(param->get_param_type().get_obj_type())) { + OZ (ObUserDefinedType::deep_copy_obj(allocator, exec_params.at(i), params.at(i), true)); + ObUserDefinedType::destruct_obj(exec_params.at(i)); + } else if (param->get_param_type().get_obj_type() != exec_params.at(i).get_param_meta().get_type()) { + const ObDataType &datatype = param->get_param_type(); + ObObjParam result_value; + ObExprResType result_type; + result_type.reset(); + result_type.set_meta(datatype.get_meta_type()); + result_type.set_accuracy(datatype.get_accuracy()); + OZ (spi_convert(session, &allocator, exec_params.at(i), result_type, result_value)); + OZ (deep_copy_obj(allocator, result_value, params.at(i))); + OX (params.at(i).set_param_meta()); + } else { + OZ (deep_copy_obj(allocator, exec_params.at(i), params.at(i))); + OX (params.at(i).set_param_meta()); + } + } + } else if ((ob_is_extend(param->get_param_type().get_obj_type()))) { + ObUserDefinedType::destruct_obj(exec_params.at(i)); + } + } + return ret; +} + +#endif + } } diff --git a/src/sql/ob_spi.h b/src/sql/ob_spi.h index d6eefab15..53748e4af 100644 --- a/src/sql/ob_spi.h +++ b/src/sql/ob_spi.h @@ -19,6 +19,9 @@ #include "sql/engine/basic/ob_ra_row_store.h" #include "sql/session/ob_sql_session_info.h" #include "sql/ob_result_set.h" +#ifdef OB_BUILD_ORACLE_PL +#include "pl/dblink/ob_pl_dblink_info.h" +#endif namespace oceanbase { namespace observer @@ -707,6 +710,23 @@ public: static void adjust_pl_status_for_xa(sql::ObExecContext &ctx, int &result); static int fill_cursor(ObResultSet &result_set, ObSPICursor *cursor); +#ifdef OB_BUILD_ORACLE_PL + static int spi_execute_dblink(pl::ObPLExecCtx *ctx, + uint64_t dblink_id, + uint64_t package_id, + uint64_t proc_id, + ParamStore ¶ms); + static int spi_execute_dblink(ObExecContext &exec_ctx, + ObIAllocator &allocator, + const pl::ObPLDbLinkInfo *dblink_info, + const ObRoutineInfo *routine_info, + ParamStore ¶ms); + static int spi_after_execute_dblink(ObSQLSessionInfo *session, + const ObRoutineInfo *routine_info, + ObIAllocator &allocator, + ParamStore ¶ms, + ParamStore &exec_params); +#endif private: static int recreate_implicit_savapoint_if_need(pl::ObPLExecCtx *ctx, int &result); static int recreate_implicit_savapoint_if_need(sql::ObExecContext &ctx, int &result); diff --git a/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp b/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp index 9ce6b1329..cf8bd399f 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp +++ b/src/sql/resolver/cmd/ob_call_procedure_resolver.cpp @@ -312,10 +312,12 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) int ret = OB_SUCCESS; ObCallProcedureStmt *stmt = NULL; ParseNode *name_node = parse_tree.children_[0]; - ParseNode *params_node = parse_tree.children_[1]; + ParseNode *dblink_node = lib::is_oracle_mode() ? parse_tree.children_[1] : NULL; + ParseNode *params_node = lib::is_oracle_mode() ? parse_tree.children_[2] : parse_tree.children_[1]; ObString db_name; ObString package_name; ObString sp_name; + ObString dblink_name; ObCallProcedureInfo *call_proc_info = NULL; const ObRoutineInfo *proc_info = NULL; if (OB_ISNULL(schema_checker_) || OB_ISNULL(session_info_)) { @@ -346,12 +348,13 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) if (T_SP_ACCESS_NAME != name_node->type_) { ret = OB_ERR_UNEXPECTED; LOG_WARN("Invalid procedure name node", K(name_node->type_), K(ret)); - } else { + } else if (OB_ISNULL(dblink_node)) { if (OB_FAIL(ObResolverUtils::resolve_sp_access_name(*schema_checker_, session_info_->get_effective_tenant_id(), session_info_->get_database_name(), *name_node, - db_name, package_name, sp_name))) { + db_name, package_name, sp_name, + dblink_name))) { LOG_WARN("resolve sp name failed", K(ret)); } else if (db_name.empty() && session_info_->get_database_name().empty()) { ret = OB_ERR_NO_DB_SELECTED; @@ -364,23 +367,35 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) } } + } else { + CK (OB_NOT_NULL(parse_tree.children_[1]->children_[0])); + OZ (resolve_dblink_routine_name(*parse_tree.children_[0], + *parse_tree.children_[1]->children_[0], + dblink_name, + db_name, + package_name, + sp_name)); } } ObSEArray expr_params; + pl::ObPLPackageGuard package_guard(params_.session_info_->get_effective_tenant_id()); // 获取routine schem info if (OB_SUCC(ret)) { if (OB_NOT_NULL(params_node) && OB_FAIL(resolve_param_exprs(params_node, expr_params))) { LOG_WARN("failed to resolve param exprs", K(ret)); - } else if (OB_FAIL(ObResolverUtils::get_routine(params_, - (*session_info_).get_effective_tenant_id(), - (*session_info_).get_database_name(), - db_name, - package_name, - sp_name, - ROUTINE_PROCEDURE_TYPE, - expr_params, - proc_info))) { + } else if (OB_FAIL(ObResolverUtils::get_routine(package_guard, + params_, + (*session_info_).get_effective_tenant_id(), + (*session_info_).get_database_name(), + db_name, + package_name, + sp_name, + ROUTINE_PROCEDURE_TYPE, + expr_params, + proc_info, + dblink_name, + &(call_proc_info->get_allocator())))) { LOG_WARN("failed to get routine info", K(ret), K(db_name), K(package_name), K(sp_name)); } else if (OB_ISNULL(proc_info)) { ret = OB_ERR_UNEXPECTED; @@ -445,7 +460,9 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) *(session_info_), *(params_.allocator_), *(params_.sql_proxy_), - pl_type)); + pl_type, + NULL, + &package_guard.dblink_guard_)); } if (OB_SUCC(ret)) { if (param_info->is_out_sp_param() || param_info->is_inout_sp_param()) { @@ -519,13 +536,17 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) } } } - + if (OB_SUCC(ret) && OB_NOT_NULL(proc_info) && (OB_INVALID_ID != proc_info->get_dblink_id())) { + stmt->set_dblink_routine_info(proc_info); + } // Step 4: cg raw expr OX (call_proc_info->set_param_cnt(params.count())); OZ (call_proc_info->prepare_expression(params)); OZ (call_proc_info->final_expression(params, session_info_, schema_checker_->get_schema_mgr())); OX (stmt->set_call_proc_info(call_proc_info)); - if (params_.is_execute_call_stmt_ && 0 != params_.cur_sql_.length()) { + if (params_.is_execute_call_stmt_ + && 0 != params_.cur_sql_.length() + && NULL == stmt->get_dblink_routine_info()) { if (NULL != params_.param_list_) { OZ (call_proc_info->set_params_info(*params_.param_list_)); } @@ -538,5 +559,42 @@ int ObCallProcedureResolver::resolve(const ParseNode &parse_tree) return ret; } +int ObCallProcedureResolver::resolve_dblink_routine_name(const ParseNode &access_node, + const ParseNode &dblink_node, + ObString &dblink_name, + ObString &db_name, + ObString &pkg_name, + ObString &sp_name) +{ + int ret = OB_SUCCESS; + const ParseNode *db_node = access_node.children_[0]; + const ParseNode *pkg_node = access_node.children_[1]; + const ParseNode *sp_node = access_node.children_[2]; + CK (OB_LIKELY(T_SP_ACCESS_NAME == access_node.type_)); + CK (OB_LIKELY(T_USER_VARIABLE_IDENTIFIER == dblink_node.type_)); + if (OB_SUCC(ret)) { + OX (dblink_name.assign_ptr(dblink_node.str_value_, static_cast(dblink_node.str_len_))); + } + if (OB_SUCC(ret) && OB_NOT_NULL(db_node)) { + if (OB_LIKELY(T_IDENT == db_node->type_)) { + db_name.assign_ptr(db_node->str_value_, static_cast(db_node->str_len_)); + } + } + if (OB_SUCC(ret) && OB_NOT_NULL(pkg_node)) { + if (OB_LIKELY(T_IDENT == pkg_node->type_)) { + pkg_name.assign_ptr(pkg_node->str_value_, static_cast(pkg_node->str_len_)); + } + } + if (OB_SUCC(ret)) { + if (OB_ISNULL(sp_node) && OB_UNLIKELY(T_IDENT != sp_node->type_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("sp_node is invalid", K(ret), K(sp_node)); + } else { + sp_name.assign_ptr(sp_node->str_value_, static_cast(sp_node->str_len_)); + } + } + return ret; +} + } } diff --git a/src/sql/resolver/cmd/ob_call_procedure_resolver.h b/src/sql/resolver/cmd/ob_call_procedure_resolver.h index 12ae2ed49..be8807d66 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_resolver.h +++ b/src/sql/resolver/cmd/ob_call_procedure_resolver.h @@ -56,6 +56,12 @@ private: int find_call_proc_info(ObCallProcedureStmt &stmt); int add_call_proc_info(ObCallProcedureInfo *call_info); int generate_pl_cache_ctx(pl::ObPLCacheCtx &pc_ctx); + int resolve_dblink_routine_name(const ParseNode &access_node, + const ParseNode &dblink_node, + ObString &dblink_name, + ObString &db_name, + ObString &pkg_name, + ObString &sp_name); private: // disallow copy DISALLOW_COPY_AND_ASSIGN(ObCallProcedureResolver); diff --git a/src/sql/resolver/cmd/ob_call_procedure_stmt.h b/src/sql/resolver/cmd/ob_call_procedure_stmt.h index a95903f26..ff9fca3ac 100644 --- a/src/sql/resolver/cmd/ob_call_procedure_stmt.h +++ b/src/sql/resolver/cmd/ob_call_procedure_stmt.h @@ -135,7 +135,9 @@ public: explicit ObCallProcedureStmt() : ObCMDStmt(NULL, stmt::T_CALL_PROCEDURE), call_proc_info_(NULL), - cache_call_info_guard_(MAX_HANDLE) { + cache_call_info_guard_(MAX_HANDLE), + dblink_routine_info_(NULL) + { } virtual ~ObCallProcedureStmt() { @@ -147,11 +149,12 @@ public: } ObCallProcedureInfo *get_call_proc_info() { return call_proc_info_; } ObCacheObjGuard &get_cacheobj_guard() { return cache_call_info_guard_; } - + void set_dblink_routine_info(const ObRoutineInfo *routine_info) { dblink_routine_info_ = routine_info; } + const ObRoutineInfo *get_dblink_routine_info() const { return dblink_routine_info_; } private: ObCallProcedureInfo *call_proc_info_; ObCacheObjGuard cache_call_info_guard_; - + const ObRoutineInfo *dblink_routine_info_; DISALLOW_COPY_AND_ASSIGN(ObCallProcedureStmt); }; diff --git a/src/sql/resolver/ob_resolver_utils.cpp b/src/sql/resolver/ob_resolver_utils.cpp index d6980c242..2c3d51184 100644 --- a/src/sql/resolver/ob_resolver_utils.cpp +++ b/src/sql/resolver/ob_resolver_utils.cpp @@ -392,7 +392,7 @@ int ObResolverUtils::get_candidate_routines(ObSchemaChecker &schema_checker, const ObString &package_name, const ObString &routine_name, const share::schema::ObRoutineType routine_type, common::ObIArray &routines, - uint64_t udt_id) + uint64_t udt_id, const pl::ObPLResolveCtx *resolve_ctx) { int ret = OB_SUCCESS; @@ -483,6 +483,18 @@ if ((OB_FAIL(ret) || 0 == routines.count()) \ TRY_SYNONYM(routine_name); if (OB_SUCC(ret) && need_try_synonym) { GET_STANDALONE_ROUTINE(); + if (OB_SUCC(ret) && OB_ISNULL(routine_info) && OB_NOT_NULL(resolve_ctx)) { + // try dblink synonym + ObString tmp_name = object_name; + ObString full_object_name = tmp_name.split_on('@'); + if (full_object_name.empty()) { + // not a dblink + } else { + ObString remote_db_name = full_object_name.split_on('.'); + OZ (resolve_ctx->package_guard_.dblink_guard_.get_routine_infos_with_synonym(resolve_ctx->session_info_, + resolve_ctx->schema_guard_, tmp_name, remote_db_name, ObString(""), full_object_name, routines)); + } + } } } else { // try package routines OZ (schema_checker.get_database_id(tenant_id, real_db_name, database_id)); @@ -998,7 +1010,9 @@ int ObResolverUtils::check_match(const pl::ObPLResolveCtx &resolve_ctx, resolve_ctx.session_info_, resolve_ctx.allocator_, resolve_ctx.sql_proxy_, - dst_pl_type)); + dst_pl_type, + NULL, + &resolve_ctx.package_guard_.dblink_guard_)); #ifdef OB_BUILD_ORACLE_PL if (OB_SUCC(ret) && dst_pl_type.is_subtype()) { const ObUserDefinedType *user_type = NULL; @@ -1035,7 +1049,7 @@ int ObResolverUtils::match_vacancy_parameters( // 处理空缺参数, 如果有默认值填充默认值, 否则报错 for (int64_t i = 0; OB_SUCC(ret) && i < match_info.match_info_.count(); ++i) { ObIRoutineParam *routine_param = NULL; - if (ObMaxType == match_info.match_info_.at(i).dest_type_) { + if(ObMaxType == match_info.match_info_.at(i).dest_type_) { OZ (routine_info.get_routine_param(i, routine_param)); CK (OB_NOT_NULL(routine_param)); if (OB_FAIL(ret)) { @@ -1237,7 +1251,8 @@ int ObResolverUtils::pick_routine(const pl::ObPLResolveCtx &resolve_ctx, return ret; } -int ObResolverUtils::get_routine(ObResolverParams ¶ms, +int ObResolverUtils::get_routine(pl::ObPLPackageGuard &package_guard, + ObResolverParams ¶ms, uint64_t tenant_id, const ObString ¤t_database, const ObString &db_name, @@ -1245,16 +1260,26 @@ int ObResolverUtils::get_routine(ObResolverParams ¶ms, const ObString &routine_name, const share::schema::ObRoutineType routine_type, const common::ObIArray &expr_params, - const ObRoutineInfo *&routine) + const ObRoutineInfo *&routine, + const ObString &dblink_name, + ObIAllocator *allocator) { int ret = OB_SUCCESS; +#define COPY_DBLINK_ROUTINE(dblink_routine) \ + ObRoutineInfo *copy_routine = NULL; \ + CK (OB_NOT_NULL(allocator)); \ + OZ (ObSchemaUtils::alloc_schema(*allocator, \ + *(static_cast(dblink_routine)), \ + copy_routine)); \ + OX (routine = copy_routine); + + const ObRoutineInfo *tmp_routine_info = NULL; CK (OB_NOT_NULL(params.allocator_)); CK (OB_NOT_NULL(params.session_info_)); CK (OB_NOT_NULL(params.schema_checker_)); CK (OB_NOT_NULL(params.schema_checker_->get_schema_guard())); CK (OB_NOT_NULL(GCTX.sql_proxy_)); if (OB_SUCC(ret)) { - ObPLPackageGuard package_guard(params.session_info_->get_effective_tenant_id()); ObPLResolveCtx resolve_ctx(*(params.allocator_), *(params.session_info_), *(params.schema_checker_->get_schema_guard()), @@ -1268,15 +1293,104 @@ int ObResolverUtils::get_routine(ObResolverParams ¶ms, resolve_ctx.params_.param_list_ = params.param_list_; resolve_ctx.params_.is_execute_call_stmt_ = params.is_execute_call_stmt_; OZ (package_guard.init()); - OZ (get_routine(resolve_ctx, - tenant_id, - current_database, - db_name, - package_name, - routine_name, - routine_type, - expr_params, - routine)); + if (dblink_name.empty()) { + OZ (get_routine(resolve_ctx, + tenant_id, + current_database, + db_name, + package_name, + routine_name, + routine_type, + expr_params, + tmp_routine_info)); + if (OB_SUCC(ret)) { + if (OB_INVALID_ID == tmp_routine_info->get_dblink_id()) { + routine = tmp_routine_info; + } else { + COPY_DBLINK_ROUTINE(tmp_routine_info); + } + } + if (OB_ERR_SP_DOES_NOT_EXIST == ret) { + /* Example 1: create or replace synonym test.pkg100_syn for webber.pkg100@oci_link; + * `pkg100` is a package name in remote database `webber`. + * Example 2: create or replace synonym test.p101_syn for webber.p101@oci_link; + * `p101` is a procedure name in remote database `webber`. + * + * If the code executes here, there are the following situations + * 1. Only `db_name.empty()` is true , this is not possible; + * 2. Only `package_name.empty()` is true, user call statement is `call test.p101_syn(1)`; + * 3. `(db_name.empty() && package_name.empty()` is true, user call statement is `call p101_syn(1)`; + * 4. `db_name.empty()` is false and `package_name.empty()` is false, + * user call statement is `call test.pkg100_syn.p1(1)` + */ + + ret = OB_SUCCESS; + uint64_t database_id = OB_INVALID_ID; + uint64_t object_db_id = OB_INVALID_ID; + bool exist = false; + ObString object_name; + ObSchemaChecker schema_checker; + ObSynonymChecker synonym_checker; + bool routine_name_is_synonym = package_name.empty(); + const ObString &synonym_name = routine_name_is_synonym ? routine_name : package_name; + OZ (schema_checker.init(resolve_ctx.schema_guard_)); + OZ (schema_checker.get_database_id(tenant_id, (db_name.empty() ? current_database : db_name), database_id)); + OZ (resolve_synonym_object_recursively(schema_checker, synonym_checker, tenant_id, database_id, + synonym_name, object_db_id, object_name, exist)); + LOG_INFO("after find synonym", K(ret), K(synonym_name), K(object_name), K(object_db_id), K(exist)); + if (OB_SUCC(ret) && exist) { + ObString tmp_name; + if (OB_FAIL(ob_write_string(*params.allocator_, object_name, tmp_name))) { + LOG_WARN("write string failed", K(ret)); + } else { + ObString full_object_name = tmp_name.split_on('@'); + if (full_object_name.empty()) { + exist = false; + } else { + ObString remote_db_name = full_object_name.split_on('.'); + const ObIRoutineInfo *dblink_routine_info = NULL; + // ObRoutineInfo *tmp_routine_info = NULL; + if (routine_name_is_synonym) { + OZ (ObPLResolver::resolve_dblink_routine(resolve_ctx, + tmp_name, + remote_db_name, + ObString(""), + full_object_name, + expr_params, + dblink_routine_info)); + } else { + OZ (ObPLResolver::resolve_dblink_routine(resolve_ctx, + tmp_name, + remote_db_name, + full_object_name, + routine_name, + expr_params, + dblink_routine_info)); + } + if (OB_SUCC(ret) && OB_NOT_NULL(dblink_routine_info)) { + COPY_DBLINK_ROUTINE(dblink_routine_info); + } + } + } + } + if (OB_SUCC(ret) && !exist) { + ret = OB_ERR_SP_DOES_NOT_EXIST; + LOG_WARN("routine not exist", K(ret)); + } + } + } else { + const ObIRoutineInfo *dblink_routine_info = NULL; + OZ (ObPLResolver::resolve_dblink_routine(resolve_ctx, + dblink_name, + db_name, + package_name, + routine_name, + expr_params, + dblink_routine_info)); + if (OB_SUCC(ret) && OB_NOT_NULL(dblink_routine_info)) { + COPY_DBLINK_ROUTINE(dblink_routine_info); + } + } } return ret; } @@ -1306,7 +1420,8 @@ int ObResolverUtils::get_routine(const pl::ObPLResolveCtx &resolve_ctx, routine_name, routine_type, candidate_routine_infos, - udt_id))) { + udt_id, + &resolve_ctx))) { LOG_WARN("failed to get candidate routine infos", K(db_name), K(package_name), K(routine_name), K(ret)); } else { @@ -1355,6 +1470,7 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, { int ret = OB_SUCCESS; ParseResult parser_result; + ObString dblink_name; ObStmtNodeTree *parser_tree = NULL; lib::Worker::CompatMode compat_mode = lib::Worker::CompatMode::MYSQL; if (OB_FAIL(share::ObCompatModeGetter::get_tenant_mode(tenant_id, compat_mode))) { @@ -1391,7 +1507,7 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, tenant_id, current_database, *(parser_tree->children_[0]->children_[0]), - database_name, package_name, routine_name))) { + database_name, package_name, routine_name, dblink_name))) { LOG_WARN("failed to resolve_sp_access_name", K(ret), K(procedure_name), K(tenant_id), K(current_database)); } @@ -1447,7 +1563,8 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, const ParseNode &sp_access_name_node, ObString &db_name, ObString &package_name, - ObString &routine_name) + ObString &routine_name, + ObString &dblink_name) { int ret = OB_SUCCESS; @@ -1483,6 +1600,7 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, ObString package_or_db_name; uint64_t package_id = OB_INVALID_ID; uint64_t database_id = OB_INVALID_ID; + bool is_dblink_routine = false; if (OB_UNLIKELY(package_or_db_node->type_ != T_IDENT)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("package_or_db_node is invalid", K(package_or_db_node)); @@ -1521,6 +1639,22 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, } else if (OB_FAIL(schema_checker.get_package_id( tenant_id, object_db_id, object_name, COMPATIBLE_ORACLE_MODE, package_id))) { LOG_WARN("failed to get package id", K(ret), K(object_db_id), K(object_name)); + // If failed, object_name may be a dblink object + if (OB_ERR_PACKAGE_DOSE_NOT_EXIST == ret) { + ret = OB_SUCCESS; + ObString full_pkg_name = object_name.split_on('@'); + if (full_pkg_name.empty()) { + // not a dblink + } else { + dblink_name = object_name; + db_name = full_pkg_name.split_on('.'); + package_name = full_pkg_name; + is_dblink_routine = true; + } + if (OB_SUCC(ret) && !is_dblink_routine) { + ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST; + } + } } else { package_name = object_name; } @@ -1529,7 +1663,8 @@ int ObResolverUtils::resolve_sp_access_name(ObSchemaChecker &schema_checker, object_name = package_or_db_name; } } - if (OB_FAIL(ret) || OB_INVALID_ID == package_id) { + if (is_dblink_routine) { + } else if (OB_FAIL(ret) || OB_INVALID_ID == package_id) { if (OB_FAIL(schema_checker.get_package_id( OB_SYS_TENANT_ID, OB_SYS_DATABASE_ID, object_name, COMPATIBLE_ORACLE_MODE, package_id))) { diff --git a/src/sql/resolver/ob_resolver_utils.h b/src/sql/resolver/ob_resolver_utils.h index 7a9fcff1d..61c3ed6df 100644 --- a/src/sql/resolver/ob_resolver_utils.h +++ b/src/sql/resolver/ob_resolver_utils.h @@ -165,7 +165,8 @@ public: const ObString &routine_name, const share::schema::ObRoutineType routine_type, common::ObIArray &routines, - uint64_t udt_id = OB_INVALID_ID); + uint64_t udt_id = OB_INVALID_ID, + const pl::ObPLResolveCtx *resolve_ctx = NULL); static int check_routine_exists(const ObSQLSessionInfo *session_info, ObSchemaChecker *schema_checker, pl::ObPLBlockNS *secondary_namespace, @@ -227,7 +228,8 @@ public: const common::ObIArray &expr_params, const common::ObIArray &routine_infos, const share::schema::ObRoutineInfo *&routine_info); - static int get_routine(ObResolverParams ¶ms, + static int get_routine(pl::ObPLPackageGuard &package_guard, + ObResolverParams ¶ms, uint64_t tenant_id, const ObString ¤t_database, const ObString &db_name, @@ -235,7 +237,9 @@ public: const ObString &routine_name, const share::schema::ObRoutineType routine_type, const common::ObIArray &expr_params, - const share::schema::ObRoutineInfo *&routine); + const share::schema::ObRoutineInfo *&routine, + const ObString &dblink_name = ObString(""), + ObIAllocator *allocator = NULL); static int get_routine(const pl::ObPLResolveCtx &resolve_ctx, uint64_t tenant_id, const ObString ¤t_database, @@ -259,7 +263,8 @@ public: const ParseNode &sp_access_name_node, ObString &db_name, ObString &package_name, - ObString &routine_name); + ObString &routine_name, + ObString &dblink_name); static int resolve_sp_name(ObSQLSessionInfo &session_info, const ParseNode &sp_name_node, ObString &db_name, diff --git a/src/storage/tx/ob_dblink_client.cpp b/src/storage/tx/ob_dblink_client.cpp index c2079e750..3bed43bf9 100644 --- a/src/storage/tx/ob_dblink_client.cpp +++ b/src/storage/tx/ob_dblink_client.cpp @@ -93,9 +93,9 @@ int ObDBLinkClient::rm_xa_start(const ObXATransID &xid, const ObTxIsolationLevel } // TODO, check connection } else { - int64_t flag = ObXAFlag::TMNOFLAGS; + int64_t flag = ObXAFlag::OBTMNOFLAGS; if (ObTxIsolationLevel::RR == isolation || ObTxIsolationLevel::SERIAL == isolation) { - flag = ObXAFlag::TMSERIALIZABLE; + flag = ObXAFlag::OBTMSERIALIZABLE; } if (OB_FAIL(init_query_impl_(isolation))) { TRANS_LOG(WARN, "fail to init query impl", K(ret), K(xid), K(isolation), K(*this)); @@ -220,7 +220,7 @@ int ObDBLinkClient::rm_xa_commit() } } else { // two phase commit - const int64_t flags = ObXAFlag::TMNOFLAGS; + const int64_t flags = ObXAFlag::OBTMNOFLAGS; state_ = ObDBLinkClientState::COMMITTING; if (OB_FAIL(impl_->xa_commit(xid_, flags))) { TRANS_LOG(WARN, "fail to execute query", K(ret), K(*this)); @@ -302,7 +302,7 @@ int ObDBLinkClient::rm_xa_end_() TRANS_LOG(WARN, "unexpected dblink client", K(ret), K(*this)); } } else { - if (OB_FAIL(impl_->xa_end(xid_, ObXAFlag::TMSUCCESS))) { + if (OB_FAIL(impl_->xa_end(xid_, ObXAFlag::OBTMSUCCESS))) { TRANS_LOG(WARN, "fail to do xa end", K(ret), K(*this)); } else { state_ = ObDBLinkClientState::END; diff --git a/src/storage/tx/ob_xa_ctx.cpp b/src/storage/tx/ob_xa_ctx.cpp index 938c1016f..26fb06efa 100644 --- a/src/storage/tx/ob_xa_ctx.cpp +++ b/src/storage/tx/ob_xa_ctx.cpp @@ -755,7 +755,7 @@ int ObXACtx::process_xa_start_loosely_(const obrpc::ObXAStartRPCRequest &req) const ObXATransID &xid = req.get_xid(); const ObAddr &sender = req.get_sender(); const int64_t timeout_seconds = req.get_timeout_seconds(); - const int64_t unused_flag = ObXAFlag::TMNOFLAGS; + const int64_t unused_flag = ObXAFlag::OBTMNOFLAGS; const bool is_new_branch = req.is_new_branch(); ObXABranchInfo info; diff --git a/src/storage/tx/ob_xa_dblink_service.cpp b/src/storage/tx/ob_xa_dblink_service.cpp index cbcea5205..c40122965 100644 --- a/src/storage/tx/ob_xa_dblink_service.cpp +++ b/src/storage/tx/ob_xa_dblink_service.cpp @@ -517,7 +517,7 @@ int ObXAService::commit_for_dblink_trans(ObTxDesc *&tx_desc) } } // step 1.2, xa end for local branch - if (OB_SUCCESS != (tmp_ret = xa_end(xid, ObXAFlag::TMSUCCESS, tx_desc))) { + if (OB_SUCCESS != (tmp_ret = xa_end(xid, ObXAFlag::OBTMSUCCESS, tx_desc))) { TRANS_LOG(WARN, "xa end failed", K(tmp_ret), K(xid), K(tx_id)); need_rollback = true; } @@ -571,7 +571,7 @@ int ObXAService::commit_for_dblink_trans(ObTxDesc *&tx_desc) // do nothing } else { ObTransID unused_tx_id; - if (OB_SUCCESS != (tmp_ret = xa_commit(xid, ObXAFlag::TMNOFLAGS, timeout_seconds, + if (OB_SUCCESS != (tmp_ret = xa_commit(xid, ObXAFlag::OBTMNOFLAGS, timeout_seconds, has_tx_level_temp_table, unused_tx_id))) { TRANS_LOG(WARN, "xa rollback for local failed", K(tmp_ret), K(xid), K(tx_id), K(has_tx_level_temp_table)); @@ -651,7 +651,7 @@ int ObXAService::rollback_for_dblink_trans(ObTxDesc *&tx_desc) } } // step 1.2, xa end for local branch - if (OB_SUCCESS != (tmp_ret = xa_end(xid, ObXAFlag::TMSUCCESS, tx_desc))) { + if (OB_SUCCESS != (tmp_ret = xa_end(xid, ObXAFlag::OBTMSUCCESS, tx_desc))) { TRANS_LOG(WARN, "xa end failed", K(tmp_ret), K(xid), K(tx_id)); } // step 2, xa rollback for each participant diff --git a/src/storage/tx/ob_xa_define.cpp b/src/storage/tx/ob_xa_define.cpp index 9cfef2788..d50e97d70 100644 --- a/src/storage/tx/ob_xa_define.cpp +++ b/src/storage/tx/ob_xa_define.cpp @@ -228,20 +228,20 @@ bool ObXAFlag::is_valid(const int64_t flag, const int64_t xa_req_type) switch (xa_req_type) { case ObXAReqType::XA_START: { - if (((flag & TMRESUME) && ((flag & TMJOIN) || (flag & LOOSELY))) - || ((flag & LOOSELY) && (flag & TMJOIN))) { + if (((flag & OBTMRESUME) && ((flag & OBTMJOIN) || (flag & OBLOOSELY))) + || ((flag & OBLOOSELY) && (flag & OBTMJOIN))) { ret_bool = false; } else { - const bool is_resumejoin = flag & (TMRESUME | TMJOIN); + const bool is_resumejoin = flag & (OBTMRESUME | OBTMJOIN); if (!is_resumejoin) { - const int64_t mask = LOOSELY | TMREADONLY | TMSERIALIZABLE; + const int64_t mask = OBLOOSELY | OBTMREADONLY | OBTMSERIALIZABLE; if (mask != (flag | mask)) { ret_bool = false; } else { ret_bool = true; } } else { - if ((flag & TMJOIN) && (flag & TMRESUME)) { + if ((flag & OBTMJOIN) && (flag & OBTMRESUME)) { ret_bool = false; } else { ret_bool = true; @@ -252,7 +252,7 @@ bool ObXAFlag::is_valid(const int64_t flag, const int64_t xa_req_type) } case ObXAReqType::XA_END: { const int64_t mask = 0x00000000FFFFFFFF; - if ((flag & mask) != TMSUSPEND && (flag & mask) != TMSUCCESS && (flag & mask) != TMFAIL) { + if ((flag & mask) != OBTMSUSPEND && (flag & mask) != OBTMSUCCESS && (flag & mask) != OBTMFAIL) { ret_bool = false; } else { ret_bool = true; @@ -267,7 +267,7 @@ bool ObXAFlag::is_valid(const int64_t flag, const int64_t xa_req_type) } case ObXAReqType::XA_COMMIT: { // noflags or onephase - if (flag != TMNOFLAGS && flag != TMONEPHASE) { + if (flag != OBTMNOFLAGS && flag != OBTMONEPHASE) { ret_bool = false; } else { ret_bool = true; @@ -293,9 +293,9 @@ bool ObXAFlag::is_valid(const int64_t flag, const int64_t xa_req_type) bool ObXAFlag::is_valid_inner_flag(const int64_t flag) { bool ret_bool = true; - if ((flag & TMSUSPEND) && (flag & TMSUCCESS)) { + if ((flag & OBTMSUSPEND) && (flag & OBTMSUCCESS)) { ret_bool = false; - } else if (!(flag & TMSUSPEND) && !(flag & TMSUCCESS)) { + } else if (!(flag & OBTMSUSPEND) && !(flag & OBTMSUCCESS)) { ret_bool = false; } else { ret_bool = true; @@ -308,10 +308,10 @@ bool ObXAFlag::is_tmnoflags(const int64_t flag, const int64_t xa_req_type) { bool ret_bool = true; if (ObXAReqType::XA_START == xa_req_type) { - const int64_t mask = LOOSELY | TMREADONLY | TMSERIALIZABLE; + const int64_t mask = OBLOOSELY | OBTMREADONLY | OBTMSERIALIZABLE; ret_bool = ((mask | flag) == mask); } else { - ret_bool = (TMNOFLAGS == flag); + ret_bool = (OBTMNOFLAGS == flag); } TRANS_LOG(INFO, "check tmnoflags", K(ret_bool), K(xa_req_type), KPHEX(&flag, sizeof(int64_t))); return ret_bool; diff --git a/src/storage/tx/ob_xa_define.h b/src/storage/tx/ob_xa_define.h index b5be1d3ef..2e90a67e6 100644 --- a/src/storage/tx/ob_xa_define.h +++ b/src/storage/tx/ob_xa_define.h @@ -104,21 +104,22 @@ class ObXAFlag public: enum { - TMNOFLAGS = 0, + OBTMNOFLAGS = 0, // non-standard xa protocol, to denote a readonly xa trans - TMREADONLY = 0x100, + OBTMREADONLY = 0x100, // non-standard xa protocol, to denote a serializable xa trans - TMSERIALIZABLE = 0x400, + OBTMSERIALIZABLE = 0x400, // non-standard xa protocol, to denote loosely coupled xa trans - LOOSELY = 0x10000, - TMJOIN = 0x200000, - TMSUSPEND = 0x2000000, - TMSUCCESS = 0x4000000, - TMRESUME = 0x8000000, - TMFAIL = 0x20000000, - TMONEPHASE = 0x40000000, + + OBLOOSELY = 0x10000, + OBTMJOIN = 0x200000, + OBTMSUSPEND = 0x2000000, + OBTMSUCCESS = 0x4000000, + OBTMRESUME = 0x8000000, + OBTMFAIL = 0x20000000, + OBTMONEPHASE = 0x40000000, // non-standard xa protocol, to denote temp table xa trans - TEMPTABLE = 0x100000000, + OBTEMPTABLE = 0x100000000, }; public: // 用于检查xa请求传入的flag @@ -126,30 +127,30 @@ public: static bool is_valid(const int64_t flag, const int64_t xa_req_type); // check the flag stored in inner table static bool is_valid_inner_flag(const int64_t flag); - static bool contain_tmreadonly(const int64_t flag) { return flag & TMREADONLY; } - static bool contain_tmserializable(const int64_t flag) { return flag & TMSERIALIZABLE; } + static bool contain_tmreadonly(const int64_t flag) { return flag & OBTMREADONLY; } + static bool contain_tmserializable(const int64_t flag) { return flag & OBTMSERIALIZABLE; } static bool is_tmnoflags(const int64_t flag, const int64_t xa_req_type); - static bool contain_loosely(const int64_t flag) { return flag & LOOSELY; } - static bool contain_tmjoin(const int64_t flag) { return flag & TMJOIN; } - static bool is_tmjoin(const int64_t flag) { return flag == TMJOIN; } - static bool contain_tmresume(const int64_t flag) { return flag & TMRESUME; } - static bool is_tmresume(const int64_t flag) { return flag == TMRESUME; } - static bool contain_tmsuccess(const int64_t flag) { return flag & TMSUCCESS; } - static bool contain_tmsuspend(const int64_t flag) { return flag & TMSUSPEND; } - static bool contain_tmonephase(const int64_t flag) { return flag & TMONEPHASE; } - static bool is_tmonephase(const int64_t flag) { return flag == TMONEPHASE; } - static bool contain_tmfail(const int64_t flag) { return flag & TMFAIL; } + static bool contain_loosely(const int64_t flag) { return flag & OBLOOSELY; } + static bool contain_tmjoin(const int64_t flag) { return flag & OBTMJOIN; } + static bool is_tmjoin(const int64_t flag) { return flag == OBTMJOIN; } + static bool contain_tmresume(const int64_t flag) { return flag & OBTMRESUME; } + static bool is_tmresume(const int64_t flag) { return flag == OBTMRESUME; } + static bool contain_tmsuccess(const int64_t flag) { return flag & OBTMSUCCESS; } + static bool contain_tmsuspend(const int64_t flag) { return flag & OBTMSUSPEND; } + static bool contain_tmonephase(const int64_t flag) { return flag & OBTMONEPHASE; } + static bool is_tmonephase(const int64_t flag) { return flag == OBTMONEPHASE; } + static bool contain_tmfail(const int64_t flag) { return flag & OBTMFAIL; } static int64_t add_end_flag(const int64_t flag, const int64_t end_flag) { int64_t ret = end_flag; if (contain_loosely(flag)) { - ret |= LOOSELY; + ret |= OBLOOSELY; } return ret; } static bool contain_temp_table(const int64_t flag) { - return flag & ObXAFlag::TEMPTABLE; + return flag & ObXAFlag::OBTEMPTABLE; } }; @@ -221,7 +222,7 @@ struct ObXABranchInfo const common::ObAddr &addr, const int64_t unrespond_msg_cnt, const int64_t last_hb_ts, - const int64_t end_flag = ObXAFlag::TMNOFLAGS); + const int64_t end_flag = ObXAFlag::OBTMNOFLAGS); TO_STRING_KV(K_(xid), K_(state), K_(timeout_seconds), K_(addr), K_(unrespond_msg_cnt), K_(last_hb_ts), K_(end_flag)); ObXATransID xid_; diff --git a/src/storage/tx/ob_xa_query.cpp b/src/storage/tx/ob_xa_query.cpp index d2f92c6f0..6be0376e9 100644 --- a/src/storage/tx/ob_xa_query.cpp +++ b/src/storage/tx/ob_xa_query.cpp @@ -593,7 +593,7 @@ int ObXAQueryOraImpl::convert_flag_(const int64_t xa_flag, { int ret = OB_SUCCESS; switch (xa_flag) { - case ObXAFlag::TMNOFLAGS: { + case ObXAFlag::OBTMNOFLAGS: { if (ObXAReqType::XA_START == xa_req_type) { oci_flag = OCI_TRANS_NEW; } else if (ObXAReqType::XA_COMMIT == xa_req_type) { @@ -603,7 +603,7 @@ int ObXAQueryOraImpl::convert_flag_(const int64_t xa_flag, } break; } - case ObXAFlag::TMSUCCESS: { + case ObXAFlag::OBTMSUCCESS: { if (ObXAReqType::XA_END == xa_req_type) { oci_flag = OCI_DEFAULT; } else { @@ -611,7 +611,7 @@ int ObXAQueryOraImpl::convert_flag_(const int64_t xa_flag, } break; } - case ObXAFlag::TMSERIALIZABLE: { + case ObXAFlag::OBTMSERIALIZABLE: { if (ObXAReqType::XA_START == xa_req_type) { oci_flag = OCI_TRANS_SERIALIZABLE; } else { diff --git a/src/storage/tx/ob_xa_service.cpp b/src/storage/tx/ob_xa_service.cpp index 44441c9fb..f5fb4db18 100644 --- a/src/storage/tx/ob_xa_service.cpp +++ b/src/storage/tx/ob_xa_service.cpp @@ -355,7 +355,7 @@ int ObXAService::insert_xa_lock(ObISQLClient &client, LOCK_FORMAT_ID, trans_id.get_id(), scheduler_ip_buf, GCTX.self_addr().get_port(), ObXATransState::ACTIVE, - (long)ObXAFlag::TMNOFLAGS))) { + (long)ObXAFlag::OBTMNOFLAGS))) { TRANS_LOG(WARN, "generate insert xa trans sql fail", KR(ret), K(exec_tenant_id), K(tenant_id), K(sql)); } else if (OB_FAIL(client.write(exec_tenant_id, sql.ptr(), affected_rows))) { @@ -600,7 +600,7 @@ int ObXAService::delete_xa_all_tightly_branch(const uint64_t tenant_id, OB_ALL_TENANT_GLOBAL_TRANSACTION_TNAME, tenant_id, (int)gtrid_len, gtrid_str, - (long)ObXAFlag::LOOSELY))) { + (long)ObXAFlag::OBLOOSELY))) { TRANS_LOG(WARN, "generate delete xa trans sql fail", K(ret), K(xid)); } else if (OB_FAIL(mysql_proxy->write(exec_tenant_id, sql.ptr(), affected_rows))) { TRANS_LOG(WARN, "execute delete xa trans sql fail", @@ -2713,7 +2713,7 @@ int ObXAService::update_coord(const uint64_t tenant_id, int64_t mask = 0; if (has_tx_level_temp_table) { - mask = ObXAFlag::TEMPTABLE; + mask = ObXAFlag::OBTEMPTABLE; } THIS_WORKER.set_timeout_ts(ObTimeUtility::current_time() + XA_INNER_TABLE_TIMEOUT); diff --git a/tools/deploy/copy.sh b/tools/deploy/copy.sh index e759ae559..58710ebce 100755 --- a/tools/deploy/copy.sh +++ b/tools/deploy/copy.sh @@ -34,10 +34,14 @@ then libtool --mode=install cp $BUILD_DIR/src/observer/observer $BIN_DIR/observer libtool --mode=install cp $SOURCE_DIR/src/share/inner_table/sys_package/*.sql $ADMIN_DIR - libtool --mode=install cp ./usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1 $LIB_DIR - libtool --mode=install cp ./usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1 $LIB_DIR/libclntsh.so - libtool --mode=install cp ./usr/lib/oracle/11.2/client64/lib/libnnz11.so $LIB_DIR - libtool --mode=install cp ./usr/lib/oracle/11.2/client64/lib/libociei.so $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1 $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libclntsh.so.12.1 $LIB_DIR/libclntsh.so + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libclntshcore.so.12.1 $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libnnz12.so $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libons.so $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libociei.so $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libmql1.so $LIB_DIR + libtool --mode=install cp ./usr/lib/oracle/12.2/client64/lib/libipc1.so $LIB_DIR libtool --mode=install cp $SOURCE_DIR/deps/3rd/usr/local/oceanbase/devtools/bin/llvm-symbolizer $TOOL_DIR/ diff --git a/tools/ob_error/src/CMakeLists.txt b/tools/ob_error/src/CMakeLists.txt index 2353d3121..08fe0f345 100644 --- a/tools/ob_error/src/CMakeLists.txt +++ b/tools/ob_error/src/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(ob_error ${SRC_LIST}) add_library(oberror SHARED ${SRC_LIST}) include_directories( + ${CMAKE_SOURCE_DIR}/ ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/deps/oblib/src )