[CP] [CP] grammar compatibility: support insert duplicate update with row alias
This commit is contained in:
parent
2587f45c44
commit
190baf2787
@ -131,7 +131,7 @@ extern void obsql_oracle_parse_fatal_error(int32_t errcode, yyscan_t yyscanner,
|
||||
//%nonassoc STRING_VALUE
|
||||
%left '(' ')'
|
||||
%nonassoc SQL_CACHE SQL_NO_CACHE CHARSET DATABASE_ID REPLICA_NUM/*for shift/reduce conflict between opt_query_expresion_option_list and SQL_CACHE*/
|
||||
%nonassoc HIGHER_PARENS TRANSACTION SIZE AUTO SKEWONLY DEFAULT/*for simple_expr conflict*/
|
||||
%nonassoc HIGHER_PARENS TRANSACTION SIZE AUTO SKEWONLY DEFAULT AS/*for simple_expr conflict*/
|
||||
%left '.'
|
||||
%right NOT NOT2
|
||||
%right BINARY COLLATE
|
||||
@ -403,7 +403,7 @@ END_P SET_VAR DELIMITER
|
||||
%type <node> opt_generated_keyname opt_generated_option_list opt_generated_column_attribute_list generated_column_attribute opt_storage_type
|
||||
%type <node> data_type special_table_type opt_if_not_exists opt_if_exists opt_charset collation opt_collation cast_data_type
|
||||
%type <node> replace_with_opt_hint insert_with_opt_hint column_list opt_on_duplicate_key_clause opt_into opt_replace opt_temporary opt_algorithm opt_sql_security opt_definer view_algorithm no_param_column_ref
|
||||
%type <node> insert_vals_list insert_vals value_or_values
|
||||
%type <node> insert_vals_list insert_vals value_or_values opt_insert_row_alias
|
||||
%type <node> select_with_parens select_no_parens select_clause select_into no_table_select_with_order_and_limit simple_select_with_order_and_limit select_with_parens_with_order_and_limit select_clause_set select_clause_set_left select_clause_set_right select_clause_set_with_order_and_limit
|
||||
%type <node> simple_select no_table_select limit_clause select_expr_list
|
||||
%type <node> with_select with_clause with_list common_table_expr opt_column_alias_name_list alias_name_list column_alias_name
|
||||
@ -8793,12 +8793,39 @@ dml_table_name values_clause
|
||||
NULL, /*duplicate key node*/
|
||||
NULL /*error logging caluse*/);
|
||||
}
|
||||
| dml_table_name SET update_asgn_list
|
||||
| dml_table_name SET update_asgn_list opt_insert_row_alias
|
||||
{
|
||||
ParseNode *val_list = NULL;
|
||||
ParseNode *into_node = NULL;
|
||||
merge_nodes(val_list, result, T_ASSIGN_LIST, $3);
|
||||
malloc_non_terminal_node(into_node, result->malloc_pool_, T_INSERT_INTO_CLAUSE, 1, $1);
|
||||
if ($4 != NULL) {
|
||||
ParseNode *subquery_node = NULL;
|
||||
ParseNode *values_node = NULL;
|
||||
ParseNode *values_list_node = NULL;
|
||||
ParseNode *select_node = NULL;
|
||||
ParseNode *column_list_node = new_node(result->malloc_pool_, T_COLUMN_LIST, val_list->num_child_);
|
||||
ParseNode *value_vector_node = new_node(result->malloc_pool_, T_VALUE_VECTOR, val_list->num_child_);
|
||||
for (int32_t i = 0; i < val_list->num_child_; i++) {
|
||||
ParseNode *assign_item = val_list->children_[i];
|
||||
if (assign_item->num_child_ != 2) {
|
||||
yyerror(&@3, result, "assign_item child num is invalid\n");
|
||||
YYERROR;
|
||||
} else {
|
||||
column_list_node->children_[i]=assign_item->children_[0];
|
||||
value_vector_node->children_[i]=assign_item->children_[1];
|
||||
}
|
||||
}
|
||||
malloc_non_terminal_node(into_node, result->malloc_pool_, T_INSERT_INTO_CLAUSE, 2, $1, column_list_node);
|
||||
malloc_non_terminal_node(values_list_node, result->malloc_pool_, T_VALUES_ROW_LIST, 1, value_vector_node);
|
||||
malloc_non_terminal_node(values_node, result->malloc_pool_, T_VALUES_TABLE_EXPRESSION, 1, values_list_node);
|
||||
malloc_select_values_stmt(subquery_node, result, values_node, NULL, NULL);
|
||||
malloc_select_values_stmt(select_node, result, subquery_node, NULL, NULL);
|
||||
select_node->children_[PARSE_SELECT_FROM]->children_[0]->children_[1] = $4;
|
||||
val_list = select_node;
|
||||
val_list->reserved_ = 1;
|
||||
} else {
|
||||
malloc_non_terminal_node(into_node, result->malloc_pool_, T_INSERT_INTO_CLAUSE, 1, $1);
|
||||
}
|
||||
malloc_non_terminal_node($$, result->malloc_pool_, T_SINGLE_TABLE_INSERT, 4,
|
||||
into_node, /*insert_into_clause*/
|
||||
val_list, /*values_list*/
|
||||
@ -8808,10 +8835,27 @@ dml_table_name values_clause
|
||||
;
|
||||
|
||||
values_clause:
|
||||
value_or_values insert_vals_list
|
||||
value_or_values insert_vals_list opt_insert_row_alias
|
||||
{
|
||||
(void)($1);
|
||||
merge_nodes($$, result, T_VALUE_LIST, $2);
|
||||
if ($3 != NULL) {
|
||||
ParseNode *subquery_node = NULL;
|
||||
ParseNode *values_node = NULL;
|
||||
ParseNode *values_list_node = NULL;
|
||||
if ($2->type_ == T_LINK_NODE) {
|
||||
$2->type_ = T_VALUES_ROW_LIST;
|
||||
values_list_node = $2;
|
||||
} else {
|
||||
malloc_non_terminal_node(values_list_node, result->malloc_pool_, T_VALUES_ROW_LIST, 1, $2);
|
||||
}
|
||||
malloc_non_terminal_node(values_node, result->malloc_pool_, T_VALUES_TABLE_EXPRESSION, 1, values_list_node);
|
||||
malloc_select_values_stmt(subquery_node, result, values_node, NULL, NULL);
|
||||
malloc_select_values_stmt($$, result, subquery_node, NULL, NULL);
|
||||
$$->children_[PARSE_SELECT_FROM]->children_[0]->children_[1] = $3;
|
||||
$$->reserved_ = 1;
|
||||
} else {
|
||||
merge_nodes($$, result, T_VALUE_LIST, $2);
|
||||
}
|
||||
}
|
||||
| select_stmt
|
||||
{
|
||||
@ -8819,6 +8863,19 @@ value_or_values insert_vals_list
|
||||
}
|
||||
;
|
||||
|
||||
opt_insert_row_alias:
|
||||
AS table_subquery_alias
|
||||
{
|
||||
(void)($1);
|
||||
if (OB_UNLIKELY(T_STAR == $2->type_)) {
|
||||
yyerror(&@2, result, "table.* as label is invalid\n");
|
||||
YYERROR;
|
||||
} else {
|
||||
$$ = $2;
|
||||
}
|
||||
}
|
||||
| /*emtpy*/ {$$ = NULL;};
|
||||
|
||||
value_or_values:
|
||||
VALUE
|
||||
{
|
||||
|
@ -15987,7 +15987,7 @@ int ObDMLResolver::refine_generate_table_column_name(const ParseNode &column_ali
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("get unexpected error", K(column_alias_node.type_), K(ret));
|
||||
} else if (OB_UNLIKELY(column_alias_node.num_child_ != select_stmt.get_select_item_size())) {
|
||||
ret = OB_ERR_COULUMN_VALUE_NOT_MATCH;
|
||||
ret = OB_ERR_VIEW_WRONG_LIST;
|
||||
LOG_WARN("column count does not match value count", K(column_alias_node.num_child_), K(ret),
|
||||
K(select_stmt.get_select_item_size()));
|
||||
} else {
|
||||
|
@ -163,7 +163,9 @@ int ObInsertResolver::resolve_insert_clause(const ParseNode &node)
|
||||
LOG_WARN("failed to resolve insert filed", K(ret));
|
||||
} else if (OB_FAIL(get_label_se_columns(insert_stmt->get_insert_table_info(), label_se_columns))) {
|
||||
LOG_WARN("failed to get label se columns", K(ret));
|
||||
} else if (OB_FAIL(resolve_values(*values_node, label_se_columns))) {
|
||||
} else if (OB_FAIL(resolve_values(*values_node,
|
||||
label_se_columns,
|
||||
table_item, node.children_[DUPLICATE_NODE]))) {
|
||||
LOG_WARN("failed to resolve values", K(ret));
|
||||
} else {
|
||||
has_tg = insert_stmt->has_instead_of_trigger();
|
||||
@ -531,7 +533,10 @@ int ObInsertResolver::resolve_insert_assign(const ParseNode &assign_list)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint64_t>& label_se_columns)
|
||||
int ObInsertResolver::resolve_values(const ParseNode &value_node,
|
||||
ObIArray<uint64_t>& label_se_columns,
|
||||
TableItem* table_item,
|
||||
const ParseNode *duplicate_node)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
ObInsertStmt *insert_stmt = get_insert_stmt();
|
||||
@ -558,6 +563,7 @@ int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint6
|
||||
LOG_WARN("allocate select buffer failed", K(ret), "size", sizeof(ObSelectResolver));
|
||||
} else {
|
||||
// value from sub-query(insert into table select ..)
|
||||
bool is_mock = lib::is_mysql_mode() && value_node.reserved_;
|
||||
ObSelectStmt *select_stmt = NULL;
|
||||
sub_select_resolver_ = new(select_buffer) ObSelectResolver(params_);
|
||||
//insert clause and select clause in insert into select belong to the same namespace level
|
||||
@ -571,6 +577,20 @@ int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint6
|
||||
TableItem *sub_select_table = NULL;
|
||||
ObString view_name;
|
||||
ObSEArray<ColumnItem, 4> column_items;
|
||||
ParseNode *alias_node = NULL;
|
||||
ParseNode *table_alias_node = NULL;
|
||||
if (is_mock &&
|
||||
value_node.children_[PARSE_SELECT_FROM] != NULL &&
|
||||
value_node.children_[PARSE_SELECT_FROM]->num_child_ == 1 &&
|
||||
value_node.children_[PARSE_SELECT_FROM]->children_[0]->type_ == T_ALIAS &&
|
||||
value_node.children_[PARSE_SELECT_FROM]->children_[0]->num_child_ == 2) {
|
||||
alias_node = value_node.children_[PARSE_SELECT_FROM]->children_[0]->children_[1];
|
||||
if (T_LINK_NODE == alias_node->type_ && alias_node->num_child_ == 2) {
|
||||
table_alias_node = alias_node->children_[0];
|
||||
} else {
|
||||
table_alias_node = alias_node;
|
||||
}
|
||||
}
|
||||
if (OB_UNLIKELY(T_SELECT != value_node.type_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid value node", K(value_node.type_));
|
||||
@ -579,7 +599,8 @@ int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint6
|
||||
} else if (OB_ISNULL(select_stmt = sub_select_resolver_->get_select_stmt())) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid select stmt", K(select_stmt));
|
||||
} else if (!session_info_->get_ddl_info().is_ddl() && OB_FAIL(check_insert_select_field(*insert_stmt, *select_stmt))) {
|
||||
} else if (!session_info_->get_ddl_info().is_ddl() &&
|
||||
OB_FAIL(check_insert_select_field(*insert_stmt, *select_stmt, is_mock))) {
|
||||
LOG_WARN("check insert select field failed", K(ret), KPC(insert_stmt), KPC(select_stmt));
|
||||
} else if (!session_info_->get_ddl_info().is_ddl() && OB_FAIL(add_new_sel_item_for_oracle_temp_table(*select_stmt))) {
|
||||
LOG_WARN("add session id value to select item failed", K(ret));
|
||||
@ -587,8 +608,42 @@ int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint6
|
||||
label_se_columns,
|
||||
*select_stmt))) {
|
||||
LOG_WARN("add label security columns to select item failed", K(ret));
|
||||
} else if (NULL != table_alias_node) {
|
||||
view_name.assign_ptr(const_cast<char*>(table_alias_node->str_value_),
|
||||
static_cast<int32_t>(table_alias_node->str_len_));
|
||||
} else if (OB_FAIL(insert_stmt->generate_anonymous_view_name(*allocator_, view_name))) {
|
||||
LOG_WARN("failed to generate view name", K(ret));
|
||||
}
|
||||
|
||||
if (OB_SUCC(ret) && is_mock) {
|
||||
ObString ori_table_name = table_item->table_name_;
|
||||
ObSEArray<ObString, 4> ori_column_names;
|
||||
ObString row_alias_table_name = view_name;
|
||||
ObSEArray<ObString, 4> row_alias_column_names;
|
||||
//1. check_table_and_column_name
|
||||
if (OB_FAIL(check_table_and_column_name(insert_stmt->get_values_desc(),
|
||||
select_stmt,
|
||||
ori_table_name,
|
||||
ori_column_names,
|
||||
row_alias_table_name,
|
||||
row_alias_column_names))) {
|
||||
LOG_WARN("fail to get table and column name", K(ret));
|
||||
}
|
||||
//2.check_validity_of_duplicate_node
|
||||
if (OB_FAIL(ret)) {
|
||||
//do nothing
|
||||
} else if (duplicate_node != NULL) {
|
||||
if (OB_FAIL(check_validity_of_duplicate_node(duplicate_node,
|
||||
ori_table_name,
|
||||
ori_column_names,
|
||||
row_alias_table_name,
|
||||
row_alias_column_names))) {
|
||||
LOG_WARN("fail to check validity of duplicate node", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
//do nothing
|
||||
} else if (OB_FAIL(resolve_generate_table_item(select_stmt, view_name, sub_select_table))) {
|
||||
LOG_WARN("failed to resolve generate table item", K(ret));
|
||||
} else if (OB_FAIL(resolve_all_generated_table_columns(*sub_select_table,
|
||||
@ -601,12 +656,235 @@ int ObInsertResolver::resolve_values(const ParseNode &value_node, ObIArray<uint6
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObInsertResolver::check_table_and_column_name(const ObIArray<ObColumnRefRawExpr*> & value_desc,
|
||||
ObSelectStmt *select_stmt,
|
||||
ObString &ori_table_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObString &row_alias_table_name,
|
||||
ObIArray<ObString> &row_alias_column_names)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_ISNULL(select_stmt)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(ret));
|
||||
}
|
||||
//get original table name and column name,row alias table name and column name
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < value_desc.count(); i++) {
|
||||
//column name comparsion is case insensitive
|
||||
const ObColumnRefRawExpr* column = value_desc.at(i);
|
||||
if (OB_ISNULL(column)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("column is NULL", K(ret));
|
||||
} else if (OB_FAIL(ori_column_names.push_back(column->get_column_name()))) {
|
||||
LOG_WARN("fail to push column name");
|
||||
} else if (OB_FAIL(row_alias_column_names.push_back(select_stmt->get_select_item(i).alias_name_))){
|
||||
LOG_WARN("fail to push column name");
|
||||
}
|
||||
}
|
||||
if (OB_SUCC(ret)) {
|
||||
//check validity
|
||||
ObNameCaseMode mode = OB_NAME_CASE_INVALID;
|
||||
bool perserve_lettercase = true;
|
||||
ObCollationType cs_type = CS_TYPE_INVALID;
|
||||
if (OB_FAIL(session_info_->get_name_case_mode(mode))) {
|
||||
LOG_WARN("fail to get name case mode", K(mode), K(ret));
|
||||
} else if (OB_FAIL(session_info_->get_collation_connection(cs_type))) {
|
||||
LOG_WARN("fail to get collation_connection", K(ret));
|
||||
} else {
|
||||
perserve_lettercase = lib::is_oracle_mode() ?
|
||||
true : (mode != OB_LOWERCASE_AND_INSENSITIVE);
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
//do nothing
|
||||
} else if (!perserve_lettercase) {
|
||||
ObCharset::casedn(cs_type, ori_table_name);
|
||||
ObCharset::casedn(cs_type, row_alias_table_name);
|
||||
}
|
||||
if (0 == ori_table_name.compare(row_alias_table_name)) {
|
||||
//case: insert into t1(a,b) values (4,5) as t1(a,b) on duplicate key update a = t1.a;
|
||||
ret = OB_ERR_NONUNIQ_TABLE;
|
||||
LOG_USER_ERROR(OB_ERR_NONUNIQ_TABLE, row_alias_table_name.length(), row_alias_table_name.ptr());
|
||||
} else if (row_alias_column_names.count() == 0 ||
|
||||
ori_column_names.count() == 0) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected column column", K(ret));
|
||||
} else if (row_alias_column_names.count() != ori_column_names.count()) {
|
||||
//case: insert into t1(a,b) values (4,5) as new(a,b,c) on duplicate key update a = t1.a;
|
||||
ret = OB_ERR_VIEW_WRONG_LIST;
|
||||
LOG_WARN("unexpect different count between row_alias_column_names and ori_column_names", K(ret));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObInsertResolver::check_validity_of_duplicate_node(const ParseNode* node,
|
||||
ObString &ori_table_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObString &row_alias_table_name,
|
||||
ObIArray<ObString> &row_alias_column_names)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool is_valid = true;
|
||||
if (OB_ISNULL(node)) {
|
||||
is_valid = false;
|
||||
} else if (T_ASSIGN_ITEM == node->type_) {
|
||||
ObString table_name;
|
||||
ObString column_name;
|
||||
ParseNode* table_name_node = NULL;
|
||||
ParseNode* column_name_node = NULL;
|
||||
ParseNode* col_ref_node = node->children_[0];
|
||||
if (col_ref_node->num_child_ != 3) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(ret));
|
||||
} else if (OB_ISNULL(table_name_node = col_ref_node->children_[1])) {
|
||||
//do nothing
|
||||
} else if (OB_ISNULL(column_name_node = col_ref_node->children_[2])) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(ret));
|
||||
} else {
|
||||
table_name.assign_ptr(table_name_node->str_value_,
|
||||
static_cast<int32_t>(table_name_node->str_len_));
|
||||
if (0 == (row_alias_table_name.compare(ori_table_name)) ) {
|
||||
column_name.assign_ptr(column_name_node->str_value_,
|
||||
static_cast<int32_t>(column_name_node->str_len_));
|
||||
/*
|
||||
* INSERT INTO t1 VALUES (4,5,7) AS t1(m,n,p) ON DUPLICATE KEY UPDATE NEW.m = m+n+1;
|
||||
* NEW.m is not allowed to set
|
||||
*/
|
||||
ret = OB_ERR_BAD_FIELD_ERROR;
|
||||
ObString scope_name = ObString::make_string(get_scope_name(current_scope_));
|
||||
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, column_name.length(), column_name.ptr(),
|
||||
scope_name.length(), scope_name.ptr());
|
||||
} else if (OB_FAIL(check_ambiguous_column(column_name, ori_column_names, row_alias_column_names))) {
|
||||
LOG_WARN("fail to check ambiguous columns", K(ret));
|
||||
}
|
||||
}
|
||||
} else if (T_FUN_SYS == node->type_) {
|
||||
if (node->num_child_ != 2) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(node->num_child_), K(ret));
|
||||
} else {
|
||||
ObString node_name;
|
||||
ObString node_column_name;
|
||||
node_name.assign_ptr(node->children_[0]->str_value_,
|
||||
static_cast<int32_t>(node->children_[0]->str_len_));
|
||||
if (0 == node_name.case_compare("values")) {
|
||||
//do nothing, do not replace column under values expr
|
||||
if (node->children_[1]->type_ == T_EXPR_LIST) {
|
||||
ParseNode* expr_list_node = node->children_[1];
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < expr_list_node->num_child_; ++i) {
|
||||
ObString node_table_name;
|
||||
if (OB_ISNULL(expr_list_node->children_[i])) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(ret));
|
||||
} else {
|
||||
//case: insert into t1(a,b) values (4,5) as new(a,b) on duplicate key update a = value(new.a)+new.a;
|
||||
//new.a under values is not allowed
|
||||
ParseNode* col_ref_node = expr_list_node->children_[i];
|
||||
if (col_ref_node->num_child_ != 3) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpected error", K(ret));
|
||||
} else if (col_ref_node->children_[1] == NULL) {
|
||||
//do nothing
|
||||
} else {
|
||||
node_table_name.assign_ptr(col_ref_node->children_[1]->str_value_,
|
||||
static_cast<int32_t>(col_ref_node->children_[1]->str_len_));
|
||||
if (0 == (node_table_name.compare(row_alias_table_name))) {
|
||||
node_column_name.assign_ptr(col_ref_node->children_[2]->str_value_,
|
||||
static_cast<int32_t>(col_ref_node->children_[2]->str_len_));
|
||||
ret = OB_ERR_BAD_FIELD_ERROR;
|
||||
ObString scope_name = ObString::make_string(get_scope_name(current_scope_));
|
||||
LOG_USER_ERROR(OB_ERR_BAD_FIELD_ERROR, node_column_name.length(), node_column_name.ptr(),
|
||||
scope_name.length(), scope_name.ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is_valid = false;
|
||||
} else if (T_COLUMN_REF == node->type_) {
|
||||
ObString table_name;
|
||||
ObString column_name;
|
||||
if (node->num_child_ != 3) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("unexpect column ref child node", K(node->num_child_), K(ret));
|
||||
} else {
|
||||
if ((node->children_[1]) != NULL) {
|
||||
table_name.assign_ptr(node->children_[1]->str_value_,
|
||||
static_cast<int32_t>(node->children_[1]->str_len_));
|
||||
}
|
||||
if ((node->children_[2]) != NULL) {
|
||||
column_name.assign_ptr(node->children_[2]->str_value_,
|
||||
static_cast<int32_t>(node->children_[2]->str_len_));
|
||||
}
|
||||
if (node->children_[1] == NULL ||
|
||||
(0 == (table_name.compare(ori_table_name)) &&
|
||||
0 == (table_name.compare(row_alias_table_name)))) {
|
||||
//case: insert into t1(a,b) values (4,5) as new(a,b) on duplicate key update a = value(a)+a;
|
||||
//update a[0] = value(a[1])+a[2], a[2] is ambiguous
|
||||
if (OB_FAIL(check_ambiguous_column(column_name, ori_column_names, row_alias_column_names))) {
|
||||
LOG_WARN("fail to check ambiguous columns", K(ret));
|
||||
}
|
||||
}
|
||||
}
|
||||
is_valid = false;
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && is_valid && i < node->num_child_; i++) {
|
||||
if (T_ASSIGN_ITEM == node->type_ && 0 == i) {
|
||||
//ON DUPLICATE KEY UPDATE c = new.a+values(b), only deal with value list [new.a+values(b)]
|
||||
} else if (OB_FAIL(SMART_CALL(check_validity_of_duplicate_node(node->children_[i],
|
||||
ori_table_name,
|
||||
ori_column_names,
|
||||
row_alias_table_name,
|
||||
row_alias_column_names)))) {
|
||||
LOG_WARN("refine_insert_update_assignment fail", K(ret));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObInsertResolver::check_ambiguous_column(ObString &column_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObIArray<ObString> &row_alias_column_names)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool find_in_ori = false;
|
||||
bool find_in_row_alias = false;
|
||||
if (row_alias_column_names.count() != ori_column_names.count()) {
|
||||
ret = OB_ERR_VIEW_WRONG_LIST;
|
||||
LOG_WARN("unexpect different count between row_alias_column_names and ori_column_names", K(ret));
|
||||
}
|
||||
for (int i = 0; OB_SUCC(ret) && (!find_in_row_alias || !find_in_ori)
|
||||
&& i < row_alias_column_names.count(); i++) {
|
||||
ObString row_alias_col_name = row_alias_column_names.at(i);
|
||||
ObString ori_col_name = ori_column_names.at(i);
|
||||
if (0 == (column_name.case_compare(row_alias_col_name))) {
|
||||
find_in_row_alias = true;
|
||||
}
|
||||
if (0 == (column_name.case_compare(ori_col_name))) {
|
||||
find_in_ori = true;
|
||||
}
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
//do nothing
|
||||
} else if (find_in_row_alias && find_in_ori) {
|
||||
ret = OB_NON_UNIQ_ERROR;
|
||||
ObString scope_name = ObString::make_string(get_scope_name(current_scope_));
|
||||
LOG_USER_ERROR(OB_NON_UNIQ_ERROR, column_name.length(), column_name.ptr(),
|
||||
scope_name.length(), scope_name.ptr());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int ObInsertResolver::check_insert_select_field(ObInsertStmt &insert_stmt,
|
||||
ObSelectStmt &select_stmt)
|
||||
ObSelectStmt &select_stmt,
|
||||
bool is_mock)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool is_generated_column = false;
|
||||
const ObIArray<ObColumnRefRawExpr*> &values_desc = insert_stmt.get_values_desc();
|
||||
ObSelectStmt *ref_stmt = NULL;
|
||||
if (OB_ISNULL(session_info_)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("invalid session_info_", K(ret));
|
||||
@ -614,6 +892,15 @@ int ObInsertResolver::check_insert_select_field(ObInsertStmt &insert_stmt,
|
||||
ret = OB_ERR_COULUMN_VALUE_NOT_MATCH;
|
||||
LOG_WARN("column count mismatch", K(values_desc.count()), K(select_stmt.get_select_item_size()));
|
||||
LOG_USER_ERROR(OB_ERR_COULUMN_VALUE_NOT_MATCH, 1l);
|
||||
} else if (is_mock && select_stmt.is_single_table_stmt()) {
|
||||
const TableItem *table_item = select_stmt.get_table_item(0);
|
||||
if (table_item->is_generated_table()) {
|
||||
ref_stmt = table_item->ref_query_;
|
||||
if (ref_stmt->get_select_item_size() != select_stmt.get_select_item_size()) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("item size is unexpected", K(ret), K(ref_stmt->get_select_item_size()), K(select_stmt.get_select_item_size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int64_t i = 0; OB_SUCC(ret) && i < values_desc.count(); ++i) {
|
||||
const ObColumnRefRawExpr *value_desc = values_desc.at(i);
|
||||
@ -649,6 +936,19 @@ int ObInsertResolver::check_insert_select_field(ObInsertStmt &insert_stmt,
|
||||
ret = OB_ERR_INSERT_INTO_GENERATED_ALWAYS_IDENTITY_COLUMN;
|
||||
LOG_USER_ERROR(OB_ERR_INSERT_INTO_GENERATED_ALWAYS_IDENTITY_COLUMN);
|
||||
}
|
||||
if (OB_FAIL(ret)) {
|
||||
//do nothing
|
||||
} else if (is_mock &&
|
||||
ref_stmt != NULL) {
|
||||
if (!ref_stmt->get_select_item(i).is_real_alias_) {
|
||||
ref_stmt->get_select_item(i).alias_name_ = value_desc->get_column_name();
|
||||
ref_stmt->get_select_item(i).is_real_alias_ = true;
|
||||
}
|
||||
if (!select_stmt.get_select_item(i).is_real_alias_) {
|
||||
select_stmt.get_select_item(i).alias_name_ = ref_stmt->get_select_item(i).alias_name_;
|
||||
select_stmt.get_select_item(i).is_real_alias_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -75,14 +75,33 @@ private:
|
||||
ObRawExpr *&expr,
|
||||
bool in_generated_column = false);
|
||||
int set();
|
||||
int resolve_values(const ParseNode &value_node, ObIArray<uint64_t>& label_se_columns);
|
||||
int resolve_values(const ParseNode &value_node,
|
||||
ObIArray<uint64_t>& label_se_columns,
|
||||
TableItem* table_item,
|
||||
const ParseNode *duplicate_node);
|
||||
int check_table_and_column_name(const ObIArray<ObColumnRefRawExpr*> & value_desc,
|
||||
ObSelectStmt *select_stmt,
|
||||
ObString &ori_table_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObString &row_alias_table_name,
|
||||
ObIArray<ObString> &row_alias_column_names);
|
||||
int check_validity_of_duplicate_node(const ParseNode* node,
|
||||
ObString &ori_table_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObString &row_alias_table_name,
|
||||
ObIArray<ObString> &row_alias_column_names);
|
||||
int check_ambiguous_column(ObString &column_name,
|
||||
ObIArray<ObString> &ori_column_names,
|
||||
ObIArray<ObString> &row_alias_column_names);
|
||||
virtual int resolve_insert_update_assignment(const ParseNode *node, ObInsertTableInfo& table_info) override;
|
||||
int replace_column_to_default(ObRawExpr *&origin);
|
||||
virtual int check_returning_validity() override;
|
||||
int resolve_insert_constraint();
|
||||
int check_view_insertable();
|
||||
int inner_cast(common::ObIArray<ObColumnRefRawExpr*> &target_columns, ObSelectStmt &select_stmt);
|
||||
int check_insert_select_field(ObInsertStmt &insert_stmt, ObSelectStmt &select_stmt);
|
||||
int check_insert_select_field(ObInsertStmt &insert_stmt,
|
||||
ObSelectStmt &select_stmt,
|
||||
bool is_mock = false);
|
||||
|
||||
int replace_column_with_mock_column(ObColumnRefRawExpr *gen_col,
|
||||
ObColumnRefRawExpr *value_desc);
|
||||
|
Loading…
x
Reference in New Issue
Block a user