add for replace and insert_up with batch_optimization
This commit is contained in:
committed by
ob-robot
parent
671aeb2cea
commit
f001af9558
@ -697,6 +697,7 @@ int ObParser::check_is_insert(common::ObIArray<common::ObString> &queries, bool
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
is_ins = false;
|
||||
bool is_replace = false;
|
||||
if (queries.count() < 1) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
LOG_WARN("queries is unexpected", K(ret));
|
||||
@ -705,6 +706,8 @@ int ObParser::check_is_insert(common::ObIArray<common::ObString> &queries, bool
|
||||
} else {
|
||||
ObString &sql_str = queries.at(0);
|
||||
is_ins = (sql_str.length() > 6 && 0 == STRNCASECMP(sql_str.ptr(), "insert", 6));
|
||||
is_replace = (sql_str.length() > 7 && 0 == STRNCASECMP(sql_str.ptr(), "replace", 7));
|
||||
is_ins = is_ins | is_replace;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -731,7 +734,9 @@ int ObParser::reconstruct_insert_sql(const common::ObString &stmt,
|
||||
allocator_ = &allocator;
|
||||
if (OB_FAIL(parse(stmt, parse_result, parse_mode, false, true))) {
|
||||
// if parser SQL failed,then we won't rewrite it and keep it as it is
|
||||
LOG_WARN("failed to parser insert sql", K(ret));
|
||||
LOG_WARN("failed to parser insert sql", K(ret),
|
||||
K(parse_result.ins_multi_value_res_->on_duplicate_pos_),
|
||||
K(parse_result.ins_multi_value_res_->values_count_));
|
||||
} else if (parse_result.ins_multi_value_res_->values_count_ == 1) {
|
||||
// only one set of values,not need rewrite
|
||||
} else if (OB_ISNULL(bak_allocator)) {
|
||||
@ -740,6 +745,13 @@ int ObParser::reconstruct_insert_sql(const common::ObString &stmt,
|
||||
} else {
|
||||
// restore the allocator
|
||||
allocator_ = bak_allocator;
|
||||
LOG_DEBUG("after do reconstruct sql, result is",
|
||||
K(parse_result.ins_multi_value_res_->on_duplicate_pos_),
|
||||
K(parse_result.ins_multi_value_res_->values_col_),
|
||||
K(parse_result.ins_multi_value_res_->values_count_),
|
||||
K(stmt));
|
||||
bool is_on_duplicate = (parse_result.ins_multi_value_res_->on_duplicate_pos_ > 0);
|
||||
int64_t on_duplicate_length = stmt.length() - parse_result.ins_multi_value_res_->on_duplicate_pos_;
|
||||
for (ParenthesesOffset *current_obj = parse_result.ins_multi_value_res_->ref_parentheses_;
|
||||
OB_SUCC(ret) && NULL != current_obj;
|
||||
current_obj = current_obj->next_) {
|
||||
@ -753,7 +765,11 @@ int ObParser::reconstruct_insert_sql(const common::ObString &stmt,
|
||||
// right_parentheses_ - left_parentheses_,not contain the length of the left parenthesis, so the length + 1
|
||||
const int64_t values_length = current_obj->right_parentheses_ - current_obj->left_parentheses_ + 1;
|
||||
// The reason for here + 1 is to add a delimiter;
|
||||
const int64_t final_length = shared_length + values_length + 1; // 这个+1的原因是
|
||||
int64_t final_length = shared_length + values_length + 1; // 这个+1的原因是 为了后边的';'
|
||||
if (is_on_duplicate) {
|
||||
// for the on_duplicate_key clause of insert_up
|
||||
final_length = final_length + on_duplicate_length;
|
||||
}
|
||||
if (OB_ISNULL(new_sql_buf = static_cast<char*>(allocator_->alloc(final_length)))) {
|
||||
ret = OB_ALLOCATE_MEMORY_FAILED;
|
||||
LOG_WARN("fail to alloc memory", K(ret), K(final_length));
|
||||
@ -761,11 +777,19 @@ int ObParser::reconstruct_insert_sql(const common::ObString &stmt,
|
||||
LOG_WARN("failed to deep copy new sql", K(ret), K(final_length), K(shared_length), K(pos), K(stmt));
|
||||
} else if (OB_FAIL(databuff_memcpy(new_sql_buf, final_length, pos, values_length, (stmt.ptr() + (current_obj->left_parentheses_ - 1))))) {
|
||||
LOG_WARN("failed to deep copy member list buf", K(ret), K(final_length), K(pos), K(stmt), K(values_length));
|
||||
} else if (is_on_duplicate && OB_FAIL(databuff_memcpy(new_sql_buf,
|
||||
final_length,
|
||||
pos,
|
||||
on_duplicate_length,
|
||||
stmt.ptr() + parse_result.ins_multi_value_res_->on_duplicate_pos_))) {
|
||||
|
||||
} else {
|
||||
new_sql_buf[final_length - 1] = ';';
|
||||
ObString part(final_length, new_sql_buf);
|
||||
if (OB_FAIL(ins_queries.push_back(part))) {
|
||||
LOG_WARN("fail to push back query str", K(ret), K(part));
|
||||
} else {
|
||||
LOG_DEBUG("after rebuild multi_query sql is", K(part));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,6 +273,7 @@ typedef struct _InsMultiValuesResult
|
||||
ParenthesesOffset *tail_parentheses_;
|
||||
int values_col_;
|
||||
int values_count_;
|
||||
int on_duplicate_pos_; // the start position of on duplicate key in insert ... on duplicate key update statement
|
||||
int ret_code_;
|
||||
} InsMultiValuesResult;
|
||||
|
||||
|
||||
@ -17572,44 +17572,46 @@ int obsql_mysql_multi_fast_parse(ParseResult *p)
|
||||
}
|
||||
|
||||
enum state_multi_values {
|
||||
INS_START_STATE = 0,
|
||||
INS_INSERT_STATE = 1,
|
||||
INS_HINT_START_STATE = 2,
|
||||
INS_HINT_END_STATE = 3,
|
||||
INS_INTO_STATE = 4,
|
||||
INS_VALUES_STATE = 5,
|
||||
INS_LEFT_PAR_STATE = 6,
|
||||
INS_RIGHT_PAR_STATE = 7,
|
||||
INS_COMMA_STATE = 8,
|
||||
INS_END_SUCCESS = 9,
|
||||
ERROR_STATE = 10
|
||||
STMT_START_STATE = 0,
|
||||
STMT_INS_OR_REPLACE_STATE = 1,
|
||||
STMT_HINT_START_STATE = 2,
|
||||
STMT_HINT_END_STATE = 3,
|
||||
STMT_INTO_STATE = 4,
|
||||
STMT_VALUES_STATE = 5,
|
||||
STMT_LEFT_PAR_STATE = 6,
|
||||
STMT_RIGHT_PAR_STATE = 7,
|
||||
STMT_ON_STATE = 8,
|
||||
STMT_DUPLICATE_STATE = 9,
|
||||
STMT_KEY_STATE = 10,
|
||||
STMT_UPDATE_STATE = 11,
|
||||
STMT_END_SUCCESS = 12,
|
||||
ERROR_STATE = 13
|
||||
};
|
||||
|
||||
// Used to split an insert SQL with multiple values
|
||||
// example: insert /*+parllen(5)*/ into test.t1(c1,c2,c3) values(1,1,1),((1),(2),3);
|
||||
// insert /*+parllen(5)*/ into test.t1(c1,c2,c3) values(1,1,1);
|
||||
// insert /*+parllen(5)*/ into test.t1(c1,c2,c3) values((1),(2),3);
|
||||
/*
|
||||
* INS_START_STATE -(insert)-> INS_INSERT_STATE -(into)-> INS_INTO_STATE -(values/value)-> INS_VALUES_STATE
|
||||
* INS_VALUES_STATE -(find left'(')-> INS_LEFT_PAR_STATE -(find last right')')-> INS_RIGHT_PAR_STATE
|
||||
* INS_RIGHT_PAR_STATE -(find ',')-> INS_VALUES_STATE -->....
|
||||
* INS_RIGHT_PAR_STATE -(find ';')-> INS_END_SUCCESS
|
||||
*/
|
||||
int obsql_mysql_multi_values_parse(ParseResult *p)
|
||||
{
|
||||
int ret = 0;
|
||||
int SUCCESS = 0;
|
||||
int UNEXPECTED_RRROR = -1;
|
||||
int ret = SUCCESS;
|
||||
int64_t pair_count = 0;
|
||||
bool is_end = false;
|
||||
int state = INS_START_STATE;
|
||||
int state = STMT_START_STATE;
|
||||
if (OB_UNLIKELY(NULL == p)) {
|
||||
ret = -1;
|
||||
ret = UNEXPECTED_RRROR;
|
||||
} else {
|
||||
YYSTYPE yylval;
|
||||
YYLTYPE yylloc;
|
||||
int token = YYEMPTY;
|
||||
int left_parentheses = 0;
|
||||
int right_parentheses = 0;
|
||||
while (0 == ret && !is_end) {
|
||||
int on_start_pos = 0;
|
||||
p->ins_multi_value_res_->on_duplicate_pos_ = -1;
|
||||
p->ins_multi_value_res_->values_col_ = -1;
|
||||
while (SUCCESS == ret && !is_end) {
|
||||
token = obsql_mysql_yylex(&yylval, &yylloc, p->yyscan_info_);
|
||||
if (token == PARSER_SYNTAX_ERROR || token == ERROR) {
|
||||
state = ERROR_STATE;
|
||||
@ -17618,86 +17620,117 @@ int obsql_mysql_multi_values_parse(ParseResult *p)
|
||||
is_end = true;
|
||||
}
|
||||
switch (state) {
|
||||
case INS_START_STATE:
|
||||
if (token == INSERT) {
|
||||
state = INS_INSERT_STATE;
|
||||
} else if (token == INSERT_HINT_BEGIN) {
|
||||
state = INS_HINT_START_STATE;
|
||||
case STMT_START_STATE:
|
||||
if (token == INSERT || token == REPLACE) {
|
||||
state = STMT_INS_OR_REPLACE_STATE;
|
||||
} else if (token == INSERT_HINT_BEGIN || token == REPLACE_HINT_BEGIN) {
|
||||
state = STMT_HINT_START_STATE;
|
||||
}
|
||||
break;
|
||||
case INS_INSERT_STATE:
|
||||
case STMT_INS_OR_REPLACE_STATE:
|
||||
if (token == INTO) {
|
||||
state = INS_INTO_STATE;
|
||||
state = STMT_INTO_STATE;
|
||||
} else if (token == VALUES || token == VALUE) {
|
||||
p->ins_multi_value_res_->values_col_ = yylloc.last_column;
|
||||
state = STMT_VALUES_STATE;
|
||||
}
|
||||
break;
|
||||
case INS_HINT_START_STATE:
|
||||
case STMT_HINT_START_STATE:
|
||||
if (token == HINT_END) {
|
||||
state = INS_HINT_END_STATE;
|
||||
state = STMT_HINT_END_STATE;
|
||||
}
|
||||
break;
|
||||
case INS_HINT_END_STATE:
|
||||
case STMT_HINT_END_STATE:
|
||||
if (token == INTO) {
|
||||
state = INS_INTO_STATE;
|
||||
state = STMT_INTO_STATE;
|
||||
} else if (token == VALUES || token == VALUE) {
|
||||
state = STMT_VALUES_STATE;
|
||||
}
|
||||
break;
|
||||
case INS_INTO_STATE:
|
||||
case STMT_INTO_STATE:
|
||||
if (token == VALUES || token == VALUE) {
|
||||
state = INS_VALUES_STATE;
|
||||
state = STMT_VALUES_STATE;
|
||||
p->ins_multi_value_res_->values_col_ = yylloc.last_column;
|
||||
}
|
||||
break;
|
||||
case INS_VALUES_STATE:
|
||||
case STMT_VALUES_STATE:
|
||||
if (token == '(') {
|
||||
state = INS_LEFT_PAR_STATE;
|
||||
state = STMT_LEFT_PAR_STATE;
|
||||
// Record the starting position of the left bracket
|
||||
pair_count++;
|
||||
left_parentheses = yylloc.last_column;
|
||||
} else {
|
||||
// If the first position is not the left bracket, it will jump out of the loop and will not be rewritten
|
||||
ret = -1;
|
||||
// If the first token following 'values' is not '(', report an error directly
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
break;
|
||||
case INS_LEFT_PAR_STATE:
|
||||
case STMT_LEFT_PAR_STATE:
|
||||
if (token == ')') {
|
||||
pair_count--;
|
||||
if (pair_count == 0) {
|
||||
// Record the starting position of the right bracket
|
||||
state = INS_RIGHT_PAR_STATE;
|
||||
right_parentheses = yylloc.last_column;
|
||||
// After the ')' are matched, record the position of the left and right brackets at the moment
|
||||
if (left_parentheses > 0) {
|
||||
right_parentheses = yylloc.last_column;
|
||||
on_start_pos = yylloc.last_column;
|
||||
ret = store_prentthese_info(left_parentheses, right_parentheses, p);
|
||||
left_parentheses = 0;
|
||||
right_parentheses = 0;
|
||||
state = STMT_RIGHT_PAR_STATE;
|
||||
} else {
|
||||
// only ')', without the position of '('
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
}
|
||||
} else if (token == '(') {
|
||||
pair_count++;
|
||||
} else {
|
||||
// do nothing
|
||||
// Other tokens will not be processed
|
||||
}
|
||||
break;
|
||||
case INS_RIGHT_PAR_STATE:
|
||||
case STMT_RIGHT_PAR_STATE:
|
||||
// Ended the right bracket matching, if you encounter ',', it means that the next '(' is about to start
|
||||
// If you encounter ON, it means that this is an inset ... on duplicate key statement
|
||||
// If the terminator is encountered, it means the end of the current SQL
|
||||
if (token == ',') {
|
||||
if (pair_count == 0) {
|
||||
// At this point, a set of values ends and offset is recorded
|
||||
if (right_parentheses <= 0 || left_parentheses <= 0) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = store_prentthese_info(left_parentheses, right_parentheses, p);
|
||||
// Start looking for the next set of values
|
||||
state = INS_VALUES_STATE;
|
||||
left_parentheses = 0;
|
||||
right_parentheses = 0;
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
state = STMT_VALUES_STATE;
|
||||
} else if (token == ON) {
|
||||
// Is insert on duplicate key update...
|
||||
// Record the start position of on duplicate key
|
||||
p->ins_multi_value_res_->on_duplicate_pos_ = on_start_pos;
|
||||
state = STMT_ON_STATE;
|
||||
} else if (token == END_P || token == DELIMITER) {
|
||||
// When the termination symbol appears, it jumps out of the loop
|
||||
if (right_parentheses <= 0 || left_parentheses <= 0) {
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = store_prentthese_info(left_parentheses, right_parentheses, p);
|
||||
state = INS_END_SUCCESS;
|
||||
}
|
||||
state = STMT_END_SUCCESS;
|
||||
} else {
|
||||
// If other characters appear, skip rewriting
|
||||
ret = -1;
|
||||
// Other symbol appear, it jumps out of the loop
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
break;
|
||||
case STMT_ON_STATE:
|
||||
if (token == DUPLICATE) {
|
||||
state = STMT_DUPLICATE_STATE;
|
||||
} else {
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
break;
|
||||
case STMT_DUPLICATE_STATE:
|
||||
if (token == KEY) {
|
||||
state = STMT_KEY_STATE;
|
||||
} else {
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
break;
|
||||
case STMT_KEY_STATE:
|
||||
if (token == UPDATE) {
|
||||
state = STMT_UPDATE_STATE;
|
||||
} else {
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
break;
|
||||
case STMT_UPDATE_STATE:
|
||||
if (token == END_P || token == DELIMITER) {
|
||||
// When the termination symbol appears, it jumps out of the loop
|
||||
state = STMT_END_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case ERROR_STATE:
|
||||
@ -17706,8 +17739,8 @@ int obsql_mysql_multi_values_parse(ParseResult *p)
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
if (INS_END_SUCCESS != state) {
|
||||
ret = -1;
|
||||
if (STMT_END_SUCCESS != state) {
|
||||
ret = UNEXPECTED_RRROR;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user