611 lines
22 KiB
C++
611 lines
22 KiB
C++
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License, version 2.0,
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is also distributed with certain software (including
|
|
but not limited to OpenSSL) that is licensed under separate terms,
|
|
as designated in a particular file or component or in included license
|
|
documentation. The authors of MySQL hereby grant you an additional
|
|
permission to link the program and your derivative works with the
|
|
separately licensed software that they have included with MySQL.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License, version 2.0, for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "sql/dd/upgrade_57/event.h"
|
|
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
|
|
#include "lex_string.h"
|
|
#include "m_ctype.h"
|
|
#include "m_string.h"
|
|
#include "my_base.h"
|
|
#include "my_dbug.h"
|
|
#include "my_inttypes.h"
|
|
#include "my_loglevel.h"
|
|
#include "my_sys.h"
|
|
#include "my_time.h"
|
|
#include "my_user.h" // parse_user
|
|
#include "mysql/components/services/log_builtins.h"
|
|
#include "mysql/psi/psi_base.h"
|
|
#include "mysql/udf_registration_types.h"
|
|
#include "mysql_com.h"
|
|
#include "mysqld_error.h"
|
|
#include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client
|
|
#include "sql/dd/dd_event.h" // create_event
|
|
#include "sql/dd/impl/upgrade/server.h"
|
|
#include "sql/dd/types/event.h"
|
|
#include "sql/dd/upgrade_57/global.h"
|
|
#include "sql/event_db_repository.h" // Events
|
|
#include "sql/event_parse_data.h" // Event_parse_data
|
|
#include "sql/field.h"
|
|
#include "sql/handler.h"
|
|
#include "sql/histograms/value_map.h"
|
|
#include "sql/key.h"
|
|
#include "sql/log.h" // LogErr()
|
|
#include "sql/mysqld.h" // default_tz_name
|
|
#include "sql/sp.h" // load_charset
|
|
#include "sql/sql_base.h" // open_tables
|
|
#include "sql/sql_class.h"
|
|
#include "sql/sql_const.h"
|
|
#include "sql/sql_servers.h"
|
|
#include "sql/sql_time.h" // interval_type_to_name
|
|
#include "sql/system_variables.h"
|
|
#include "sql/table.h" // Table_check_intact
|
|
#include "sql/thd_raii.h"
|
|
#include "sql/thr_malloc.h"
|
|
#include "sql/transaction.h" // trans_commit
|
|
#include "sql/tztime.h" // my_tz_find
|
|
#include "sql_string.h"
|
|
#include "thr_lock.h"
|
|
|
|
namespace dd {
|
|
class Schema;
|
|
} // namespace dd
|
|
|
|
namespace dd {
|
|
namespace upgrade_57 {
|
|
|
|
static Check_table_intact table_intact;
|
|
|
|
/**
|
|
Column definitions for 5.7 mysql.event table (5.7.13 and up).
|
|
*/
|
|
const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] = {
|
|
{{STRING_WITH_LEN("db")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("name")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("body")}, {STRING_WITH_LEN("longblob")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("definer")},
|
|
{STRING_WITH_LEN("char(93)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("execute_at")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("interval_value")},
|
|
{STRING_WITH_LEN("int(11)")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("interval_field")},
|
|
{STRING_WITH_LEN(
|
|
"enum('YEAR','QUARTER','MONTH','DAY',"
|
|
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR'"
|
|
","
|
|
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND'"
|
|
","
|
|
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
|
|
"'SECOND_MICROSECOND')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("created")}, {STRING_WITH_LEN("timestamp")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("modified")}, {STRING_WITH_LEN("timestamp")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("last_executed")},
|
|
{STRING_WITH_LEN("datetime")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("starts")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("ends")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("status")},
|
|
{STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("on_completion")},
|
|
{STRING_WITH_LEN("enum('DROP','PRESERVE')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("sql_mode")},
|
|
{STRING_WITH_LEN(
|
|
"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
|
|
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_"
|
|
"SUBTRACTION',"
|
|
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
|
|
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','"
|
|
"MYSQL40',"
|
|
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_"
|
|
"TABLES',"
|
|
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
|
|
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
|
|
"'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_"
|
|
"LENGTH')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("comment")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("originator")}, {STRING_WITH_LEN("int(10)")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("time_zone")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("latin1")}},
|
|
{{STRING_WITH_LEN("character_set_client")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("collation_connection")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("db_collation")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("body_utf8")}, {STRING_WITH_LEN("longblob")}, {NULL, 0}}};
|
|
|
|
static const TABLE_FIELD_DEF event_table_def = {ET_FIELD_COUNT,
|
|
event_table_fields};
|
|
|
|
/**
|
|
Column definitions for 5.7 mysql.event table (before 5.7.13).
|
|
*/
|
|
|
|
static const TABLE_FIELD_TYPE event_table_fields_old[ET_FIELD_COUNT] = {
|
|
{{STRING_WITH_LEN("db")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("name")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("body")}, {STRING_WITH_LEN("longblob")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("definer")},
|
|
{STRING_WITH_LEN("char(77)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("execute_at")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("interval_value")},
|
|
{STRING_WITH_LEN("int(11)")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("interval_field")},
|
|
{STRING_WITH_LEN(
|
|
"enum('YEAR','QUARTER','MONTH','DAY',"
|
|
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR'"
|
|
","
|
|
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND'"
|
|
","
|
|
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
|
|
"'SECOND_MICROSECOND')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("created")}, {STRING_WITH_LEN("timestamp")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("modified")}, {STRING_WITH_LEN("timestamp")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("last_executed")},
|
|
{STRING_WITH_LEN("datetime")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("starts")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("ends")}, {STRING_WITH_LEN("datetime")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("status")},
|
|
{STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("on_completion")},
|
|
{STRING_WITH_LEN("enum('DROP','PRESERVE')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("sql_mode")},
|
|
{STRING_WITH_LEN(
|
|
"set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
|
|
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_"
|
|
"SUBTRACTION',"
|
|
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
|
|
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','"
|
|
"MYSQL40',"
|
|
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_"
|
|
"TABLES',"
|
|
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
|
|
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
|
|
"'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_"
|
|
"LENGTH')")},
|
|
{NULL, 0}},
|
|
{{STRING_WITH_LEN("comment")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("originator")}, {STRING_WITH_LEN("int(10)")}, {NULL, 0}},
|
|
{{STRING_WITH_LEN("time_zone")},
|
|
{STRING_WITH_LEN("char(64)")},
|
|
{STRING_WITH_LEN("latin1")}},
|
|
{{STRING_WITH_LEN("character_set_client")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("collation_connection")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("db_collation")},
|
|
{STRING_WITH_LEN("char(32)")},
|
|
{STRING_WITH_LEN("utf8")}},
|
|
{{STRING_WITH_LEN("body_utf8")}, {STRING_WITH_LEN("longblob")}, {NULL, 0}}};
|
|
|
|
static const TABLE_FIELD_DEF event_table_def_old = {ET_FIELD_COUNT,
|
|
event_table_fields_old};
|
|
|
|
/**
|
|
Load the charset and time zone information for an event.
|
|
*/
|
|
static void load_event_creation_context(THD *thd, TABLE *table,
|
|
Event_parse_data *et_parse_data) {
|
|
LEX_STRING tz_name;
|
|
const CHARSET_INFO *client_cs;
|
|
const CHARSET_INFO *connection_cl;
|
|
thd->variables.time_zone = my_tz_SYSTEM;
|
|
|
|
if ((tz_name.str = get_field(thd->mem_root,
|
|
table->field[ET_FIELD_TIME_ZONE])) == NULL) {
|
|
LogErr(WARNING_LEVEL, ER_EVENT_CANT_GET_TIMEZONE_FROM_FIELD,
|
|
et_parse_data->dbname.str, et_parse_data->name.str);
|
|
} else {
|
|
tz_name.length = strlen(tz_name.str);
|
|
String tz_str(tz_name.str, &my_charset_latin1);
|
|
if ((thd->variables.time_zone = my_tz_find(thd, &tz_str)) == NULL) {
|
|
thd->variables.time_zone = my_tz_SYSTEM;
|
|
LogErr(WARNING_LEVEL, ER_EVENT_CANT_FIND_TIMEZONE,
|
|
et_parse_data->dbname.str, et_parse_data->name.str);
|
|
}
|
|
}
|
|
|
|
if (load_charset(thd->mem_root, table->field[ET_FIELD_CHARACTER_SET_CLIENT],
|
|
thd->variables.character_set_client, &client_cs)) {
|
|
LogErr(WARNING_LEVEL, ER_EVENT_CANT_GET_CHARSET, et_parse_data->dbname.str,
|
|
et_parse_data->name.str);
|
|
}
|
|
|
|
if (load_collation(thd->mem_root, table->field[ET_FIELD_COLLATION_CONNECTION],
|
|
thd->variables.collation_connection, &connection_cl)) {
|
|
LogErr(WARNING_LEVEL, ER_EVENT_CANT_GET_COLLATION,
|
|
et_parse_data->dbname.str, et_parse_data->name.str);
|
|
}
|
|
|
|
thd->variables.character_set_client = client_cs;
|
|
thd->variables.collation_connection = connection_cl;
|
|
}
|
|
|
|
/**
|
|
Update the created, last modified and last executed
|
|
time for the event with the values read from the old
|
|
data dir.
|
|
*/
|
|
|
|
static bool update_event_timing_fields(THD *thd, TABLE *table,
|
|
const char *event_db_name,
|
|
const char *event_name) {
|
|
dd::Event *new_event = nullptr;
|
|
dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
|
|
|
|
if (thd->dd_client()->acquire_for_modification(event_db_name, event_name,
|
|
&new_event))
|
|
return true;
|
|
|
|
if (new_event == nullptr) return true;
|
|
|
|
if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null()) {
|
|
MYSQL_TIME time;
|
|
my_time_t last_executed;
|
|
bool not_used = false;
|
|
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time, TIME_NO_ZERO_DATE);
|
|
last_executed = my_tz_OFFSET0->TIME_to_gmt_sec(&time, ¬_used);
|
|
new_event->set_last_executed(last_executed);
|
|
}
|
|
|
|
new_event->set_created(table->field[ET_FIELD_CREATED]->val_int());
|
|
new_event->set_last_altered(table->field[ET_FIELD_MODIFIED]->val_int());
|
|
|
|
if (thd->dd_client()->update(new_event)) {
|
|
trans_rollback_stmt(thd);
|
|
return true;
|
|
}
|
|
|
|
return trans_commit_stmt(thd) || trans_commit(thd);
|
|
}
|
|
|
|
/**
|
|
Searches for a LEX_STRING in an LEX_STRING array.
|
|
|
|
@param[in] haystack The array.
|
|
@param[in] needle The string to search for.
|
|
@param[in] cs Charset info.
|
|
|
|
@note The last LEX_STRING in the array should have str member set to NULL.
|
|
|
|
@retval -1 Not found.
|
|
@retval >=0 Ordinal position.
|
|
*/
|
|
|
|
static int find_string_in_array(const LEX_CSTRING *haystack,
|
|
const LEX_CSTRING *needle,
|
|
const CHARSET_INFO *cs) {
|
|
const LEX_CSTRING *pos;
|
|
for (pos = haystack; pos->str; pos++) {
|
|
if (!cs->coll->strnncollsp(
|
|
cs, pointer_cast<const uchar *>(pos->str), pos->length,
|
|
pointer_cast<const uchar *>(needle->str), needle->length)) {
|
|
return static_cast<int>(pos - haystack);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
Update the event's interval and status information in the DD.
|
|
*/
|
|
|
|
static bool set_status_and_interval_for_event(THD *thd, TABLE *table,
|
|
Event_parse_data *et_parse_data) {
|
|
char *ptr;
|
|
bool not_used = false;
|
|
MYSQL_TIME time;
|
|
|
|
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
|
|
et_parse_data->expression = table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
|
|
else
|
|
et_parse_data->expression = 0;
|
|
|
|
/*
|
|
If neither STARTS and ENDS is set, then both fields are empty.
|
|
Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
|
|
*/
|
|
et_parse_data->execute_at_null = table->field[ET_FIELD_EXECUTE_AT]->is_null();
|
|
if (!et_parse_data->expression && !et_parse_data->execute_at_null) {
|
|
if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time, TIME_NO_ZERO_DATE))
|
|
return true;
|
|
et_parse_data->execute_at =
|
|
my_tz_OFFSET0->TIME_to_gmt_sec(&time, ¬_used);
|
|
}
|
|
|
|
/*
|
|
We load the interval type from disk as string and then map it to
|
|
an integer. This decouples the values of enum interval_type
|
|
and values actually stored on disk. Therefore the type can be
|
|
reordered without risking incompatibilities of data between versions.
|
|
*/
|
|
if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null()) {
|
|
int i;
|
|
char buff[MAX_FIELD_WIDTH];
|
|
String str(buff, sizeof(buff), &my_charset_bin);
|
|
LEX_CSTRING tmp;
|
|
|
|
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_str(&str);
|
|
if (!(tmp.length = str.length())) return true;
|
|
|
|
tmp.str = str.c_ptr_safe();
|
|
|
|
i = find_string_in_array(interval_type_to_name, &tmp, system_charset_info);
|
|
if (i < 0) return true;
|
|
et_parse_data->interval = (interval_type)i;
|
|
}
|
|
|
|
if ((ptr = get_field(thd->mem_root, table->field[ET_FIELD_STATUS])) == NULL)
|
|
return true;
|
|
|
|
switch (ptr[0]) {
|
|
case 'E':
|
|
et_parse_data->status = Event_parse_data::ENABLED;
|
|
break;
|
|
case 'S':
|
|
et_parse_data->status = Event_parse_data::SLAVESIDE_DISABLED;
|
|
break;
|
|
case 'D':
|
|
default:
|
|
et_parse_data->status = Event_parse_data::DISABLED;
|
|
break;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
Create an entry in the DD for the event by reading all the
|
|
event attributes stored in 'mysql.event' table.
|
|
*/
|
|
static bool migrate_event_to_dd(THD *thd, TABLE *event_table) {
|
|
char *ptr;
|
|
MYSQL_TIME time;
|
|
LEX_USER user_info;
|
|
Event_parse_data et_parse_data;
|
|
LEX_STRING event_body, event_body_utf8;
|
|
|
|
et_parse_data.interval = INTERVAL_LAST;
|
|
et_parse_data.identifier = NULL;
|
|
|
|
if ((et_parse_data.definer.str = get_field(
|
|
thd->mem_root, event_table->field[ET_FIELD_DEFINER])) == NULL)
|
|
return true;
|
|
et_parse_data.definer.length = strlen(et_parse_data.definer.str);
|
|
|
|
if ((et_parse_data.name.str =
|
|
get_field(thd->mem_root, event_table->field[ET_FIELD_NAME])) == NULL)
|
|
return true;
|
|
et_parse_data.name.length = strlen(et_parse_data.name.str);
|
|
|
|
if ((et_parse_data.dbname.str =
|
|
get_field(thd->mem_root, event_table->field[ET_FIELD_DB])) == NULL)
|
|
return true;
|
|
et_parse_data.dbname.length = strlen(et_parse_data.dbname.str);
|
|
|
|
if ((et_parse_data.comment.str = get_field(
|
|
thd->mem_root, event_table->field[ET_FIELD_COMMENT])) == NULL)
|
|
et_parse_data.comment.length = 0;
|
|
else
|
|
et_parse_data.comment.length = strlen(et_parse_data.comment.str);
|
|
|
|
bool not_used = false;
|
|
et_parse_data.starts_null = event_table->field[ET_FIELD_STARTS]->is_null();
|
|
if (!et_parse_data.starts_null) {
|
|
event_table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
|
|
et_parse_data.starts = my_tz_OFFSET0->TIME_to_gmt_sec(&time, ¬_used);
|
|
}
|
|
|
|
et_parse_data.ends_null = event_table->field[ET_FIELD_ENDS]->is_null();
|
|
if (!et_parse_data.ends_null) {
|
|
event_table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
|
|
et_parse_data.ends = my_tz_OFFSET0->TIME_to_gmt_sec(&time, ¬_used);
|
|
}
|
|
|
|
et_parse_data.originator = event_table->field[ET_FIELD_ORIGINATOR]->val_int();
|
|
|
|
if (set_status_and_interval_for_event(thd, event_table, &et_parse_data))
|
|
return true;
|
|
|
|
if ((ptr = get_field(thd->mem_root,
|
|
event_table->field[ET_FIELD_ORIGINATOR])) == NULL)
|
|
return true;
|
|
|
|
if ((ptr = get_field(thd->mem_root,
|
|
event_table->field[ET_FIELD_ON_COMPLETION])) == NULL)
|
|
return true;
|
|
|
|
et_parse_data.on_completion =
|
|
(ptr[0] == 'D' ? Event_parse_data::ON_COMPLETION_DROP
|
|
: Event_parse_data::ON_COMPLETION_PRESERVE);
|
|
|
|
// Set up the event body.
|
|
if ((event_body.str =
|
|
get_field(thd->mem_root, event_table->field[ET_FIELD_BODY])) == NULL)
|
|
return true;
|
|
event_body.length = strlen(event_body.str);
|
|
|
|
if ((event_body_utf8.str = get_field(
|
|
thd->mem_root, event_table->field[ET_FIELD_BODY_UTF8])) == NULL)
|
|
return true;
|
|
event_body_utf8.length = strlen(event_body_utf8.str);
|
|
et_parse_data.body_changed = true;
|
|
|
|
dd::upgrade::Routine_event_context_guard event_ctx_guard(thd);
|
|
|
|
thd->variables.sql_mode = (sql_mode_t)(
|
|
event_table->field[ET_FIELD_SQL_MODE]->val_int() & MODE_ALLOWED_MASK);
|
|
|
|
// Holders for user name and host name used in parse user.
|
|
char definer_user_name_holder[USERNAME_LENGTH + 1];
|
|
char definer_host_name_holder[HOSTNAME_LENGTH + 1];
|
|
memset(&user_info, 0, sizeof(LEX_USER));
|
|
user_info.user = {definer_user_name_holder, USERNAME_LENGTH};
|
|
user_info.host = {definer_host_name_holder, HOSTNAME_LENGTH};
|
|
|
|
parse_user(et_parse_data.definer.str, et_parse_data.definer.length,
|
|
definer_user_name_holder, &user_info.user.length,
|
|
definer_host_name_holder, &user_info.host.length);
|
|
|
|
load_event_creation_context(thd, event_table, &et_parse_data);
|
|
|
|
dd::String_type event_sql;
|
|
if (dd::upgrade::build_event_sp(thd, et_parse_data.name.str,
|
|
et_parse_data.name.length, event_body.str,
|
|
event_body.length, &event_sql) ||
|
|
dd::upgrade::invalid_sql(thd, et_parse_data.dbname.str, event_sql)) {
|
|
LogErr(ERROR_LEVEL, ER_UPGRADE_PARSE_ERROR, "Event",
|
|
et_parse_data.dbname.str, et_parse_data.name.str,
|
|
dd::upgrade::Syntax_error_handler::error_message());
|
|
return false;
|
|
}
|
|
|
|
// Disable autocommit option in thd variable
|
|
Disable_autocommit_guard autocommit_guard(thd);
|
|
|
|
dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
|
|
const dd::Schema *schema = nullptr;
|
|
if (thd->dd_client()->acquire(et_parse_data.dbname.str, &schema)) return true;
|
|
DBUG_ASSERT(schema != nullptr);
|
|
|
|
if (dd::create_event(thd, *schema, et_parse_data.name.str, event_body.str,
|
|
event_body_utf8.str, &user_info, &et_parse_data)) {
|
|
trans_rollback_stmt(thd);
|
|
// Full rollback we have THD::transaction_rollback_request.
|
|
trans_rollback(thd);
|
|
return true;
|
|
}
|
|
|
|
if (trans_commit_stmt(thd) || trans_commit(thd)) return true;
|
|
|
|
return (update_event_timing_fields(thd, event_table, et_parse_data.dbname.str,
|
|
et_parse_data.name.str));
|
|
}
|
|
|
|
/**
|
|
Migrate all the events from 'mysql.event' to 'events' DD table.
|
|
*/
|
|
|
|
bool migrate_events_to_dd(THD *thd) {
|
|
TABLE *event_table;
|
|
int error = 0;
|
|
uint flags = MYSQL_LOCK_IGNORE_TIMEOUT;
|
|
DML_prelocking_strategy prelocking_strategy;
|
|
MEM_ROOT records_mem_root;
|
|
Thd_mem_root_guard root_guard(thd, &records_mem_root);
|
|
|
|
TABLE_LIST tables("mysql", "event", TL_READ);
|
|
auto table_list = &tables;
|
|
|
|
if (open_and_lock_tables(thd, table_list, flags, &prelocking_strategy)) {
|
|
LogErr(ERROR_LEVEL, ER_EVENT_CANT_OPEN_TABLE_MYSQL_EVENT);
|
|
return true;
|
|
}
|
|
|
|
event_table = tables.table;
|
|
event_table->use_all_columns();
|
|
|
|
if (table_intact.check(thd, event_table, &event_table_def)) {
|
|
// check with table format too before returning error.
|
|
if (table_intact.check(thd, event_table, &event_table_def_old)) {
|
|
close_thread_tables(thd);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
System_table_close_guard event_table_guard(thd, event_table);
|
|
|
|
// Initialize time zone support infrastructure since the information
|
|
// is not available during upgrade.
|
|
my_tz_init(thd, default_tz_name, 0);
|
|
|
|
if (event_table->file->ha_index_init(0, 1)) {
|
|
LogErr(ERROR_LEVEL, ER_EVENT_CANT_OPEN_TABLE_MYSQL_EVENT);
|
|
goto err;
|
|
}
|
|
|
|
// Read the first row in the 'event' table via index.
|
|
if ((error = event_table->file->ha_index_first(event_table->record[0]))) {
|
|
if (error == HA_ERR_END_OF_FILE) {
|
|
my_tz_free();
|
|
return false;
|
|
}
|
|
LogErr(ERROR_LEVEL, ER_EVENT_CANT_OPEN_TABLE_MYSQL_EVENT);
|
|
goto err;
|
|
}
|
|
|
|
if (migrate_event_to_dd(thd, event_table)) goto err;
|
|
|
|
// Read the next row in 'event' table via index.
|
|
while (!(error = event_table->file->ha_index_next(event_table->record[0])) &&
|
|
!dd::upgrade::Syntax_error_handler::has_too_many_errors()) {
|
|
if (migrate_event_to_dd(thd, event_table)) goto err;
|
|
}
|
|
|
|
if (error != HA_ERR_END_OF_FILE) {
|
|
LogErr(ERROR_LEVEL, ER_EVENT_CANT_OPEN_TABLE_MYSQL_EVENT);
|
|
goto err;
|
|
}
|
|
|
|
my_tz_free();
|
|
return dd::upgrade::Syntax_error_handler::has_errors();
|
|
|
|
err:
|
|
my_tz_free();
|
|
return true;
|
|
}
|
|
|
|
} // namespace upgrade_57
|
|
} // namespace dd
|