[FEAT MERGE]support PL dblink oracle

This commit is contained in:
seuwebber 2023-08-21 03:40:30 +00:00 committed by ob-robot
parent cda81cde61
commit ee361e15fe
53 changed files with 3215 additions and 324 deletions

View File

@ -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" )

View File

@ -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

View File

@ -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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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<pl::ObUserDefinedType *> &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;

View File

@ -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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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)

View File

@ -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<typename T>
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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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<typename T>
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;
}
}
}
}

View File

@ -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 &param)
{
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 = &param.length_;
bind_[param.col_idx_].is_null = &param.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;
}

View File

@ -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 &param);
int64_t get_stmt_param_count() const { return param_count_; }
private:
ObMySQLPreparedStatement &stmt_;

View File

@ -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 &param)
{
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 = &param.length_;
bind_[param.col_idx_].is_null = &param.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;
}

View File

@ -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 &param);
private:
ObMySQLPreparedStatement &stmt_;
common::ObIAllocator &alloc_;

File diff suppressed because it is too large Load Diff

View File

@ -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 &param, \
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 &param, \
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 &param);
int bind_result(const ObBindParam &param);
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 *&param);
int get_bind_result_param_by_idx(const int64_t idx,
ObBindParam *&param);
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 &params,
const share::schema::ObRoutineInfo &routine_info,
const ObTimeZoneInfo *tz_info);
private:
int bind_proc_param(ObIAllocator &allocator,
ParamStore &params,
const share::schema::ObRoutineInfo &routine_info,
common::ObIArray<int64_t> &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 &params,
const share::schema::ObRoutineInfo &routine_info,
common::ObIArray<int64_t> &basic_out_param,
const ObTimeZoneInfo *tz_info);
int convert_proc_output_param_result(const ObTimeZoneInfo &tz_info,
const ObBindParam &bind_param,
ObObjParam &param,
const share::schema::ObRoutineInfo &routine_info,
ObIAllocator &allocator);
};
} //namespace sqlclient
}

View File

@ -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<pl::ObUserDefinedType *> &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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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;

View File

@ -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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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<pl::ObUserDefinedType *> &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);

View File

@ -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 {

View File

@ -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));

View File

@ -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";

View File

@ -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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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)
{

View File

@ -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 &params,
ObString &sql,
const share::schema::ObRoutineInfo &routine_info,
const common::ObIArray<const pl::ObUserDefinedType *> &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,

View File

@ -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)

View File

