Files
oceanbase/src/pl/ob_pl_package_manager.cpp

1509 lines
66 KiB
C++

/**
* 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 "pl/ob_pl_package_manager.h"
#include "pl/ob_pl.h"
#include "pl/ob_pl_package.h"
#include "pl/ob_pl_resolver.h"
#include "pl/ob_pl_compile.h"
#include "pl/ob_pl_stmt.h"
#include "pl/ob_pl_package_state.h"
#include "sql/session/ob_sql_session_info.h"
#include "sql/engine/ob_exec_context.h"
#include "sql/plan_cache/ob_cache_object_factory.h"
#include "sql/plan_cache/ob_plan_cache.h"
#include "sql/ob_sql_utils.h"
#include "observer/ob_server_struct.h"
#include "observer/ob_req_time_service.h"
#include "lib/file/file_directory_utils.h"
#include "pl/pl_cache/ob_pl_cache_mgr.h"
namespace oceanbase
{
using namespace common;
using namespace share::schema;
using namespace sql;
namespace pl
{
int ObPLPackageManager::read_package_sql(FILE* file, char* buf, int64_t buf_len, bool &eof)
{
int ret = OB_SUCCESS;
enum {S_LINE_START, S_NORMAL, S_COMMENT, S_TERMINATE} state = S_LINE_START;
if (OB_ISNULL(file)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("package sql file is null", K(ret));
} else if (OB_ISNULL(buf)) {
ret = OB_ERR_NULL_VALUE;
LOG_WARN("sql buffer is null", K(ret));
} else if (buf_len <= 0) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("buffer length is invalid", K(buf_len), K(ret));
} else {
char *p = buf;
char *p_start = p;
char *p_end = p + buf_len - 1;
int c;
// clear buffer
*p = '\0';
*p_end = '\0';
while (OB_SUCC(ret) && state != S_TERMINATE) {
if (EOF == (c = fgetc(file))) {
ret = OB_IO_ERROR;
} else {
if (p >= p_end) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("query is too long", K(buf), K(buf_len), K(ret));
} else {
switch (state) {
case S_LINE_START: {
// row start with '#' or '--' is comment
if (isspace(c)) {
// ignore space
state = S_LINE_START;
} else if ('#' == c) {
state = S_COMMENT;
} else if ('-' == c) {
c = fgetc(file);
if ('-' == c) {
state = S_COMMENT;
} else if (EOF == c) {
ret = OB_IO_ERROR;
} else {
*p++ = '-';
*p++ = static_cast<char>(c);
state = S_NORMAL;
}
} else {
*p++ = static_cast<char>(c);
state = S_NORMAL;
}
}
break;
case S_COMMENT: {
if (c == '\n') {
state = S_LINE_START;
}
}
break;
case S_NORMAL: {
/* if ('#' == c) {
state = S_COMMENT;
} else */ if ('/' == c) {
if ((p != p_start) && '/' == *(p - 1)) {
*(p - 1) = '\0';
state = S_TERMINATE;
} else {
*p++ = static_cast<char>(c);
state = S_NORMAL;
}
} else {
*p++ = static_cast<char>(c);
if ('\n' == c) {
state = S_LINE_START;
} else {
state = S_NORMAL;
}
}
}
break;
default: {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("parser package file with wrong state", K(state), K(ret));
}
break;
}
}
}
}
if (OB_FAIL(ret)) {
if (feof(file)) {
eof = true;
ret = OB_SUCCESS;
} else {
LOG_WARN("read package file error", K(errno), K(ret));
}
}
}
return ret;
}
int ObPLPackageManager::read_and_exec_package_sql(
ObMySQLProxy &sql_proxy, const char* package_full_path, ObCompatibilityMode compa_mode)
{
int ret = OB_SUCCESS;
if (!sql_proxy.is_inited() || !sql_proxy.is_active()) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("sql_proxy not inited or not active", "sql_proxy inited",
sql_proxy.is_inited(), "sql_proxy active", sql_proxy.is_active(), K(ret));
} else {
FILE* file = NULL;
int64_t affected_rows = 0;
if (access(package_full_path, F_OK) != 0) {
LOG_INFO("package sql file not exists", K(package_full_path), K(ret));
} else if (OB_ISNULL(file = fopen(package_full_path, "rb"))) {
ret = OB_IO_ERROR;
LOG_WARN("package sql file open failed", K(package_full_path), K(ret));
} else {
// system tenant will run with mysql compatibility mode
// but we need to create system packages with oralce compatibility
// here hack to oracle mode
bool eof = false;
SMART_VAR(char[OB_MAX_SQL_LENGTH], sql_buf) {
while (OB_SUCC(ret) && !eof) {
if (OB_FAIL(read_package_sql(file, sql_buf, OB_MAX_SQL_LENGTH, eof))) {
LOG_WARN("fail to read package sql file", K(ret));
} else if (strlen(sql_buf) != 0
&& OB_FAIL(sql_proxy.write(OB_SYS_TENANT_ID,
sql_buf,
affected_rows,
static_cast<int64_t>(compa_mode)))) {
LOG_WARN("fail to exec package sql", K(sql_buf), K(ret));
} else if (affected_rows != 0) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("affected_rows expected to be zero", K(affected_rows), K(ret));
} else {
OZ (ObSPIService::force_refresh_schema(OB_SYS_TENANT_ID));
}
}
}
fclose(file);
}
}
return ret;
}
int ObPLPackageManager::load_sys_package(
ObMySQLProxy &sql_proxy, const char *package_spec_name, const char *package_body_name, ObCompatibilityMode compa_mode)
{
int ret = OB_SUCCESS;
const int64_t begin_time = ObTimeUtility::current_time();
LOG_INFO("load sys package begin",
"package name", package_spec_name, "package body name", package_body_name);
if (OB_FAIL(read_and_exec_package_sql(sql_proxy, package_spec_name, compa_mode))) {
LOG_WARN("fail to read and exec package header sql", K(package_spec_name), K(ret));
} else if (OB_FAIL(read_and_exec_package_sql(sql_proxy, package_body_name, compa_mode))) {
LOG_WARN("fail to read and exec package body sql", K(package_body_name), K(ret));
}
const int64_t now = ObTimeUtility::current_time();
LOG_INFO("load sys package finish", "total_time_used", now - begin_time);
return ret;
}
static const char* sys_package_dir = "admin";
static ObSysPackageFile oracle_sys_package_file_table[] = {
#ifdef OB_BUILD_ORACLE_PL
{"dbms_standard", "dbms_standard.sql", "dbms_standard_body.sql"},
{"dbms_output", "dbms_output.sql", "dbms_output_body.sql"},
{"dbms_metadata", "dbms_metadata.sql", "dbms_metadata_body.sql"},
{"dbms_spm", "dbms_spm.sql", "dbms_spm_body.sql"},
{"utl_raw", "utl_raw.sql", "utl_raw_body.sql"},
{"dbms_lob", "dbms_lob.sql", "dbms_lob_body.sql"},
{"sa_components", "sa_components.sql", "sa_components_body.sql"},
{"sa_label_admin", "sa_label_admin.sql", "sa_label_admin_body.sql"},
{"sa_policy_admin", "sa_policy_admin.sql", "sa_policy_admin_body.sql"},
{"sa_session", "sa_session.sql", "sa_session_body.sql"},
{"sa_sysdba", "sa_sysdba.sql", "sa_sysdba_body.sql"},
{"sa_user_admin", "sa_user_admin.sql", "sa_user_admin_body.sql"},
{"utl_i18n", "utl_i18n.sql", "utl_i18n_body.sql"},
{"dbms_crypto", "dbms_crypto.sql","dbms_crypto_body.sql"},
{"dbms_random", "dbms_random.sql", "dbms_random_body.sql"},
{"dbms_debug", "dbms_debug.sql", "dbms_debug_body.sql"},
{"utl_inaddr", "utl_inaddr.sql", "utl_inaddr_body.sql"},
{"utl_encode", "dbms_utl_encode.sql", "dbms_utl_encode_body.sql"},
{"dbms_warning", "dbms_warning.sql", "dbms_warning_body.sql"},
{"dbms_errlog", "dbms_errlog.sql", "dbms_errlog_body.sql"},
{"dbms_lock", "dbms_lock.sql", "dbms_lock_body.sql"},
{"dbms_sql", "dbms_sql.sql", "dbms_sql_body.sql"},
{"dbms_xa", "dbms_xa.sql", "dbms_xa_body.sql"},
{"dbms_resource_manager", "dbms_resource_manager.sql", "dbms_resource_manager_body.sql"},
{"dbms_utility", "dbms_utility.sql", "dbms_utility_body.sql"},
{"odciconst", "odciconst.sql", "odciconst_body.sql"},
{"dbms_stats", "dbms_stats.sql", "dbms_stats_body.sql"},
{"dbms_any", "dbms_any.sql", "dbms_any_body.sql"},
{"xml_type", "xml_type.sql", "xml_type_body.sql"},
{"dbms_crypto", "dbms_crypto.sql", "dbms_crypto_body.sql"},
{"dbms_ijob", "dbms_ijob.sql", "dbms_ijob_body.sql"},
{"dbms_job", "dbms_job.sql", "dbms_job_body.sql"},
{"dbms_ischeduler", "dbms_ischeduler.sql", "dbms_ischeduler_body.sql"},
{"dbms_scheduler", "dbms_scheduler.sql", "dbms_scheduler_body.sql"},
{"catodci", "catodci.sql", "catodci_body.sql"},
{"dbms_describe", "dbms_describe.sql", "dbms_describe_body.sql"},
{"utl_file", "utl_file.sql", "utl_file_body.sql"},
{"dbms_plan_cache", "dbms_plancache.sql", "dbms_plancache_body.sql"},
{"dbms_sys_error", "dbms_sys_error.sql", "dbms_sys_error_body.sql"},
{"dbms_preprocessor", "dbms_preprocessor.sql", "dbms_preprocessor_body.sql"},
{"dbms_audit_mgmt", "dbms_audit_mgmt.sql", "dbms_audit_mgmt_body.sql"},
{"dbms_application", "dbms_application.sql", "dbms_application_body.sql"},
{"dbms_session", "dbms_session.sql", "dbms_session_body.sql"},
{"dbms_monitor", "dbms_monitor.sql", "dbms_monitor_body.sql"},
{"dbms_xplan", "dbms_xplan.sql", "dbms_xplan_body.sql"},
{"dbms_workload_repository", "dbms_workload_repository.sql", "dbms_workload_repository_body.sql"},
{"dbms_ash_internal", "dbms_ash_internal.sql", "dbms_ash_internal_body.sql"},
{"dbms_rls", "dbms_rls.sql", "dbms_rls_body.sql"},
{"dbms_udr", "dbms_udr.sql", "dbms_udr_body.sql"},
{"json_element_t", "json_element_type.sql", "json_element_type_body.sql"},
{"json_object_t", "json_object_type.sql", "json_object_type_body.sql"},
#endif
};
static ObSysPackageFile mysql_sys_package_file_table[] = {
{"dbms_stats", "dbms_stats_mysql.sql", "dbms_stats_body_mysql.sql"},
{"dbms_scheduler", "dbms_scheduler_mysql.sql", "dbms_scheduler_mysql_body.sql"},
{"dbms_application", "dbms_application_mysql.sql", "dbms_application_body_mysql.sql"},
{"dbms_session", "dbms_session_mysql.sql", "dbms_session_body_mysql.sql"},
{"dbms_monitor", "dbms_monitor_mysql.sql", "dbms_monitor_body_mysql.sql"},
{"dbms_resource_manager", "dbms_resource_manager_mysql.sql", "dbms_resource_manager_body_mysql.sql"},
#ifdef OB_BUILD_ORACLE_PL
{"dbms_xplan", "dbms_xplan_mysql.sql", "dbms_xplan_mysql_body.sql"},
{"dbms_spm", "dbms_spm_mysql.sql", "dbms_spm_body_mysql.sql"},
#endif
{"dbms_udr", "dbms_udr_mysql.sql", "dbms_udr_body_mysql.sql"},
{"dbms_workload_repository", "dbms_workload_repository_mysql.sql", "dbms_workload_repository_body_mysql.sql"}
};
int ObPLPackageManager::load_sys_package(ObMySQLProxy &sql_proxy, ObString &package_name, ObCompatibilityMode compa_mode)
{
int ret = OB_SUCCESS;
char package_spec_full_path[MAX_PATH_SIZE] = {};
char package_body_full_path[MAX_PATH_SIZE] = {};
bool dir_exists = false;
bool package_exists = false;
if (OB_FAIL(FileDirectoryUtils::is_exists(sys_package_dir, dir_exists))) {
LOG_WARN("check sys package dir whether exist failed", K(ret), K(sys_package_dir));
} else if (!dir_exists) {
ret = OB_ENTRY_NOT_EXIST;
LOG_WARN("sys package dir not exist", K(ret), K(sys_package_dir));
}
if (ObCompatibilityMode::ORACLE_MODE == compa_mode) {
int sys_package_count = ARRAYSIZEOF(oracle_sys_package_file_table);
for (int64_t i = 0; OB_SUCC(ret) && i < sys_package_count; ++i) {
if (0 == package_name.case_compare(ObString(oracle_sys_package_file_table[i].package_name))) {
const char *package_spec_name = oracle_sys_package_file_table[i].package_spec_file_name;
const char *package_body_name = oracle_sys_package_file_table[i].package_body_file_name;
OZ (databuff_printf(
package_spec_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_spec_name));
OZ (databuff_printf(
package_body_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_body_name));
OX (package_exists = true);
break;
}
}
} else if (ObCompatibilityMode::MYSQL_MODE == compa_mode) {
int sys_package_count = ARRAYSIZEOF(mysql_sys_package_file_table);
for (int64_t i = 0; OB_SUCC(ret) && i < sys_package_count; ++i) {
if (0 == package_name.case_compare(ObString(mysql_sys_package_file_table[i].package_name))) {
const char *package_spec_name = mysql_sys_package_file_table[i].package_spec_file_name;
const char *package_body_name = mysql_sys_package_file_table[i].package_body_file_name;
OZ (databuff_printf(
package_spec_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_spec_name));
OZ (databuff_printf(
package_body_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_body_name));
OX (package_exists = true);
break;
}
}
}
if (OB_SUCC(ret) && !package_exists) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package not exists", K(ret), K(package_name));
LOG_USER_ERROR(OB_ERR_PACKAGE_DOSE_NOT_EXIST,
"PACKAGE",
ObString("oceanbase").length(), ObString("oceanbase").ptr(),
package_name.length(), package_name.ptr());
}
OZ (load_sys_package(sql_proxy, package_spec_full_path, package_body_full_path, compa_mode));
return ret;
}
int ObPLPackageManager::load_all_common_sys_package(ObMySQLProxy &sql_proxy,
const ObSysPackageFile *package_file,
int sys_package_count,
ObCompatibilityMode compa_mode)
{
int ret = OB_SUCCESS;
char package_spec_full_path[MAX_PATH_SIZE] = {};
char package_body_full_path[MAX_PATH_SIZE] = {};
CK (OB_NOT_NULL(package_file));
LOG_INFO("load all sys package begin", "sys package total count", sys_package_count);
for (int i = 0; OB_SUCC(ret) && i < sys_package_count; ++i) {
const char *package_spec_name = package_file[i].package_spec_file_name;
const char *package_body_name = package_file[i].package_body_file_name;
OZ (databuff_printf(
package_spec_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_spec_name));
OZ (databuff_printf(
package_body_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, package_body_name));
if (OB_SUCC(ret)) {
LOG_INFO("load sys package begin", K(package_spec_name));
if (OB_FAIL(load_sys_package(sql_proxy, package_spec_full_path, package_body_full_path, compa_mode))) {
LOG_WARN("load sys package failed",
K(package_spec_full_path), K(package_body_full_path), K(compa_mode), K(ret));
} else {
LOG_INFO("load sys package success", K(ret), K(package_spec_name));
}
}
}
return ret;
}
int ObPLPackageManager::load_all_common_sys_package(ObMySQLProxy &sql_proxy, ObCompatibilityMode need_compa_mode)
{
int ret = OB_SUCCESS;
bool exist = false;
if (OB_FAIL(FileDirectoryUtils::is_exists(sys_package_dir, exist))) {
LOG_WARN("check sys package dir whether exist failed", K(sys_package_dir), K(ret));
} else if (!exist) {
LOG_INFO("sys package dir not exist", K(sys_package_dir));
} else {
if (need_compa_mode == ObCompatibilityMode::OCEANBASE_MODE) {
OZ (load_all_common_sys_package(sql_proxy, oracle_sys_package_file_table,
ARRAYSIZEOF(oracle_sys_package_file_table), ObCompatibilityMode::ORACLE_MODE));
OZ (load_all_common_sys_package(sql_proxy, mysql_sys_package_file_table,
ARRAYSIZEOF(mysql_sys_package_file_table), ObCompatibilityMode::MYSQL_MODE));
} else if (need_compa_mode == ObCompatibilityMode::ORACLE_MODE) {
OZ (load_all_common_sys_package(sql_proxy, oracle_sys_package_file_table,
ARRAYSIZEOF(oracle_sys_package_file_table), ObCompatibilityMode::ORACLE_MODE));
} else if (need_compa_mode == ObCompatibilityMode::MYSQL_MODE) {
OZ (load_all_common_sys_package(sql_proxy, mysql_sys_package_file_table,
ARRAYSIZEOF(mysql_sys_package_file_table), ObCompatibilityMode::MYSQL_MODE));
}
}
if (OB_SUCC(ret)) {
LOG_INFO("load all common sys package success!");
} else {
LOG_INFO("load all common sys package failed!");
}
return ret;
}
int ObPLPackageManager::load_all_special_sys_package(ObMySQLProxy &sql_proxy)
{
int ret = OB_SUCCESS;
bool exist = false;
if (OB_FAIL(FileDirectoryUtils::is_exists(sys_package_dir, exist))) {
LOG_WARN("check sys package dir whether exist failed", K(sys_package_dir), K(ret));
} else if (!exist) {
LOG_INFO("sys package dir not exist", K(sys_package_dir));
} else {
// for now! we only have one special system package "__DBMS_UPGRADE"
char package_spec_full_path[MAX_PATH_SIZE] = {};
char package_body_full_path[MAX_PATH_SIZE] = {};
#ifdef OB_BUILD_ORACLE_PL
OZ (databuff_printf(
package_spec_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, "__dbms_upgrade.sql"));
OZ (databuff_printf(
package_body_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, "__dbms_upgrade_body.sql"));
OZ (load_sys_package(sql_proxy, package_spec_full_path, package_body_full_path, ObCompatibilityMode::ORACLE_MODE));
#endif
memset(package_spec_full_path, 0, sizeof(package_spec_full_path));
memset(package_body_full_path, 0, sizeof(package_body_full_path));
OZ (databuff_printf(
package_spec_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, "__dbms_upgrade_mysql.sql"));
OZ (databuff_printf(
package_body_full_path, MAX_PATH_SIZE, "%s/%s", sys_package_dir, "__dbms_upgrade_body_mysql.sql"));
OZ (load_sys_package(sql_proxy, package_spec_full_path, package_body_full_path, ObCompatibilityMode::MYSQL_MODE));
}
return ret;
}
int ObPLPackageManager::load_all_sys_package(ObMySQLProxy &sql_proxy)
{
int ret = OB_SUCCESS;
OZ (load_all_common_sys_package(sql_proxy, ObCompatibilityMode::OCEANBASE_MODE));
OZ (load_all_special_sys_package(sql_proxy));
if (OB_SUCC(ret)) {
LOG_INFO("load all sys package success!", K(ret));
} else {
LOG_INFO("load all sys package failed!", K(ret));
}
return ret;
}
int ObPLPackageManager::get_package_var(const ObPLResolveCtx &resolve_ctx, uint64_t package_id,
const ObString &var_name, const ObPLVar *&var, int64_t &var_idx)
{
int ret = OB_SUCCESS;
var = NULL;
var_idx = OB_INVALID_INDEX;
if (OB_INVALID_ID == package_id || var_name.empty()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package id or var name invalid", K(package_id), K(var_name), K(ret));
} else {
ObPLPackage *package_spec = NULL;
if (OB_FAIL(get_cached_package_spec(resolve_ctx, package_id, package_spec))) {
LOG_WARN("get cached package spec failed", K(package_id), K(ret));
} else if (OB_ISNULL(package_spec)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package not exist", K(package_id), K(ret));
} else {
if (OB_FAIL(package_spec->get_var(var_name, var, var_idx))) {
LOG_WARN("package get var failed", K(package_id), K(var_name), K(ret));
}
}
}
return ret;
}
int ObPLPackageManager::get_package_var(const ObPLResolveCtx &resolve_ctx, uint64_t package_id,
int64_t var_idx, const ObPLVar *&var)
{
int ret = OB_SUCCESS;
var = NULL;
if (OB_INVALID_ID == package_id || OB_INVALID_INDEX == var_idx) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package id or var index invalid", K(package_id), K(var_idx), K(ret));
} else {
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
if (OB_FAIL(get_cached_package(resolve_ctx, package_id, package_spec, package_body, true))) {
LOG_WARN("get cached package failed", K(package_id), K(ret));
} else if (OB_ISNULL(package_spec)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec not exist", K(package_id), K(ret));
} else {
const ObPLPackage *tmp_package = NULL;
if (package_id == package_spec->get_id()) {
tmp_package = package_spec;
} else if (!OB_ISNULL(package_body) && package_id == package_body->get_id()) {
tmp_package = package_body;
} else {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package body not exist", K(package_id), K(ret));
LOG_USER_ERROR(OB_ERR_PACKAGE_DOSE_NOT_EXIST, "PACKAGE BODY",
package_spec->get_db_name().length(), package_spec->get_db_name().ptr(),
package_spec->get_name().length(), package_spec->get_name().ptr());
}
if (OB_SUCC(ret)) {
if (OB_FAIL(tmp_package->get_var(var_idx, var))) {
LOG_WARN("package get var failed", K(ret));
} else if (OB_ISNULL(var)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package var not found", K(package_id), K(var_idx), K(ret));
} else if (!var->is_readonly() && OB_ISNULL(package_body)) {// 对于非constant值, 需要保证body的合法性
OZ (get_cached_package(resolve_ctx, package_id, package_spec, package_body, false));
}
}
}
}
return ret;
}
int ObPLPackageManager::get_package_type(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
const ObString &type_name,
const ObUserDefinedType *&user_type,
bool log_user_error)
{
int ret = OB_SUCCESS;
user_type = NULL;
if (OB_INVALID_ID == package_id || type_name.empty()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package id or type name invalid", K(package_id), K(type_name), K(ret));
} else {
observer::ObReqTimeGuard req_timeinfo_guard;
ObPLPackage *package_spec = NULL;
if (OB_FAIL(get_cached_package_spec(resolve_ctx, package_id, package_spec))) {
LOG_WARN("get cached package failed", K(ret));
} else if (OB_ISNULL(package_spec)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec not exist", K(package_id), K(ret));
} else {
if (OB_FAIL(package_spec->get_type(type_name, user_type))) {
LOG_WARN("package get type failed", K(package_id), K(type_name), K(ret));
} else if (OB_ISNULL(user_type)) {
ret = OB_ERR_SP_UNDECLARED_TYPE;
LOG_WARN("package type not found", K(package_id), K(type_name), K(ret));
if (log_user_error) {
LOG_USER_ERROR(OB_ERR_SP_UNDECLARED_TYPE, type_name.length(), type_name.ptr());
} else {}
} else {}
}
}
return ret;
}
int ObPLPackageManager::get_package_type(const ObPLResolveCtx &resolve_ctx, uint64_t package_id,
uint64_t type_id, const ObUserDefinedType *&user_type)
{
int ret = OB_SUCCESS;
user_type = NULL;
if (OB_INVALID_ID == package_id || OB_INVALID_INDEX == type_id) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package id or type index invalid", K(package_id), K(type_id), K(ret));
} else {
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
if (OB_FAIL(get_cached_package(resolve_ctx, package_id, package_spec, package_body, true))) {
LOG_WARN("get cached package failed", K(ret));
} else if (OB_ISNULL(package_spec)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec not exist", K(package_id), K(ret));
} else {
const ObPLPackage *tmp_package = NULL;
if (package_id == package_spec->get_id()) {
tmp_package = package_spec;
} else if (OB_NOT_NULL(package_body) && package_id == package_body->get_id()) {
tmp_package = package_body;
} else {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package body not exist", K(package_id), K(ret));
LOG_USER_ERROR(OB_ERR_PACKAGE_DOSE_NOT_EXIST, "PACKAGE BODY",
package_spec->get_db_name().length(), package_spec->get_db_name().ptr(),
package_spec->get_name().length(), package_spec->get_name().ptr());
}
if (OB_SUCC(ret)) {
if (OB_FAIL(tmp_package->get_type(type_id, user_type))) {
LOG_WARN("get package type failed", K(ret));
} else if (OB_ISNULL(user_type)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package type not found", K(ret));
} else {}
}
}
}
return ret;
}
int ObPLPackageManager::get_package_expr(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
int64_t expr_idx,
ObSqlExpression *&expr)
{
int ret = OB_SUCCESS;
if (OB_INVALID_ID == package_id || OB_INVALID_ID == expr_idx) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package id or expr idx invalid", K(ret), K(package_id), K(expr_idx));
} else {
observer::ObReqTimeGuard req_timeinfo_guard;
ObPLPackage *package_spec = NULL;
if (OB_FAIL(get_cached_package_spec(resolve_ctx, package_id, package_spec))) {
LOG_WARN("get cached package failed", K(ret));
} else if (OB_ISNULL(package_spec)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec not exist", K(package_id), K(ret));
} else if (OB_ISNULL(expr = package_spec->get_default_expr(expr_idx))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package expr not exist",
K(ret), K(expr_idx), K(package_id), K(package_spec->get_default_exprs().count()));
}
}
return ret;
}
int ObPLPackageManager::get_package_cursor(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
int64_t cursor_id,
const ObPLCursor *&cursor)
{
int ret = OB_SUCCESS;
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
ObPLPackage *tmp_package = NULL;
cursor = NULL;
CK (package_id != OB_INVALID_ID);
CK (cursor_id != OB_INVALID_INDEX);
OZ (get_cached_package(resolve_ctx, package_id, package_spec, package_body));
OX (tmp_package = package_spec != NULL && package_spec->get_id() == package_id
? package_spec
: package_body != NULL && package_body->get_id() == package_id
? package_body : NULL);
if (OB_SUCC(ret) && OB_ISNULL(tmp_package)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec does not exist", K(ret), K(package_id));
}
OZ (tmp_package->get_cursor(cursor_id, cursor));
return ret;
}
int ObPLPackageManager::get_package_cursor(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
const ObString &cursor_name,
const ObPLCursor *&cursor,
int64_t &cursor_idx)
{
int ret = OB_SUCCESS;
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
ObPLPackage *tmp_package = NULL;
cursor = NULL;
cursor_idx = OB_INVALID_INDEX;
CK (package_id != OB_INVALID_ID);
CK (!cursor_name.empty());
OZ (get_cached_package(resolve_ctx, package_id, package_spec, package_body));
OX (tmp_package = package_spec != NULL && package_spec->get_id() == package_id
? package_spec
: package_body != NULL && package_body->get_id() == package_id
? package_body : NULL);
if (OB_SUCC(ret) && OB_ISNULL(tmp_package)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec does not exist", K(ret), K(package_id));
}
OZ (tmp_package->get_cursor(cursor_name, cursor, cursor_idx));
if (OB_FAIL(ret) || OB_ISNULL(cursor)) {
} else if (ObPLCursor::DUP_DECL == cursor->get_state()) {
ret = OB_ERR_SP_DUP_CURSOR;
LOG_WARN("too many declarations of cursor match this call",
K(ret), K(cursor_name), K(cursor_idx));
} else if (ObPLCursor::DECLARED == cursor->get_state()) {
CK (tmp_package != package_body);
CK (OB_NOT_NULL(package_body));
OZ (package_body->get_cursor(
cursor->get_package_id(), cursor->get_routine_id(), cursor->get_index(), cursor));
}
return ret;
}
int ObPLPackageManager::get_package_condition(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
const ObString &condition_name,
const ObPLCondition *&value)
{
int ret = OB_SUCCESS;
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
ObPLPackage *tmp_package = NULL;
value = NULL;
CK (package_id != OB_INVALID_ID);
CK (!condition_name.empty());
OZ (get_cached_package(resolve_ctx, package_id, package_spec, package_body, true));
OX (tmp_package = (package_spec != NULL && package_spec->get_id() == package_id) ? package_spec :
(package_body != NULL && package_body->get_id() == package_id) ? package_body :
NULL);
if (OB_SUCC(ret) && OB_ISNULL(tmp_package)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec does not exist", K(ret), K(package_id));
}
CK (OB_NOT_NULL(tmp_package));
OZ (tmp_package->get_condition(condition_name, value));
return ret;
}
int ObPLPackageManager::get_package_routine(const ObPLResolveCtx &ctx,
sql::ObExecContext &exec_ctx,
uint64_t package_id,
int64_t routine_idx,
ObPLFunction *&routine)
{
int ret = OB_SUCCESS;
routine = NULL;
bool is_overflow = false;
if (OB_FAIL(check_stack_overflow(is_overflow))) {
LOG_WARN("failed to check stack overflow", K(ret));
} else if (is_overflow) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("too deep recusive", K(ret));
}
CK (OB_LIKELY(OB_INVALID_ID != package_id));
CK (OB_LIKELY(OB_INVALID_INDEX != routine_idx));
if (OB_SUCC(ret)) {
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
OZ (get_cached_package(ctx, package_id, package_spec, package_body));
CK (OB_NOT_NULL(package_spec));
if (OB_SUCC(ret) && OB_ISNULL(package_body)){
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_USER_ERROR(OB_ERR_PACKAGE_DOSE_NOT_EXIST, "PACKAGE BODY",
package_spec->get_db_name().length(), package_spec->get_db_name().ptr(),
package_spec->get_name().length(), package_spec->get_name().ptr());
}
OZ (package_body->get_routine(routine_idx, routine));
if (OB_SUCC(ret) && OB_ISNULL(routine)) {
ret = OB_ERR_SP_DOES_NOT_EXIST;
LOG_WARN("can not found package routine in package body", K(ret), K(routine_idx), K(routine));
} else {
ObPLPackageState *dummy_state = NULL;
if (OB_SUCC(ret) && OB_NOT_NULL(package_body->get_init_routine())) {
// call一个pacakge 函数的时候,去执行package的init 函数
OZ (get_package_state(ctx, exec_ctx, package_id, dummy_state));
}
}
}
return ret;
}
int ObPLPackageManager::get_package_var_val(const ObPLResolveCtx &resolve_ctx,
sql::ObExecContext &exec_ctx,
uint64_t package_id,
int64_t spec_version,
int64_t body_version,
int64_t var_idx,
ObObj &var_val)
{
int ret = OB_SUCCESS;
const ObPLVar *var = NULL;
ObPLPackageState *package_state = NULL;
ObPackageStateVersion version(spec_version, body_version);
CK (package_id != OB_INVALID_ID);
CK (var_idx != OB_INVALID_INDEX);
OZ (get_package_item_state(
resolve_ctx.session_info_, package_id, version, package_state));
if (OB_SUCC(ret) && OB_ISNULL(package_state)) {
OZ (get_package_var(resolve_ctx, package_id, var_idx, var),
K(package_id), K(var_idx));
CK (OB_NOT_NULL(var));
OZ (get_package_state(
resolve_ctx, exec_ctx, package_id, package_state, var->is_readonly()),
K(package_id), K(var_idx), K(var->is_readonly()));
}
OZ (package_state->get_package_var_val(var_idx, var_val),
K(var_idx));
return ret;
}
int ObPLPackageManager::set_package_var_val(const ObPLResolveCtx &resolve_ctx,
sql::ObExecContext &exec_ctx,
uint64_t package_id,
int64_t var_idx,
const ObObj &var_val,
bool need_deserialize,
bool from_proxy)
{
int ret = OB_SUCCESS;
ObPLPackageState *package_state = NULL;
ObObj old_var_val;
ObObj new_var_val = var_val;
const ObPLVar *var = NULL;
CK (package_id != OB_INVALID_ID);
CK (var_idx != OB_INVALID_INDEX);
OZ (get_package_state(resolve_ctx, exec_ctx, package_id, package_state),
K(package_id), K(var_idx), K(var_val));
OZ (package_state->get_package_var_val(var_idx, old_var_val), K(package_id), K(var_idx));
OZ (get_package_var(resolve_ctx, package_id, var_idx, var), K(package_id), K(var_idx));
OV (OB_NOT_NULL(var), OB_ERR_UNEXPECTED, K(package_id), K(var_idx));
if (need_deserialize) {
OZ (var->get_type().init_session_var(resolve_ctx,
var->get_type().is_cursor_type() ?
package_state->get_pkg_cursor_allocator()
: package_state->get_pkg_allocator(),
exec_ctx,
NULL,
false,
new_var_val), K(package_id), K(var_idx), K(var_val));
if (OB_FAIL(ret)) {
} else if (var->get_type().is_cursor_type()) {
OV (var_val.is_tinyint() || var_val.is_number(), OB_ERR_UNEXPECTED, K(var_val));
if (OB_SUCC(ret)
&& (var_val.is_tinyint() ? var_val.get_bool() : !var_val.is_zero_number())) {
if (from_proxy) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("can not sync package open cursor from proxy,"
"need route current sql to orignal server", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "sync package open cursor from proxy");
} else {
ObPLCursorInfo *cursor = reinterpret_cast<ObPLCursorInfo *>(new_var_val.get_ext());
CK (OB_NOT_NULL(cursor));
OX (cursor->set_sync_cursor());
}
}
} else if (var->get_type().is_opaque_type()) {
if (var_val.is_null()) {
ret = OB_NOT_SUPPORTED;
LOG_WARN("can not sync package opaque type", K(ret));
LOG_USER_ERROR(OB_NOT_SUPPORTED, "sync package opaque type");
}
} else {
OZ (var->get_type().deserialize(resolve_ctx,
var->get_type().is_cursor_type() ?
package_state->get_pkg_cursor_allocator()
: package_state->get_pkg_allocator(),
var_val.get_hex_string().ptr(),
var_val.get_hex_string().length(),
new_var_val), K(package_id), K(var_idx), K(var_val));
}
LOG_DEBUG("deserialize package var", K(package_id), K(var_idx), K(var_val), K(new_var_val));
}
if (OB_SUCC(ret) && var->is_not_null() && new_var_val.is_null()) {
ret = OB_ERR_NUMERIC_OR_VALUE_ERROR;
LOG_WARN("not null check violated", K(var->is_not_null()), K(var_val.is_null()), K(ret));
}
OZ (package_state->set_package_var_val(var_idx, new_var_val, !need_deserialize));
if (OB_NOT_NULL(var) && var->get_type().is_cursor_type() && !var->get_type().is_cursor_var()) {
// package ref cursor variable, refrence outside, do not destruct it.
} else if (OB_FAIL(ret)) {
OZ (ObUserDefinedType::destruct_obj(new_var_val, &(resolve_ctx.session_info_)));
} else {
OZ (ObUserDefinedType::destruct_obj(old_var_val, &(resolve_ctx.session_info_)));
}
if (!need_deserialize) {
OZ (package_state->update_changed_vars(var_idx));
}
return ret;
}
int ObPLPackageManager::load_package_spec(const ObPLResolveCtx &resolve_ctx,
const ObPackageInfo &package_spec_info,
ObPLPackage *&package_spec)
{
int ret = OB_SUCCESS;
package_spec = NULL;
const uint64_t tenant_id = package_spec_info.get_tenant_id();
uint64_t db_id = package_spec_info.get_database_id();
uint64_t package_id = package_spec_info.get_package_id();
ObPLBlockNS *null_parent_ns = NULL;
uint64_t effective_tenant_id = resolve_ctx.session_info_.get_effective_tenant_id();
HEAP_VAR(ObPLPackageAST, package_spec_ast, resolve_ctx.allocator_) {
const ObDatabaseSchema *db_schema = NULL;
ObPLCompiler compiler(resolve_ctx.allocator_,
resolve_ctx.session_info_,
resolve_ctx.schema_guard_,
resolve_ctx.package_guard_,
resolve_ctx.sql_proxy_);
OZ (resolve_ctx.schema_guard_.get_database_schema(tenant_id, db_id, db_schema));
CK (OB_NOT_NULL(db_schema));
OZ (package_spec_ast.init(db_schema->get_database_name_str(),
package_spec_info.get_package_name(),
PL_PACKAGE_SPEC,
package_spec_info.get_database_id(),
package_id,
package_spec_info.get_schema_version(),
NULL));
// generate cacheobj_guard to protect package and package will be destoried by map's destructor
ObCacheObjGuard* cacheobj_guard = NULL;
void* buf = NULL;
if (OB_ISNULL(buf = resolve_ctx.package_guard_.alloc_.alloc(sizeof(ObCacheObjGuard)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory.", K(ret));
} else if (FALSE_IT(cacheobj_guard = new (buf)ObCacheObjGuard(PACKAGE_SPEC_HANDLE))) {
// do nothing
} else {
OZ (ObCacheObjectFactory::alloc(*cacheobj_guard, ObLibCacheNameSpace::NS_PKG,
effective_tenant_id));
OX (package_spec = static_cast<ObPLPackage*>(cacheobj_guard->get_cache_obj()));
CK (OB_NOT_NULL(package_spec));
OZ (package_spec->init(package_spec_ast));
OZ (compiler.compile_package(package_spec_info,
null_parent_ns,
package_spec_ast,
*package_spec));
if (OB_SUCC(ret)) {
if (package_spec->get_can_cached()
&& OB_FAIL(add_package_to_plan_cache(resolve_ctx, package_spec))) {
LOG_WARN("failed to add package spec to cached", K(ret));
ret = OB_SUCCESS; // cache add failed, need not fail execute path
} else {
LOG_DEBUG("success to add package spec to cached",
K(ret), K(package_id), K(package_spec->get_can_cached()));
}
}
OZ (resolve_ctx.package_guard_.put(package_id, cacheobj_guard), package_id);
if (OB_FAIL(ret) && OB_NOT_NULL(package_spec)) {
// pointer should be free manually
cacheobj_guard->~ObCacheObjGuard();
package_spec = NULL;
}
}
}
return ret;
}
int ObPLPackageManager::load_package_body(const ObPLResolveCtx &resolve_ctx,
const share::schema::ObPackageInfo &package_spec_info,
const share::schema::ObPackageInfo &package_body_info,
ObPLPackage *&package_body)
{
int ret = OB_SUCCESS;
package_body = NULL;
ObPLCompiler compiler(resolve_ctx.allocator_,
resolve_ctx.session_info_,
resolve_ctx.schema_guard_,
resolve_ctx.package_guard_,
resolve_ctx.sql_proxy_);
const uint64_t tenant_id = package_spec_info.get_tenant_id();
uint64_t db_id = package_spec_info.get_database_id();
uint64_t package_spec_id = package_spec_info.get_package_id();
uint64_t package_body_id = package_body_info.get_package_id();
ObPLBlockNS *null_parent_ns = NULL;
const ObDatabaseSchema *db_schema = NULL;
uint64_t effective_tenant_id = resolve_ctx.session_info_.get_effective_tenant_id();
HEAP_VARS_2((ObPLPackageAST, package_spec_ast, resolve_ctx.allocator_),
(ObPLPackageAST, package_body_ast, resolve_ctx.allocator_)) {
ObString source;
if (package_spec_info.is_for_trigger()) {
OZ (ObTriggerInfo::gen_package_source(package_spec_info.get_tenant_id(),
package_spec_info.get_package_id(),
source,
PACKAGE_TYPE,
resolve_ctx.schema_guard_,
resolve_ctx.allocator_));
} else {
source = package_spec_info.get_source();
}
OZ (resolve_ctx.schema_guard_.get_database_schema(tenant_id, db_id, db_schema));
OZ (package_spec_ast.init(db_schema->get_database_name_str(),
package_spec_info.get_package_name(),
PL_PACKAGE_SPEC,
package_spec_info.get_database_id(),
package_spec_id,
package_spec_info.get_schema_version(),
NULL));
OZ (ObSQLUtils::convert_sql_text_from_schema_for_resolve(
resolve_ctx.allocator_, resolve_ctx.session_info_.get_dtc_params(), source));
{
ObPLCompilerEnvGuard guard(
package_spec_info, resolve_ctx.session_info_, resolve_ctx.schema_guard_, ret);
OZ (compiler.analyze_package(source, null_parent_ns,
package_spec_ast, package_spec_info.is_for_trigger()));
}
OZ (package_body_ast.init(db_schema->get_database_name_str(),
package_body_info.get_package_name(),
PL_PACKAGE_BODY,
package_body_info.get_database_id(),
package_body_id,
package_body_info.get_schema_version(),
&package_spec_ast));
// generate cacheobj_guard to protect package and package will be
// destoried by map's destructor
ObCacheObjGuard* cacheobj_guard = NULL;
void* buf = NULL;
if (OB_ISNULL(buf = resolve_ctx.package_guard_.alloc_.alloc(sizeof(ObCacheObjGuard)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory.", K(ret));
} else if (FALSE_IT(cacheobj_guard = new (buf)ObCacheObjGuard(PACKAGE_BODY_HANDLE))) {
// do nothing
} else {
OZ (ObCacheObjectFactory::alloc(*cacheobj_guard, ObLibCacheNameSpace::NS_PKG,
effective_tenant_id));
OX (package_body = static_cast<ObPLPackage*>(cacheobj_guard->get_cache_obj()));
CK (OB_NOT_NULL(package_body));
OZ (package_body->init(package_body_ast));
for (int64_t i = 0; OB_SUCC(ret) && i < package_spec_ast.get_dependency_table().count(); ++i) {
OZ (package_body_ast.add_dependency_object(package_spec_ast.get_dependency_table().at(i)));
}
OZ (compiler.compile_package(package_body_info,
&(package_spec_ast.get_body()->get_namespace()),
package_body_ast,
*package_body));
if (OB_SUCC(ret)
&& package_body->get_can_cached()
&& OB_FAIL(add_package_to_plan_cache(resolve_ctx, package_body))) {
LOG_WARN("add package body to plan cache failed", K(package_body_id), K(ret));
ret = OB_SUCCESS; //cache add failed, need not fail execute path
}
OZ (resolve_ctx.package_guard_.put(package_body_id, cacheobj_guard));
if (OB_FAIL(ret) && OB_NOT_NULL(package_body)) {
// pointer should be free manually
cacheobj_guard->~ObCacheObjGuard();
package_body = NULL;
}
}
}
return ret;
}
int ObPLPackageManager::check_version(const ObPLResolveCtx &resolve_ctx, uint64_t package_id,
const ObPackageStateVersion &state_version, bool &match)
{
int ret = OB_SUCCESS;
match = true;
if (OB_INVALID_ID == package_id
|| !state_version.is_valid()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("tenant or package id is invalid", K(ret), K(package_id));
} else {
ObPLPackage *package_spec = NULL;
ObPLPackage *package_body = NULL;
if (OB_FAIL(get_cached_package(resolve_ctx, package_id, package_spec, package_body))) {
LOG_WARN("failed to get cached package", K(ret), K(package_id));
} else {
if (state_version.package_version_ == package_spec->get_version()) {
if (OB_NOT_NULL(package_body) && state_version.package_body_version_ != package_body->get_version()) {
match = false;
}
} else {
match = false;
}
}
}
return ret;
}
int ObPLPackageManager::get_package_schema_info(ObSchemaGetterGuard &schema_guard,
uint64_t package_id,
const ObPackageInfo *&package_spec_info,
const ObPackageInfo *&package_body_info)
{
int ret = OB_SUCCESS;
package_spec_info = NULL;
package_body_info = NULL;
int64_t compatible_mode = lib::is_oracle_mode() ? COMPATIBLE_ORACLE_MODE
: COMPATIBLE_MYSQL_MODE;
if (!ObTriggerInfo::is_trigger_package_id(package_id)) {
const uint64_t tenant_id = get_tenant_id_by_object_id(package_id);
const ObPackageInfo *tmp_package_info = NULL;
if (OB_FAIL(schema_guard.get_package_info(tenant_id, package_id, tmp_package_info))) {
LOG_WARN("failed to get package info", K(tenant_id), K(package_id), K(ret));
} else if (OB_ISNULL(tmp_package_info)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package info is NULL", K(package_id), K(ret));
} else {
if (PACKAGE_TYPE == tmp_package_info->get_type()) {
package_spec_info = tmp_package_info;
if (OB_FAIL(schema_guard.get_package_info(tmp_package_info->get_tenant_id(),
tmp_package_info->get_database_id(),
tmp_package_info->get_package_name(),
PACKAGE_BODY_TYPE,
compatible_mode,
package_body_info))) {
LOG_WARN("failed to get package body info", "package name", package_spec_info->get_package_name(), K(ret));
}
} else {
package_body_info = tmp_package_info;
if (OB_FAIL(schema_guard.get_package_info(tmp_package_info->get_tenant_id(),
tmp_package_info->get_database_id(),
tmp_package_info->get_package_name(),
PACKAGE_TYPE,
compatible_mode,
package_spec_info))) {
LOG_WARN("failed to get package info", "package name", package_body_info->get_package_name(), K(ret));
} else if (OB_ISNULL(package_spec_info)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package body info is NULL", K(ret));
{
ObString db_name("");
const ObDatabaseSchema *database_schema = NULL;
if (OB_SUCCESS == schema_guard.get_database_schema(tmp_package_info->get_tenant_id(),
tmp_package_info->get_database_id(), database_schema)) {
if (NULL != database_schema) {
db_name =database_schema->get_database_name_str();
}
}
LOG_USER_ERROR(OB_ERR_PACKAGE_DOSE_NOT_EXIST, "PACKAGE",
db_name.length(), db_name.ptr(),
tmp_package_info->get_package_name().length(),
tmp_package_info->get_package_name().ptr());
}
}
}
}
} else {
if (OB_FAIL(schema_guard.get_package_info_from_trigger(MTL_ID(),
package_id,
package_spec_info,
package_body_info))) {
LOG_WARN("failed to get package info from trigger", K(ret), K(package_id));
}
}
return ret;
}
int ObPLPackageManager::get_cached_package_spec(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
ObPLPackage *&package_spec)
{
int ret = OB_SUCCESS;
package_spec = NULL;
bool is_overflow = false;
if (OB_FAIL(check_stack_overflow(is_overflow))) {
LOG_WARN("failed to check stack overflow", K(ret));
} else if (is_overflow) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("too deep recusive", K(ret));
}
CK (OB_LIKELY(OB_INVALID_ID != package_id));
ObCacheObjGuard* guard = NULL;
OX (ret = resolve_ctx.package_guard_.get(package_id, guard));
if (OB_SUCC(ret) && OB_NOT_NULL(guard)) {
OX (package_spec = static_cast<ObPLPackage*>(guard->get_cache_obj()));
CK (OB_NOT_NULL(package_spec));
} else if (OB_HASH_NOT_EXIST == ret) {
ret = OB_SUCCESS;
const ObPackageInfo *package_info = NULL;
const uint64_t tenant_id = get_tenant_id_by_object_id(package_id);
OZ (resolve_ctx.schema_guard_.get_package_info(tenant_id, package_id, package_info), package_id);
OV (OB_NOT_NULL(package_info), OB_ERR_UNEXPECTED, K(tenant_id), K(package_id));
OZ (get_package_from_plan_cache(resolve_ctx, package_id, package_spec), package_id);
if (OB_SUCC(ret)) {
if (OB_ISNULL(package_spec)) {
OZ (load_package_spec(resolve_ctx, *package_info, package_spec), package_id);
} else {
if (package_info->get_schema_version() != package_spec->get_version()) {
ret = OB_NEED_RETRY;
LOG_ERROR("package version changed",
K(package_id), K(ret), KPC(package_info), KPC(package_spec));
}
}
}
} else if (OB_FAIL(ret)) {
LOG_WARN("failed to get package from local cache", K(ret), K(package_id));
}
return ret;
}
int ObPLPackageManager::get_cached_package(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
ObPLPackage *&package_spec,
ObPLPackage *&package_body,
bool for_static_member)
{
int ret = OB_SUCCESS;
package_spec = NULL;
package_body = NULL;
bool is_overflow = false;
if (OB_FAIL(check_stack_overflow(is_overflow))) {
LOG_WARN("failed to check stack overflow", K(ret));
} else if (is_overflow) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("too deep recusive", K(ret));
}
CK (OB_LIKELY(OB_INVALID_ID != package_id));
if (OB_SUCC(ret)) {
const ObPackageInfo *package_spec_info = NULL;
const ObPackageInfo *package_body_info = NULL;
uint64_t package_spec_id = OB_INVALID_ID;
uint64_t package_body_id = OB_INVALID_ID;
OZ (get_package_schema_info(resolve_ctx.schema_guard_, package_id, package_spec_info, package_body_info));
OV (OB_NOT_NULL(package_spec_info), OB_ERR_UNEXPECTED, K(package_id));
OX (package_spec_id = package_spec_info->get_package_id());
OZ (get_cached_package_spec(resolve_ctx, package_spec_id, package_spec));
CK (OB_NOT_NULL(package_spec));
if (OB_SUCC(ret)
&& OB_NOT_NULL(package_body_info)
&& (!for_static_member || package_id != package_spec_id)) {
OX (package_body_id = package_body_info->get_package_id());
ObCacheObjGuard* guard = NULL;
OX (ret = resolve_ctx.package_guard_.get(package_body_id, guard));
if (OB_SUCC(ret) && OB_NOT_NULL(guard)) {
OX (package_body = static_cast<ObPLPackage*>(guard->get_cache_obj()));
CK (OB_NOT_NULL(package_body));
} else if (OB_HASH_NOT_EXIST == ret) {
ret = OB_SUCCESS;
OZ (get_package_from_plan_cache(resolve_ctx, package_body_id, package_body));
if (OB_SUCC(ret) && OB_ISNULL(package_body)) {
OZ (load_package_body(resolve_ctx, *package_spec_info, *package_body_info, package_body));
CK (OB_NOT_NULL(package_body));
}
if (OB_SUCC(ret)
&& package_body_info->get_schema_version() != package_body->get_version()) {
ret = OB_NEED_RETRY;
LOG_ERROR("package body version changed", K(package_body_id), K(ret));
}
} else {
LOG_WARN("failed to get package body from local cache", K(ret), K(package_body_id));
}
}
}
return ret;
}
int ObPLPackageManager::get_package_item_state(ObSQLSessionInfo &session_info,
int64_t package_id,
const ObPackageStateVersion &state_version,
ObPLPackageState *&package_state)
{
int ret = OB_SUCCESS;
int hash_ret = session_info.get_package_state(package_id, package_state);
if (OB_HASH_NOT_EXIST == hash_ret) {
package_state = NULL;
} else if (hash_ret != OB_SUCCESS) {
ret = hash_ret;
LOG_WARN("failed to get package state from session", K(hash_ret), K(ret));
} else if (OB_NOT_NULL(package_state) && !package_state->check_version(state_version)) {
package_state = NULL;
}
return ret;
}
int ObPLPackageManager::get_package_item_state(const ObPLResolveCtx &resolve_ctx,
ObExecContext &exec_ctx,
ObPLPackage &package,
const ObPackageStateVersion &state_version,
ObPLPackageState *&package_state)
{
int ret = OB_SUCCESS;
package_state = NULL;
ObIAllocator &session_allocator = resolve_ctx.session_info_.get_package_allocator();
uint64_t package_id = package.get_id();
bool need_new = false;
int hash_ret = resolve_ctx.session_info_.get_package_state(package_id, package_state);
if (OB_HASH_NOT_EXIST == hash_ret) {
need_new = true;
} else if (OB_SUCCESS != hash_ret) {
ret = hash_ret;
LOG_WARN("get package state failed", K(package_id), K(ret));
} else if (!package_state->check_version(state_version)) {
OZ (resolve_ctx.session_info_.del_package_state(package_id));
if (OB_SUCC(ret)) {
package_state->reset(&(resolve_ctx.session_info_));
package_state->~ObPLPackageState();
session_allocator.free(package_state);
package_state = NULL;
need_new = true;
}
}
if (OB_SUCC(ret) && need_new) {
CK (OB_ISNULL(package_state));
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(package_state =
static_cast<ObPLPackageState *>(session_allocator.alloc(sizeof(ObPLPackageState))))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("memory allocate failed", K(ret));
} else {
new (package_state)
ObPLPackageState(package_id, state_version, package.get_serially_reusable());
ExecCtxBak exec_ctx_bak;
OX (exec_ctx_bak.backup(exec_ctx));
sql::ObPhysicalPlanCtx phy_plan_ctx(exec_ctx.get_allocator());
OX (exec_ctx.set_physical_plan_ctx(&phy_plan_ctx));
if (OB_SUCC(ret) && package.get_expr_op_size() > 0) {
OZ (exec_ctx.init_expr_op(package.get_expr_op_size()));
}
// 要先加到SESSION上然后在初始化, 反之会造成死循环
OZ (resolve_ctx.session_info_.add_package_state(package_id, package_state));
if (OB_SUCC(ret)) {
// TODO bin.lb: how about the memory?
//
OZ(package.get_frame_info().pre_alloc_exec_memory(exec_ctx));
}
if (OB_SUCC(ret)
&& OB_FAIL(package.instantiate_package_state(resolve_ctx, exec_ctx, *package_state))) {
int tmp_ret = OB_SUCCESS;
if (OB_SUCCESS != (tmp_ret = resolve_ctx.session_info_.del_package_state(package_id))) {
// 删除失败, 为了避免一个未知的状态, 重新初始化这段内存, 使之是无效状态
new (package_state)
ObPLPackageState(package_id, state_version, package.get_serially_reusable());
LOG_WARN("failed to del package state", K(ret), K(package_id), K(tmp_ret));
} else {
// 删除成功将内存释放
package_state->reset(&(resolve_ctx.session_info_));
package_state->~ObPLPackageState();
session_allocator.free(package_state);
package_state = NULL;
LOG_WARN("failed to call instantiate_package_state", K(ret), K(package_id));
}
}
if (package.get_expr_op_size() > 0) {
//Memory leak
//Must be reset before free expr_op_ctx!
exec_ctx.reset_expr_op();
exec_ctx.get_allocator().free(exec_ctx.get_expr_op_ctx_store());
}
exec_ctx_bak.restore(exec_ctx);
}
}
return ret;
}
int ObPLPackageManager::get_package_state(const ObPLResolveCtx &resolve_ctx,
sql::ObExecContext &exec_ctx,
uint64_t package_id,
ObPLPackageState *&package_state,
bool for_static_member)
{
int ret = OB_SUCCESS;
package_state = NULL;
if (OB_INVALID_ID == package_id) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("invalid package id", K(ret));
} else {
ObPLPackage* package_spec = NULL;
ObPLPackage* package_body = NULL;
if (OB_FAIL(get_cached_package(
resolve_ctx, package_id, package_spec, package_body, for_static_member))) {
LOG_WARN("get package failed", K(package_id), K(ret));
} else if (OB_ISNULL(package_spec)) {
ret = OB_ERR_PACKAGE_DOSE_NOT_EXIST;
LOG_WARN("package spec not exist", K(package_id), K(ret));
} else {
ObPackageStateVersion state_version(package_spec->get_version(), NULL==package_body?OB_INVALID_VERSION:package_body->get_version());
ObPLPackageState *package_spec_state = NULL;
ObPLPackageState *package_body_state = NULL;
if (OB_FAIL(get_package_item_state(resolve_ctx, exec_ctx, *package_spec, state_version, package_spec_state))) {
LOG_WARN("get pacakge spec state failed", K(ret));
} else if (!OB_ISNULL(package_body) && OB_FAIL(get_package_item_state(resolve_ctx, exec_ctx, *package_body, state_version, package_body_state))) {
LOG_WARN("get pacakge body state failed", K(ret));
} else {
if (package_id == package_spec->get_id()) {
package_state = package_spec_state;
} else {
package_state = package_body_state;
}
}
}
}
return ret;
}
int ObPLPackageManager::add_package_to_plan_cache(const ObPLResolveCtx &resolve_ctx, ObPLPackage *package)
{
int ret = OB_SUCCESS;
ObPlanCache *plan_cache = NULL;
if (OB_ISNULL(package)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("cached package is null", K(package));
} else if (OB_ISNULL(plan_cache = resolve_ctx.session_info_.get_plan_cache())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("plan cache is null");
} else {
int64_t tenant_id = resolve_ctx.session_info_.get_effective_tenant_id();
uint64_t package_id = package->get_id();
ObString sql("package");
//ObArenaAllocator allocator(ObModIds::OB_PL_TEMP);
//HEAP_VAR(ObExecContext, exec_ctx, allocator) {
uint64_t database_id = OB_INVALID_ID;
resolve_ctx.session_info_.get_database_id(database_id);
ObPLCacheCtx pc_ctx;
pc_ctx.session_info_ = &resolve_ctx.session_info_;
pc_ctx.schema_guard_ = &resolve_ctx.schema_guard_;
(void)ObSQLUtils::md5(sql,pc_ctx.sql_id_, (int32_t)sizeof(pc_ctx.sql_id_));
int64_t sys_schema_version = OB_INVALID_VERSION;
int64_t tenant_schema_version = OB_INVALID_VERSION;
pc_ctx.key_.namespace_ = ObLibCacheNameSpace::NS_PKG;
pc_ctx.key_.db_id_ = database_id;
pc_ctx.key_.key_id_ = package_id;
pc_ctx.key_.sessid_ =
(get_tenant_id_by_object_id(package_id) != OB_SYS_TENANT_ID && resolve_ctx.session_info_.is_pl_debug_on())
? resolve_ctx.session_info_.get_sessid() : 0;
if (OB_FAIL(ret)) {
} else if (OB_FAIL(resolve_ctx.schema_guard_.get_schema_version(tenant_id, tenant_schema_version))
|| OB_FAIL(resolve_ctx.schema_guard_.get_schema_version(OB_SYS_TENANT_ID, sys_schema_version))) {
LOG_WARN("fail to get schema version", K(ret), K(tenant_id));
} else {
package->set_tenant_schema_version(tenant_schema_version);
package->set_sys_schema_version(sys_schema_version);
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(ObPLCacheMgr::add_pl_cache(resolve_ctx.session_info_.get_plan_cache(), package, pc_ctx))) {
if (OB_SQL_PC_PLAN_DUPLICATE == ret) {
LOG_INFO("package has been added by others, need not add again", K(package_id), K(ret));
ret = OB_SUCCESS;
} else if (OB_REACH_MEMORY_LIMIT == ret || OB_SQL_PC_PLAN_SIZE_LIMIT == ret) {
if (REACH_TIME_INTERVAL(1000000)) { //1s, 当内存达到上限时, 该日志打印会比较频繁, 所以以1s为间隔打印
LOG_INFO("can't add plan to plan cache",
K(package_id), K(package->get_mem_size()), K(plan_cache->get_mem_used()), K(ret));
}
ret = OB_SUCCESS;
} else if (OB_REACH_MAX_CONCURRENT_NUM != ret) { //如果是达到限流上限, 则将错误码抛出去
LOG_WARN("add package to ObPlanCache failed",
K(package_id), K(ret), K(package->get_dependency_table()));
ret = OB_SUCCESS; //add package出错, 覆盖错误码, 确保因plan cache失败不影响正常执行路径
}
} else {
LOG_INFO("add pl package to plan cache success",
K(ret), K(package_id), K(package->get_dependency_table()), K(pc_ctx.key_));
}
//exec_ctx.set_physical_plan_ctx(NULL);
//}
}
return ret;
}
int ObPLPackageManager::get_package_from_plan_cache(const ObPLResolveCtx &resolve_ctx,
uint64_t package_id,
ObPLPackage *&package)
{
int ret = OB_SUCCESS;
package = NULL;
bool is_overflow = false;
if (OB_FAIL(check_stack_overflow(is_overflow))) {
LOG_WARN("failed to check stack overflow", K(ret));
} else if (is_overflow) {
ret = OB_SIZE_OVERFLOW;
LOG_WARN("too deep recusive", K(ret));
}
if (OB_FAIL(ret)) {
// do nothing
} else {
ObString sql("package");
//SMART_VAR(ObExecContext, exec_ctx, resolve_ctx.allocator_) {
uint64_t database_id = OB_INVALID_ID;
resolve_ctx.session_info_.get_database_id(database_id);
ObPLCacheCtx pc_ctx;
pc_ctx.session_info_ = &resolve_ctx.session_info_;
pc_ctx.schema_guard_ = &resolve_ctx.schema_guard_;
(void)ObSQLUtils::md5(sql,pc_ctx.sql_id_, (int32_t)sizeof(pc_ctx.sql_id_));
pc_ctx.key_.namespace_ = ObLibCacheNameSpace::NS_PKG;
pc_ctx.key_.db_id_ = database_id;
pc_ctx.key_.key_id_ = package_id;
pc_ctx.key_.sessid_ =
(get_tenant_id_by_object_id(package_id) != OB_SYS_TENANT_ID && resolve_ctx.session_info_.is_pl_debug_on())
? resolve_ctx.session_info_.get_sessid() : 0;
// get package from plan cache
ObCacheObjGuard* cacheobj_guard = NULL;
void* buf = NULL;
if (OB_FAIL(ret)) {
} else if (OB_ISNULL(buf = resolve_ctx.package_guard_.alloc_.alloc(sizeof(ObCacheObjGuard)))) {
ret = OB_ALLOCATE_MEMORY_FAILED;
LOG_WARN("failed to allocate memory.", K(ret));
} else if (FALSE_IT(cacheobj_guard = new (buf)ObCacheObjGuard(GET_PKG_HANDLE))) {
// do nothing
} else if (OB_FAIL(ObPLCacheMgr::get_pl_cache(resolve_ctx.session_info_.get_plan_cache(), *cacheobj_guard, pc_ctx))) {
LOG_INFO("get pl package from plan cache failed", K(ret), K(package_id));
if (OB_ERR_UNEXPECTED != ret) {
ret = OB_SUCCESS;
}
} else if (FALSE_IT(package = static_cast<ObPLPackage*>(cacheobj_guard->get_cache_obj()))) {
// do nothing
} else if (OB_NOT_NULL(package)) {
if (OB_FAIL(resolve_ctx.package_guard_.put(package_id, cacheobj_guard))) {
LOG_WARN("failed to put package to package guard", K(ret), K(package_id));
// pointer should be free manualy
cacheobj_guard->~ObCacheObjGuard();
package = NULL;
} else {
LOG_DEBUG("get package from plan cache success", K(ret), K(package_id));
}
} else {}
//}
}
return ret;
}
int ObPLPackageManager::destory_package_state(sql::ObSQLSessionInfo &session_info, uint64_t package_id)
{
int ret = OB_SUCCESS;
ObPLPackageState *package_state;
if (OB_FAIL(session_info.get_package_state(package_id, package_state))) {
if (OB_HASH_NOT_EXIST != ret) {
LOG_WARN("get package state failed", K(ret));
} else {
ret = OB_SUCCESS;
}
} else if (OB_ISNULL(package_state)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("package state is null", K(ret));
} else if (OB_FAIL(session_info.del_package_state(package_id))) {
LOG_WARN("delete package state failed", K(package_state), K(ret));
} else {
package_state->reset(&session_info);
package_state->~ObPLPackageState();
session_info.get_package_allocator().free(package_state);
package_state = NULL;
}
return ret;
}
} // end namespace pl
} // end namespace oceanbase