From 89bb127f50ebcda04b4406a760acf4bf7f1c59ba Mon Sep 17 00:00:00 2001 From: hcduan Date: Mon, 27 Dec 2021 17:33:09 +0800 Subject: [PATCH] [bugfix] parse_ending_of_sp_error The parser in multi_statements mode keeps terminating semi-colon for a statement. When it is a DDL creating a stored program, the semi-colon becomes part of the definition. Tools like mysqldump wrap the definition within a version comment which does not support any semi-colon-terminated complete statement, as a result, the output could not be imported. When defining a SP (e.g., TRIGGER, PROCEDURE, and FUNCTION), we often set new separators to distinguish the default line separator (semicolon ';') and whole SP terminators. Normally, the newly defined delimiter is directly used as the ending character of the SP. Eg., DELIMITER // CREATE TRIGGER `TG` BEFORE UPDATE ON `t1` FOR EACH ROW LABELTRI: BEGIN SET new.NAME = '1'; END// Even if the last line incorrectly writes one more semicolon, the extra semicolon will be deleted when storing the SP. Eg., DELIMITER // ... ... END; // The problem is that when the user or other DBA auxiliary tools not only write one more semicolon, but also add additional characters before the newly defined end separator, the SP will incorrectly stored one more semicolon. Eg., DELIMITER // ... ... END; *// The SP is stored as: DELIMITER // ... ... END; At this time, when mysqldump is used, the last line will generated "end;". Which causes errors when importing the SP. Fix: a) When setting the SP terminator (sp_head.cc:set_body_end), we verify that the above error and remove the extra semicolon to correct the end pointer. b) When mysqldump is executed, we remove the extra semicolon when exporting the stored SP. --- client/mysqldump.cc | 5 +++++ sql/sp_head.cc | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/client/mysqldump.cc b/client/mysqldump.cc index c10632586..91c39cf87 100644 --- a/client/mysqldump.cc +++ b/client/mysqldump.cc @@ -1432,6 +1432,11 @@ static char *cover_definer_clause(char *stmt_str, size_t stmt_length, size_t stmt_version_length, const char *keyword_str, size_t keyword_length) { + /* Remove the extra semicolon to prevent mysqldump export errors */ + if (stmt_length > 0 && (stmt_str[stmt_length-1] == ';')) { + stmt_length--; + stmt_str[stmt_length] = '\0'; + } char *definer_begin = my_case_str(stmt_str, stmt_length, STRING_WITH_LEN(" DEFINER")); char *definer_end = nullptr; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 6771fb9c1..90b022c60 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1777,6 +1777,11 @@ void sp_head::set_body_start(THD *thd, const char *begin_ptr) { void sp_head::set_body_end(THD *thd) { Lex_input_stream *lip = &thd->m_parser_state->m_lip; /* shortcut */ const char *end_ptr = lip->get_cpp_ptr(); /* shortcut */ + /* Remove the extra semicolon to prevent mysqldump export errors */ + if (end_ptr - m_parser_data.get_body_start_ptr() > 0 && + (end_ptr[-1] == ';')) { + end_ptr--; + } /* Make the string of parameters. */ -- 2.32.0