Co-authored-by: zzg19950727 <1071026277@qq.com> Co-authored-by: xianyu-w <707512433@qq.com>
271 lines
11 KiB
C++
271 lines
11 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 SQL_RESV
|
|
#include "sql/resolver/ddl/ob_create_synonym_resolver.h"
|
|
#include "lib/number/ob_number_v2.h"
|
|
#include "lib/string/ob_sql_string.h"
|
|
#include "share/schema/ob_table_schema.h"
|
|
#include "share/config/ob_server_config.h"
|
|
#include "sql/resolver/ddl/ob_create_synonym_stmt.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_util.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_resolver_impl.h"
|
|
#include "sql/resolver/expr/ob_raw_expr_part_func_checker.h"
|
|
#include "sql/session/ob_sql_session_info.h"
|
|
#include "sql/resolver/ob_resolver_utils.h"
|
|
#include "sql/ob_sql_utils.h"
|
|
#include "sql/resolver/dml/ob_select_resolver.h"
|
|
#include "share/schema/ob_dependency_info.h"
|
|
#include "share/ob_tenant_id_schema_version.h"
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* CREATE [or replace ] [public] SYNONYM [schemaX.] synonym for [schemaY.]OBJECT [@dlink];
|
|
*/
|
|
namespace oceanbase
|
|
{
|
|
using namespace common;
|
|
using namespace obrpc;
|
|
using namespace share::schema;
|
|
namespace sql
|
|
{
|
|
ObCreateSynonymResolver::ObCreateSynonymResolver(ObResolverParams ¶ms)
|
|
: ObDDLResolver(params)
|
|
{
|
|
}
|
|
|
|
ObCreateSynonymResolver::~ObCreateSynonymResolver()
|
|
{
|
|
}
|
|
|
|
|
|
int ObCreateSynonymResolver::resolve(const ParseNode &parse_tree)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
ParseNode *create_synonym_node = const_cast<ParseNode*>(&parse_tree);
|
|
bool is_public_schema = false;
|
|
bool schema_name_from_node = true;
|
|
if (OB_ISNULL(create_synonym_node)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN( "invalid argument.", K(ret));
|
|
} else if (T_CREATE_SYNONYM != create_synonym_node->type_
|
|
|| CREATE_SYNONYM_NUM_CHILD != create_synonym_node->num_child_
|
|
|| OB_ISNULL(create_synonym_node->children_)) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument.", K(ret), K(create_synonym_node->type_),
|
|
K(create_synonym_node->num_child_), K(create_synonym_node->children_));
|
|
} else {
|
|
ObCreateSynonymStmt *create_synonym_stmt = NULL;
|
|
if (OB_ISNULL(create_synonym_stmt = create_stmt<ObCreateSynonymStmt>())) {
|
|
ret = OB_ALLOCATE_MEMORY_FAILED;
|
|
LOG_WARN("failed to create stmt", K(ret));
|
|
} else {
|
|
uint64_t tenant_id = session_info_->get_effective_tenant_id();
|
|
create_synonym_stmt->set_tenant_id(tenant_id);
|
|
}
|
|
//resolve or replace
|
|
if (OB_SUCC(ret)) {
|
|
if (NULL != create_synonym_node->children_[0]) {
|
|
create_synonym_stmt->set_or_replace(true);
|
|
}
|
|
}
|
|
//resolve is public
|
|
if (OB_SUCC(ret)) {
|
|
if (NULL != create_synonym_node->children_[1]) {
|
|
if (T_PUBLIC != create_synonym_node->children_[1]->type_) {
|
|
ret = OB_INVALID_ARGUMENT;
|
|
LOG_WARN("invalid argument.", K(ret), K(create_synonym_node->children_[1]->type_));
|
|
} else {
|
|
is_public_schema = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
//resolve schema of synonym
|
|
if (OB_SUCC(ret)) {
|
|
if (NULL != create_synonym_node->children_[2]) {
|
|
if (is_public_schema) {
|
|
ret = OB_ERR_INVALID_SYNONYM_NAME;
|
|
|
|
} else {
|
|
ObString db_name;
|
|
int32_t len = static_cast<int32_t>(create_synonym_node->children_[2]->str_len_);
|
|
db_name.assign_ptr(const_cast<char*>(create_synonym_node->children_[2]->str_value_), len);
|
|
create_synonym_stmt->set_database_name(db_name);
|
|
}
|
|
} else if (is_public_schema) {
|
|
create_synonym_stmt->set_database_name(OB_PUBLIC_SCHEMA_NAME);
|
|
} else {
|
|
create_synonym_stmt->set_database_name(session_info_->get_database_name());
|
|
}
|
|
}
|
|
if (OB_SUCC(ret) && ObSchemaChecker::is_ora_priv_check()) {
|
|
CK(OB_NOT_NULL(session_info_), OB_NOT_NULL(schema_checker_));
|
|
OZ (schema_checker_->check_ora_ddl_priv(
|
|
session_info_->get_effective_tenant_id(),
|
|
session_info_->get_priv_user_id(),
|
|
create_synonym_stmt->get_database_name(),
|
|
is_public_schema ?
|
|
stmt::T_CREATE_PUB_SYNONYM : stmt::T_CREATE_SYNONYM,
|
|
session_info_->get_enable_role_array()),
|
|
session_info_->get_effective_tenant_id(), session_info_->get_user_id());
|
|
}
|
|
|
|
//resolve name of synonym
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(create_synonym_node->children_[3])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected error. invalid field. synonym is null pointer",
|
|
K(ret), K(create_synonym_node->children_[3]));
|
|
} else {
|
|
ObString name;
|
|
int32_t len = static_cast<int32_t>(create_synonym_node->children_[3]->str_len_);
|
|
name.assign_ptr(const_cast<char*>(create_synonym_node->children_[3]->str_value_), len);
|
|
if (OB_FAIL(create_synonym_stmt->set_synonym_name(name))) {
|
|
LOG_WARN("Failed to set synonym name", K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
//resolve database of object
|
|
if (OB_SUCC(ret)) {
|
|
if (NULL != create_synonym_node->children_[4]) {
|
|
ObString db_name;
|
|
int32_t len = static_cast<int32_t>(create_synonym_node->children_[4]->str_len_);
|
|
db_name.assign_ptr(const_cast<char*>(create_synonym_node->children_[4]->str_value_), len);
|
|
create_synonym_stmt->set_object_database_name(db_name);
|
|
schema_name_from_node = true;
|
|
} else {
|
|
create_synonym_stmt->set_object_database_name(session_info_->get_database_name());
|
|
schema_name_from_node = false;
|
|
}
|
|
}
|
|
|
|
//resolve name of object
|
|
if (OB_SUCC(ret)) {
|
|
if (OB_ISNULL(create_synonym_node->children_[5])) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("unexpected error. invalid field. synonym is null pointer",
|
|
K(ret), K(create_synonym_node->children_[5]));
|
|
} else {
|
|
ObString string;
|
|
int32_t len = static_cast<int32_t>(create_synonym_node->children_[5]->str_len_);
|
|
string.assign_ptr(const_cast<char*>(create_synonym_node->children_[5]->str_value_), len);
|
|
if (OB_FAIL(create_synonym_stmt->set_object_name(string))) {
|
|
LOG_WARN("Failed to set object name", K(ret));
|
|
}
|
|
}
|
|
}
|
|
|
|
//resolve database link
|
|
// the idea here is to store full dblink desc string in the object_name field,
|
|
// the dblink desc string may like: 'remote_schema_name.tbl@dblink_name' or 'tbl@dblink_name'
|
|
// we have to concat all parts together to get the full desc string.
|
|
if (OB_SUCC(ret)) {
|
|
// we don't have to check whether link_name is created or not,
|
|
// because we may create the dblink with link_name after
|
|
// the synonym is created. check it in runtime.
|
|
ParseNode *dblink_name_node = create_synonym_node->children_[6];
|
|
if (NULL != dblink_name_node && NULL != dblink_name_node->children_ && NULL != dblink_name_node->children_[0]) {
|
|
dblink_name_node = dblink_name_node->children_[0];
|
|
ObSqlString obj_with_dblink;
|
|
const ObString &tmp_obj_name = create_synonym_stmt->get_object_name();
|
|
// user write something like 'create synonym syn for remote_db.tbl_name@dblink'
|
|
// in this case we add the remote_db in the object_name,
|
|
// user may also write 'synonym syn for tbl_name@dblink', we don't have to add db name
|
|
// because the actual db name have to extract from dblink schema.
|
|
if (schema_name_from_node) {
|
|
OZ (obj_with_dblink.append(create_synonym_stmt->get_object_database_name()));
|
|
OZ (obj_with_dblink.append(ObString(".")));
|
|
}
|
|
OZ (obj_with_dblink.append(tmp_obj_name));
|
|
OZ (obj_with_dblink.append_fmt("@%.*s", static_cast<int32_t>(dblink_name_node->str_len_),
|
|
dblink_name_node->str_value_));
|
|
if (OB_SUCC(ret)) {
|
|
ObString dblink_name;
|
|
CK (OB_NOT_NULL(allocator_));
|
|
OZ (ob_write_string(*allocator_, obj_with_dblink.string(), dblink_name));
|
|
OZ (create_synonym_stmt->set_object_name(dblink_name));
|
|
|
|
// we have to reset database name if dblink mode, for the db name may be remote db name
|
|
CK (OB_NOT_NULL(session_info_));
|
|
if (schema_name_from_node) {
|
|
OX (create_synonym_stmt->set_object_database_name(session_info_->get_database_name()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//well done.
|
|
|
|
//add def obj info if exists
|
|
bool ref_exists = false;
|
|
ObObjectType ref_type = ObObjectType::INVALID;
|
|
uint64_t ref_obj_id = OB_INVALID_ID;
|
|
uint64_t ref_schema_version = share::OB_INVALID_SCHEMA_VERSION;
|
|
uint64_t data_version = 0;
|
|
if (OB_FAIL(ret)) {
|
|
} else if (OB_FAIL(check_valid(create_synonym_stmt))) {
|
|
LOG_WARN("fail to check synonym stmt", K(ret));
|
|
} else if (OB_FAIL(GET_MIN_DATA_VERSION(session_info_->get_effective_tenant_id(), data_version))) {
|
|
LOG_WARN("failed to get data version", K(ret));
|
|
} else if (data_version >= DATA_VERSION_4_1_0_0
|
|
&& OB_FAIL(ObSQLUtils::find_synonym_ref_obj(create_synonym_stmt->get_object_database_name(),
|
|
create_synonym_stmt->get_object_name(),
|
|
session_info_->get_effective_tenant_id(),
|
|
ref_exists,
|
|
ref_obj_id,
|
|
ref_type,
|
|
ref_schema_version))) {
|
|
LOG_WARN("failed to find synonym ref obj", K(ret));
|
|
} else {
|
|
if (ref_exists) {
|
|
ObDependencyInfo dep;
|
|
dep.set_dep_obj_id(OB_INVALID_ID);
|
|
dep.set_dep_obj_type(ObObjectType::SYNONYM);
|
|
dep.set_ref_obj_id(ref_obj_id);
|
|
dep.set_ref_obj_type(ref_type);
|
|
dep.set_dep_timestamp(-1);
|
|
dep.set_ref_timestamp(ref_schema_version);
|
|
dep.set_tenant_id(session_info_->get_effective_tenant_id());
|
|
create_synonym_stmt->set_dependency_info(dep);
|
|
}
|
|
stmt_ = create_synonym_stmt;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int ObCreateSynonymResolver::check_valid(const ObCreateSynonymStmt *synonym_stmt)
|
|
{
|
|
int ret = OB_SUCCESS;
|
|
if (OB_ISNULL(synonym_stmt)) {
|
|
ret = OB_ERR_UNEXPECTED;
|
|
LOG_WARN("synonym stmt is NULL", K(ret));
|
|
} else {
|
|
const ObString &db_name = synonym_stmt->get_database_name();
|
|
const ObString &obj_db_name = synonym_stmt->get_object_database_name();
|
|
const ObString &synonym_name = synonym_stmt->get_synonym_name();
|
|
const ObString &object_name = synonym_stmt->get_object_name();
|
|
if (0 == db_name.case_compare(obj_db_name)
|
|
&& 0 == synonym_name.case_compare(object_name)) {
|
|
ret = OB_ERR_SYNONYM_SAME_AS_OBJECT;
|
|
LOG_WARN("cannot create a synonym with same name as object");
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}//end namespace sql
|
|
}//end namespace oceanbase
|