@ -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<const share::schema::ObIRoutineInfo *> &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<DblinkDriverProto>(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<int64_t>(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<const share::schema::ObIRoutineInfo *> &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<ObPLDbLinkInfo *>(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<ObPLDbLinkInfo *>(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<const ObRoutineInfo *>(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<int32_t>(OciDataType::OCI_SQLT_STR);
int32_t oci_sql_int = static_cast<int32_t>(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<int64_t>(full_name_copy.length() + 1), oci_sql_str);
BIND_BASIC_BY_POS(2, &context, static_cast<int64_t>(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<int64_t>(sizeof(int)), oci_sql_int);
if (FAILEDx(dblink_proxy->dblink_execute_proc(dblink_conn))) {
const DblinkDriverProto link_type = static_cast<DblinkDriverProto>(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<int64_t>(ObObjectType::PROCEDURE);
break;
case OracleObjectType::ORA_PACKAGE:
// package
object_type = static_cast<int64_t>(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<ObOciConnection *>(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<ObPLDbLinkInfo *>(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<ObPLDbLinkInfo *>(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
}
}

View File

@ -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<const share::schema::ObIRoutineInfo *> &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<const share::schema::ObIRoutineInfo *> &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<const ObPLDbLinkInfo *, 1> dblink_infos_;
#endif
};
}
}
#endif

View File

@ -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))) {

View File

@ -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,

View File

@ -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_))) {

View File

@ -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<uint64_t, sql::ObCacheObjGuard*> map_;
};

View File

@ -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<int32_t>(node->children_[1]->str_len_));
pkg_name.assign_ptr(access_node->children_[1]->str_value_,
static_cast<int32_t>(access_node->children_[1]->str_len_));
udt_name.assign_ptr(access_node->children_[2]->str_value_,
static_cast<int32_t>(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<int32_t>(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<ObRawExpr *> 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<const ObRoutineParam*>(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<const ObPLRoutineParam*>(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<ObObjAccessIdent> obj_access_idents;
ObArray<ObObjAccessIdx> access_idxs;
ObArray<ObObjAccessIdx> self_access_idxs;
ObArray<ObRawExpr *> 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<const ObRoutineInfo *>(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<ObObjAccessIdent> &obj_access_idents,
ObPLCompileUnitAST &func,
common::ObIArray<ObObjAccessIdx> &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<int32_t>(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<int32_t>(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<ObRawExpr*, int64_t> 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<ObRawExpr *> 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<int64_t>(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<sql::ObRawExpr *> &expr_params,
const ObIRoutineInfo *&routine_info)
{
int ret = OB_SUCCESS;
ObSEArray<const ObIRoutineInfo*, 8> 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<const share::schema::ObRoutineInfo*>(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<sql::ObRawExpr *> &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<const ObCollectionType *>(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<ObQualifiedName> &columns,
ObIArray<ObRawExpr*> &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<ObRawExpr*, 4> 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<uint64_t>(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<uint64_t>(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<const ObUserDefinedType *>(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<const ObUserDefinedType *>(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<const ObUserDefinedType *>(package_user_type)));
}
}
}

View File

@ -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<ObObjAccessIdx> &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<sql::ObRawExpr *> &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<sql::ObRawExpr *> &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<ObObjAccessIdent> &obj_access_idents,
ObPLCompileUnitAST &func);
int resolve_dblink_idents(const ParseNode &node,
common::ObIArray<ObObjAccessIdent> &obj_access_idents,
ObPLCompileUnitAST &func,
common::ObIArray<ObObjAccessIdx> &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);

View File

@ -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';

View File

@ -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<InOutParam> params_;
ObPLSEArray<int64_t> nocopy_params_;
common::ObString route_sql_;
uint64_t dblink_id_;
};
class ObPLInnerCallStmt : public ObPLStmt

View File

@ -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<const ObRoutineParam*>(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);

View File

@ -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()

View File

@ -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<ObPLCollAllocator *>(allocator_);
}
/*
*
* 1Collection内部的data域的ObObj数组sort域和key域的内存Collection自己的allocator分配allocator

View File

@ -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_; }

View File

@ -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();

View File

@ -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<ObRoutineParam*> &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<ObRoutineParam *, 64> 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

View File

@ -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) {

View File

@ -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()))) {

View File

@ -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 &params)
{
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 &params)
{
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<const pl::ObUserDefinedType *, 1> 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 &params,
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
}
}

View File

@ -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 &params);
static int spi_execute_dblink(ObExecContext &exec_ctx,
ObIAllocator &allocator,
const pl::ObPLDbLinkInfo *dblink_info,
const ObRoutineInfo *routine_info,
ParamStore &params);
static int spi_after_execute_dblink(ObSQLSessionInfo *session,
const ObRoutineInfo *routine_info,
ObIAllocator &allocator,
ParamStore &params,
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);

View File

@ -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<ObRawExpr*, 16> 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<int32_t>(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<int32_t>(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<int32_t>(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<int32_t>(sp_node->str_len_));
}
}
return ret;
}
}
}

View File

@ -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);

View File

@ -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);
};

View File

@ -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<const share::schema::ObIRoutineInfo *> &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 &params,
int ObResolverUtils::get_routine(pl::ObPLPackageGuard &package_guard,
ObResolverParams &params,
uint64_t tenant_id,
const ObString &current_database,
const ObString &db_name,
@ -1245,16 +1260,26 @@ int ObResolverUtils::get_routine(ObResolverParams &params,
const ObString &routine_name,
const share::schema::ObRoutineType routine_type,
const common::ObIArray<ObRawExpr *> &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<const ObRoutineInfo *>(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 &params,
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))) {

View File

@ -165,7 +165,8 @@ public:
const ObString &routine_name,
const share::schema::ObRoutineType routine_type,
common::ObIArray<const share::schema::ObIRoutineInfo *> &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<sql::ObRawExpr *> &expr_params,
const common::ObIArray<const share::schema::ObIRoutineInfo *> &routine_infos,
const share::schema::ObRoutineInfo *&routine_info);
static int get_routine(ObResolverParams &params,
static int get_routine(pl::ObPLPackageGuard &package_guard,
ObResolverParams &params,
uint64_t tenant_id,
const ObString &current_database,
const ObString &db_name,
@ -235,7 +237,9 @@ public:
const ObString &routine_name,
const share::schema::ObRoutineType routine_type,
const common::ObIArray<ObRawExpr *> &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 &current_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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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_;

View File

@ -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 {

View File

@ -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);

View File

@ -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/

View File

@ -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
)