summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt32
-rw-r--r--sql/debug_sync.cc4
-rw-r--r--sql/event_db_repository.cc4
-rw-r--r--sql/field.cc757
-rw-r--r--sql/field.h582
-rw-r--r--sql/ha_partition.cc20
-rw-r--r--sql/ha_partition.h2
-rw-r--r--sql/ha_sequence.cc3
-rw-r--r--sql/handle_connections_win.cc9
-rw-r--r--sql/handler.cc286
-rw-r--r--sql/handler.h62
-rw-r--r--sql/item.cc245
-rw-r--r--sql/item.h372
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/item_create.cc1788
-rw-r--r--sql/item_create.h105
-rw-r--r--sql/item_func.cc37
-rw-r--r--sql/item_func.h124
-rw-r--r--sql/item_geofunc.cc1371
-rw-r--r--sql/item_geofunc.h167
-rw-r--r--sql/item_jsonfunc.cc111
-rw-r--r--sql/item_jsonfunc.h111
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.cc77
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_subselect.cc58
-rw-r--r--sql/item_sum.cc23
-rw-r--r--sql/item_sum.h35
-rw-r--r--sql/item_timefunc.cc19
-rw-r--r--sql/item_timefunc.h38
-rw-r--r--sql/item_windowfunc.cc3
-rw-r--r--sql/item_windowfunc.h11
-rw-r--r--sql/item_xmlfunc.cc4
-rw-r--r--sql/lex.h8
-rw-r--r--sql/lex_string.h38
-rw-r--r--sql/log.cc11
-rw-r--r--sql/log_event.cc11400
-rw-r--r--sql/log_event_client.cc3424
-rw-r--r--sql/log_event_server.cc7903
-rw-r--r--sql/mysql_install_db.cc2
-rw-r--r--sql/mysql_upgrade_service.cc2
-rw-r--r--sql/mysqld.cc379
-rw-r--r--sql/mysqld.h10
-rw-r--r--sql/opt_range.cc16
-rw-r--r--sql/opt_subselect.cc13
-rw-r--r--sql/opt_trace.cc21
-rw-r--r--sql/partition_info.cc6
-rw-r--r--sql/procedure.h10
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/protocol.h5
-rw-r--r--sql/repl_failsafe.cc3
-rw-r--r--sql/rpl_utility.cc975
-rw-r--r--sql/rpl_utility.h4
-rw-r--r--sql/rpl_utility_server.cc1171
-rw-r--r--sql/scheduler.cc25
-rw-r--r--sql/scheduler.h9
-rw-r--r--sql/set_var.cc2
-rw-r--r--sql/share/errmsg-utf8.txt6
-rw-r--r--sql/slave.cc34
-rw-r--r--sql/sp.cc13
-rw-r--r--sql/sp_head.cc13
-rw-r--r--sql/spatial.cc27
-rw-r--r--sql/spatial.h1
-rw-r--r--sql/sql_acl.cc32
-rw-r--r--sql/sql_alter.cc18
-rw-r--r--sql/sql_alter.h3
-rw-r--r--sql/sql_base.cc26
-rw-r--r--sql/sql_basic_types.h2
-rw-r--r--sql/sql_bitmap.h380
-rw-r--r--sql/sql_builtin.cc.in6
-rw-r--r--sql/sql_class.cc47
-rw-r--r--sql/sql_class.h84
-rw-r--r--sql/sql_cmd.h20
-rw-r--r--sql/sql_connect.cc108
-rw-r--r--sql/sql_connect.h28
-rw-r--r--sql/sql_cte.cc2
-rw-r--r--sql/sql_cursor.cc7
-rw-r--r--sql/sql_db.cc65
-rw-r--r--sql/sql_digest.cc2
-rw-r--r--sql/sql_error.cc12
-rw-r--r--sql/sql_error.h21
-rw-r--r--sql/sql_get_diagnostics.cc4
-rw-r--r--sql/sql_help.cc12
-rw-r--r--sql/sql_i_s.h327
-rw-r--r--sql/sql_insert.cc11
-rw-r--r--sql/sql_lex.cc192
-rw-r--r--sql/sql_lex.h62
-rw-r--r--sql/sql_parse.cc32
-rw-r--r--sql/sql_partition.cc4
-rw-r--r--sql/sql_prepare.cc30
-rw-r--r--sql/sql_profile.cc54
-rw-r--r--sql/sql_profile.h5
-rw-r--r--sql/sql_reload.cc2
-rw-r--r--sql/sql_select.cc864
-rw-r--r--sql/sql_select.h7
-rw-r--r--sql/sql_sequence.cc18
-rw-r--r--sql/sql_show.cc1568
-rw-r--r--sql/sql_show.h5
-rw-r--r--sql/sql_signal.cc6
-rw-r--r--sql/sql_string.h22
-rw-r--r--sql/sql_table.cc453
-rw-r--r--sql/sql_table.h4
-rw-r--r--sql/sql_tablespace.cc2
-rw-r--r--sql/sql_tvc.cc4
-rw-r--r--sql/sql_type.cc1782
-rw-r--r--sql/sql_type.h2462
-rw-r--r--sql/sql_type_geom.cc915
-rw-r--r--sql/sql_type_geom.h442
-rw-r--r--sql/sql_type_json.cc6
-rw-r--r--sql/sql_view.cc7
-rw-r--r--sql/sql_yacc.yy634
-rw-r--r--sql/sql_yacc_ora.yy605
-rw-r--r--sql/strfunc.cc3
-rw-r--r--sql/strfunc.h3
-rw-r--r--sql/structs.h2
-rw-r--r--sql/sys_vars.cc16
-rw-r--r--sql/table.cc173
-rw-r--r--sql/table.h69
-rw-r--r--sql/thread_pool_info.cc357
-rw-r--r--sql/threadpool.h9
-rw-r--r--sql/threadpool_common.cc31
-rw-r--r--sql/threadpool_generic.cc228
-rw-r--r--sql/threadpool_generic.h150
-rw-r--r--sql/threadpool_win.cc50
-rw-r--r--sql/unireg.cc141
-rw-r--r--sql/unireg.h3
-rw-r--r--sql/vers_string.h27
-rw-r--r--sql/wsrep_mysqld.cc13
-rw-r--r--sql/xa.cc4
130 files changed, 23669 insertions, 21025 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 90a6a32756c..d8ca18b86e1 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -36,9 +36,10 @@ IF(WITH_WSREP AND NOT EMBEDDED_LIBRARY)
wsrep_plugin.cc
service_wsrep.cc
)
- SET(WSREP_LIB wsrep-lib wsrep_api_v26)
+ MYSQL_ADD_PLUGIN(wsrep ${WSREP_SOURCES} MANDATORY NOT_EMBEDDED EXPORT_SYMBOLS LINK_LIBRARIES wsrep-lib wsrep_api_v26)
ELSE()
- SET(WSREP_SOURCES wsrep_dummy.cc)
+ ADD_LIBRARY(wsrep STATIC wsrep_dummy.cc)
+ ADD_DEPENDENCIES(wsrep GenError)
ENDIF()
INCLUDE_DIRECTORIES(
@@ -79,7 +80,8 @@ SET (SQL_SOURCE
item_create.cc item_func.cc item_geofunc.cc item_row.cc
item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
key.cc log.cc lock.cc
- log_event.cc rpl_record.cc rpl_reporting.cc
+ log_event.cc log_event_server.cc
+ rpl_record.cc rpl_reporting.cc
log_event_old.cc rpl_record_old.cc
mf_iocache.cc my_decimal.cc
mysqld.cc net_serv.cc keycaches.cc
@@ -110,7 +112,8 @@ SET (SQL_SOURCE
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
- partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
+ partition_info.cc rpl_utility.cc rpl_utility_server.cc
+ rpl_injector.cc sql_locale.cc
rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
sql_connect.cc scheduler.cc sql_partition_admin.cc
sql_profile.cc event_parse_data.cc sql_alter.cc
@@ -133,6 +136,7 @@ SET (SQL_SOURCE
semisync.cc semisync_master.cc semisync_slave.cc
semisync_master_ack_receiver.cc
sql_type.cc sql_type_json.cc
+ sql_type_geom.cc
item_windowfunc.cc sql_window.cc
sql_cte.cc
item_vers.cc
@@ -141,14 +145,13 @@ SET (SQL_SOURCE
opt_split.cc
rowid_filter.cc rowid_filter.h
opt_trace.cc
- ${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc backup.cc xa.cc
- ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
+ ${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
@@ -163,6 +166,7 @@ IF ((CMAKE_SYSTEM_NAME MATCHES "Linux" OR
ENDIF()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_generic.cc)
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_common.cc)
+ MYSQL_ADD_PLUGIN(thread_pool_info thread_pool_info.cc DEFAULT STATIC_ONLY NOT_EMBEDDED)
ENDIF()
IF(WIN32)
@@ -176,13 +180,19 @@ RECOMPILE_FOR_EMBEDDED)
ADD_LIBRARY(sql STATIC ${SQL_SOURCE})
DTRACE_INSTRUMENT(sql)
-TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATIC_PLUGIN_LIBS}
+TARGET_LINK_LIBRARIES(sql
mysys mysys_ssl dbug strings vio pcre
${LIBWRAP} ${LIBCRYPT} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT}
- ${WSREP_LIB}
${SSL_LIBRARIES}
${LIBSYSTEMD})
+FOREACH(se aria partition perfschema sql_sequence wsrep)
+ # These engines are used directly in sql sources.
+ IF(TARGET ${se})
+ TARGET_LINK_LIBRARIES(sql ${se})
+ ENDIF()
+ENDFOREACH()
+
IF(WIN32)
SET(MYSQLD_SOURCE main.cc nt_servc.cc message.rc)
TARGET_LINK_LIBRARIES(sql psapi)
@@ -285,6 +295,9 @@ IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
SET_TARGET_PROPERTIES(mysqld_import_lib PROPERTIES IMPORTED_LOCATION ${MYSQLD_LIB})
ENDIF()
+ADD_LIBRARY( sql_builtins ${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc)
+TARGET_LINK_LIBRARIES(sql_builtins ${MYSQLD_STATIC_PLUGIN_LIBS})
+
MYSQL_ADD_EXECUTABLE(mysqld ${MYSQLD_SOURCE} DESTINATION ${INSTALL_SBINDIR} COMPONENT Server)
IF(APPLE)
@@ -312,7 +325,8 @@ IF(NOT WITHOUT_DYNAMIC_PLUGINS)
ENDIF()
ENDIF(NOT WITHOUT_DYNAMIC_PLUGINS)
-TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE sql)
+TARGET_LINK_LIBRARIES(mysqld LINK_PRIVATE sql sql_builtins)
+
# Provide plugins with minimal set of libraries
SET(INTERFACE_LIBS ${LIBRT})
diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc
index bf721bddb85..19ea40106df 100644
--- a/sql/debug_sync.cc
+++ b/sql/debug_sync.cc
@@ -1451,12 +1451,10 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
if (unlikely(error == ETIMEDOUT || error == ETIME))
{
// We should not make the statement fail, even if in strict mode.
- const bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= false;
+ Abort_on_warning_instant_set aws(thd, false);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DEBUG_SYNC_TIMEOUT,
ER_THD(thd, ER_DEBUG_SYNC_TIMEOUT));
- thd->abort_on_warning= save_abort_on_warning;
DBUG_EXECUTE_IF("debug_sync_abort_on_timeout", DBUG_ASSERT(0););
break;
}
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index dc47ed0b2e1..6783338ab10 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -1061,7 +1061,6 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
Event_basic *etn)
{
bool ret;
- ulonglong saved_mode= thd->variables.sql_mode;
Open_tables_backup open_tables_backup;
TABLE_LIST event_table;
@@ -1072,7 +1071,7 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
event_table.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_EVENT_NAME, 0, TL_READ);
/* Reset sql_mode during data dictionary operations. */
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
/*
We don't use open_event_table() here to make sure that SHOW
@@ -1097,7 +1096,6 @@ Event_db_repository::load_named_event(THD *thd, const LEX_CSTRING *dbname,
close_system_tables(thd, &open_tables_backup);
}
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(ret);
}
diff --git a/sql/field.cc b/sql/field.cc
index 969c32a5180..dbd9a30b244 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1824,9 +1824,9 @@ bool Field::send_binary(Protocol *protocol)
master's field size, @c false otherwise.
*/
bool Field::compatible_field_size(uint field_metadata,
- Relay_log_info *rli_arg __attribute__((unused)),
+ const Relay_log_info *rli_arg __attribute__((unused)),
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
uint const source_size= pack_length_from_metadata(field_metadata);
uint const destination_size= row_pack_length();
@@ -1965,24 +1965,24 @@ void Field::make_send_field(Send_field *field)
{
if (orig_table && orig_table->s->db.str && *orig_table->s->db.str)
{
- field->db_name= orig_table->s->db.str;
+ field->db_name= orig_table->s->db;
if (orig_table->pos_in_table_list &&
orig_table->pos_in_table_list->schema_table)
- field->org_table_name= (orig_table->pos_in_table_list->
- schema_table->table_name);
+ field->org_table_name= Lex_cstring_strlen(orig_table->pos_in_table_list->
+ schema_table->table_name);
else
- field->org_table_name= orig_table->s->table_name.str;
+ field->org_table_name= orig_table->s->table_name;
}
else
- field->org_table_name= field->db_name= "";
+ field->org_table_name= field->db_name= empty_clex_str;
if (orig_table && orig_table->alias.ptr())
{
- field->table_name= orig_table->alias.ptr();
+ field->table_name= orig_table->alias.lex_cstring();
field->org_col_name= field_name;
}
else
{
- field->table_name= "";
+ field->table_name= empty_clex_str;
field->org_col_name= empty_clex_str;
}
field->col_name= field_name;
@@ -2141,11 +2141,9 @@ Field_str::Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg)
{
- field_charset= collation.collation;
+ m_collation= collation;
if (collation.collation->state & MY_CS_BINSORT)
flags|=BINARY_FLAG;
- field_derivation= collation.derivation;
- field_repertoire= collation.repertoire;
}
@@ -2159,7 +2157,7 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const
SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01'
return non-unuque values, e.g. '2001-01-01' and '2001-01-01x'.
*/
- if (!field_charset->coll->propagate(field_charset, 0, 0) ||
+ if (!field_charset()->coll->propagate(field_charset(), 0, 0) ||
item->cmp_type() != STRING_RESULT)
return false;
/*
@@ -2170,8 +2168,8 @@ bool Field_str::test_if_equality_guarantees_uniqueness(const Item *item) const
WHERE latin1_bin_column = _latin1'A' COLLATE latin1_swedish_ci
return non-unique values 'a' and 'A'.
*/
- DTCollation tmp(field_charset, field_derivation, repertoire());
- return !tmp.aggregate(item->collation) && tmp.collation == field_charset;
+ DTCollation tmp(dtcollation());
+ return !tmp.aggregate(item->collation) && tmp.collation == field_charset();
}
@@ -2453,7 +2451,7 @@ bool Field_null::is_equal(const Column_definition &new_field) const
{
DBUG_ASSERT(!compression_method());
return new_field.type_handler() == type_handler() &&
- new_field.charset == field_charset &&
+ new_field.charset == field_charset() &&
new_field.length == max_display_length();
}
@@ -3037,7 +3035,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
5.00 , -1.0, 05, -05, +5 with optional pre/end space
*/
-int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr)
+int Field_decimal::cmp(const uchar *a_ptr,const uchar *b_ptr) const
{
const uchar *end;
int swap=0;
@@ -3416,7 +3414,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
}
-int Field_new_decimal::cmp(const uchar *a,const uchar*b)
+int Field_new_decimal::cmp(const uchar *a,const uchar*b) const
{
return memcmp(a, b, bin_size);
}
@@ -3469,7 +3467,7 @@ int Field_new_decimal::save_field_metadata(uchar *metadata_ptr)
@returns The size of the field based on the field metadata.
*/
-uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
+uint Field_new_decimal::pack_length_from_metadata(uint field_metadata) const
{
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
@@ -3480,9 +3478,9 @@ uint Field_new_decimal::pack_length_from_metadata(uint field_metadata)
bool Field_new_decimal::compatible_field_size(uint field_metadata,
- Relay_log_info * __attribute__((unused)),
+ const Relay_log_info * __attribute__((unused)),
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
uint const source_precision= (field_metadata >> 8U) & 0x00ff;
uint const source_decimal= field_metadata & 0x00ff;
@@ -3738,7 +3736,7 @@ bool Field_tiny::send_binary(Protocol *protocol)
return protocol->store_tiny((longlong) (int8) ptr[0]);
}
-int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_tiny::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
signed char a,b;
a=(signed char) a_ptr[0]; b= (signed char) b_ptr[0];
@@ -3907,7 +3905,7 @@ bool Field_short::send_binary(Protocol *protocol)
}
-int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_short::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
short a,b;
a=sint2korr(a_ptr);
@@ -4100,7 +4098,7 @@ bool Field_medium::send_binary(Protocol *protocol)
}
-int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_medium::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
long a,b;
if (unsigned_flag)
@@ -4278,7 +4276,7 @@ bool Field_long::send_binary(Protocol *protocol)
return protocol->store_long(Field_long::val_int());
}
-int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_long::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -4424,7 +4422,7 @@ bool Field_longlong::send_binary(Protocol *protocol)
}
-int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_longlong::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
longlong a,b;
a=sint8korr(a_ptr);
@@ -4559,7 +4557,7 @@ String *Field_float::val_str(String *val_buffer,
}
-int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_float::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
float a,b;
float4get(a,a_ptr);
@@ -4901,7 +4899,7 @@ bool Field_double::send_binary(Protocol *protocol)
}
-int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_double::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
double a,b;
float8get(a,a_ptr);
@@ -5314,7 +5312,7 @@ bool Field_timestamp::send_binary(Protocol *protocol)
}
-int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_timestamp::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -5510,7 +5508,7 @@ bool Field_timestamp_with_dec::send_binary(Protocol *protocol)
}
-int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_timestamp_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
ulong a_sec_part, b_sec_part;
@@ -5960,7 +5958,7 @@ bool Field_time::send_binary(Protocol *protocol)
}
-int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_time::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=(int32) sint3korr(a_ptr);
@@ -6148,7 +6146,7 @@ bool Field_time_hires::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
}
-int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_time_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
ulonglong a=read_bigendian(a_ptr, Field_time_hires::pack_length());
ulonglong b=read_bigendian(b_ptr, Field_time_hires::pack_length());
@@ -6476,7 +6474,7 @@ String *Field_date::val_str(String *val_buffer,
}
-int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_date::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
int32 a,b;
a=sint4korr(a_ptr);
@@ -6580,7 +6578,7 @@ bool Field_newdate::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_newdate::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
uint32 a,b;
a=(uint32) uint3korr(a_ptr);
@@ -6765,7 +6763,7 @@ bool Field_datetime::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_datetime::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
longlong a,b;
a=sint8korr(a_ptr);
@@ -6867,7 +6865,7 @@ bool Field_datetime_hires::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
}
-int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_datetime_hires::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
ulonglong a=read_bigendian(a_ptr, Field_datetime_hires::pack_length());
ulonglong b=read_bigendian(b_ptr, Field_datetime_hires::pack_length());
@@ -6984,7 +6982,7 @@ Field_longstr::report_if_important_data(const char *pstr, const char *end,
THD *thd= get_thd();
if ((pstr < end) && thd->count_cuted_fields > CHECK_FIELD_EXPRESSION)
{
- if (test_if_important_data(field_charset, pstr, end))
+ if (test_if_important_data(field_charset(), pstr, end))
{
if (thd->abort_on_warning)
set_warning(ER_DATA_TOO_LONG, 1);
@@ -7015,14 +7013,15 @@ int Field_string::store(const char *from, size_t length,CHARSET_INFO *cs)
rc= well_formed_copy_with_check((char*) ptr, field_length,
cs, from, length,
- field_length / field_charset->mbmaxlen,
+ Field_string::char_length(),
false, &copy_length);
/* Append spaces if the string was shorter than the field. */
if (copy_length < field_length)
- field_charset->cset->fill(field_charset,(char*) ptr+copy_length,
- field_length-copy_length,
- field_charset->pad_char);
+ field_charset()->cset->fill(field_charset(),
+ (char*) ptr + copy_length,
+ field_length - copy_length,
+ field_charset()->pad_char);
return rc;
}
@@ -7032,13 +7031,13 @@ int Field_str::store(longlong nr, bool unsigned_val)
{
char buff[64];
uint length;
- length= (uint) (field_charset->cset->longlong10_to_str)(field_charset,
- buff,
- sizeof(buff),
- (unsigned_val ? 10:
- -10),
- nr);
- return store(buff, length, field_charset);
+ length= (uint) (field_charset()->cset->longlong10_to_str)(field_charset(),
+ buff,
+ sizeof(buff),
+ (unsigned_val ? 10:
+ -10),
+ nr);
+ return store(buff, length, field_charset());
}
@@ -7054,8 +7053,7 @@ int Field_str::store(double nr)
{
DBUG_ASSERT(marked_for_write_or_computed());
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
- uint local_char_length= MY_MIN(sizeof(buff),
- field_length / field_charset->mbmaxlen);
+ uint local_char_length= MY_MIN(sizeof(buff), Field_str::char_length());
size_t length= 0;
my_bool error= (local_char_length == 0);
@@ -7078,7 +7076,7 @@ bool Field_string::is_equal(const Column_definition &new_field) const
DBUG_ASSERT(!compression_method());
return new_field.type_handler() == type_handler() &&
new_field.char_length == char_length() &&
- new_field.charset == field_charset &&
+ new_field.charset == field_charset() &&
new_field.length == max_display_length();
}
@@ -7164,7 +7162,7 @@ Field_string::Warn_filter_string::Warn_filter_string(const THD *thd,
const Field_string *field)
:Warn_filter(!thd->no_errors,
!thd->no_errors &&
- field->Field_string::charset() == &my_charset_bin)
+ field->field_charset() == &my_charset_bin)
{ }
@@ -7200,12 +7198,13 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
size_t length;
if (get_thd()->variables.sql_mode &
MODE_PAD_CHAR_TO_FULL_LENGTH)
- length= my_charpos(field_charset, ptr, ptr + field_length,
- field_length / field_charset->mbmaxlen);
+ length= my_charpos(field_charset(), ptr, ptr + field_length,
+ Field_string::char_length());
else
- length= field_charset->cset->lengthsp(field_charset, (const char*) ptr,
- field_length);
- val_ptr->set((const char*) ptr, length, field_charset);
+ length= field_charset()->cset->lengthsp(field_charset(),
+ (const char*) ptr,
+ field_length);
+ val_ptr->set((const char*) ptr, length, field_charset());
return val_ptr;
}
@@ -7225,7 +7224,7 @@ my_decimal *Field_string::val_decimal(my_decimal *decimal_value)
struct Check_field_param {
- Field *field;
+ const Field *field;
};
#ifdef HAVE_REPLICATION
@@ -7244,9 +7243,9 @@ check_field_for_37426(const void *param_arg)
bool
Field_string::compatible_field_size(uint field_metadata,
- Relay_log_info *rli_arg,
+ const Relay_log_info *rli_arg,
uint16 mflags __attribute__((unused)),
- int *order_var)
+ int *order_var) const
{
#ifdef HAVE_REPLICATION
const Check_field_param check_param = { this };
@@ -7258,15 +7257,15 @@ Field_string::compatible_field_size(uint field_metadata,
}
-int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
size_t a_len, b_len;
- if (field_charset->mbmaxlen != 1)
+ if (mbmaxlen() != 1)
{
- size_t char_len= field_length/field_charset->mbmaxlen;
- a_len= my_charpos(field_charset, a_ptr, a_ptr + field_length, char_len);
- b_len= my_charpos(field_charset, b_ptr, b_ptr + field_length, char_len);
+ size_t char_len= Field_string::char_length();
+ a_len= my_charpos(field_charset(), a_ptr, a_ptr + field_length, char_len);
+ b_len= my_charpos(field_charset(), b_ptr, b_ptr + field_length, char_len);
}
else
a_len= b_len= field_length;
@@ -7274,9 +7273,9 @@ int Field_string::cmp(const uchar *a_ptr, const uchar *b_ptr)
We have to remove end space to be able to compare multi-byte-characters
like in latin_de 'ae' and 0xe4
*/
- return field_charset->coll->strnncollsp(field_charset,
- a_ptr, a_len,
- b_ptr, b_len);
+ return field_charset()->coll->strnncollsp(field_charset(),
+ a_ptr, a_len,
+ b_ptr, b_len);
}
@@ -7285,13 +7284,13 @@ void Field_string::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t tmp=
#endif
- field_charset->coll->strnxfrm(field_charset,
- to, length,
- char_length() *
- field_charset->strxfrm_multiply,
- ptr, field_length,
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->coll->strnxfrm(field_charset(),
+ to, length,
+ char_length() *
+ field_charset()->strxfrm_multiply,
+ ptr, field_length,
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(tmp == length);
}
@@ -7319,12 +7318,12 @@ void Field_string::sql_type(String &res) const
uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
{
size_t length= MY_MIN(field_length,max_length);
- size_t local_char_length= max_length/field_charset->mbmaxlen;
+ size_t local_char_length= Field_string::char_length();
DBUG_PRINT("debug", ("Packing field '%s' - length: %zu ", field_name.str,
length));
if (length > local_char_length)
- local_char_length= my_charpos(field_charset, from, from+length,
+ local_char_length= my_charpos(field_charset(), from, from + length,
local_char_length);
set_if_smaller(length, local_char_length);
@@ -7334,13 +7333,14 @@ uchar *Field_string::pack(uchar *to, const uchar *from, uint max_length)
(this is for not packing padding adding bytes in BINARY
fields).
*/
- if (field_charset->mbmaxlen == 1)
+ if (mbmaxlen() == 1)
{
- while (length && from[length-1] == field_charset->pad_char)
+ while (length && from[length-1] == field_charset()->pad_char)
length --;
}
else
- length= field_charset->cset->lengthsp(field_charset, (const char*) from, length);
+ length= field_charset()->cset->lengthsp(field_charset(),
+ (const char*) from, length);
// Length always stored little-endian
*to++= (uchar) length;
@@ -7412,7 +7412,10 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
memcpy(to, from, length);
// Pad the string with the pad character of the fields charset
- field_charset->cset->fill(field_charset, (char*) to + length, field_length - length, field_charset->pad_char);
+ field_charset()->cset->fill(field_charset(),
+ (char*) to + length,
+ field_length - length,
+ field_charset()->pad_char);
return from+length;
}
@@ -7475,13 +7478,15 @@ uint Field_string::max_packed_col_length(uint max_length)
uint Field_string::get_key_image(uchar *buff, uint length, imagetype type_arg)
{
- size_t bytes = my_charpos(field_charset, (char*) ptr,
- (char*) ptr + field_length,
- length / field_charset->mbmaxlen);
+ size_t bytes= my_charpos(field_charset(), (char*) ptr,
+ (char*) ptr + field_length,
+ length / mbmaxlen());
memcpy(buff, ptr, bytes);
if (bytes < length)
- field_charset->cset->fill(field_charset, (char*) buff + bytes,
- length - bytes, field_charset->pad_char);
+ field_charset()->cset->fill(field_charset(),
+ (char*) buff + bytes,
+ length - bytes,
+ field_charset()->pad_char);
return (uint)bytes;
}
@@ -7507,6 +7512,12 @@ Field *Field_string::make_new_field(MEM_ROOT *root, TABLE *new_table,
}
+en_fieldtype Field_string::tmp_engine_column_type(bool use_packed_rows) const
+{
+ return field_length >= MIN_STRING_LENGTH_TO_PACK_ROWS ? FIELD_SKIP_ENDSPACE :
+ FIELD_NORMAL;
+}
+
/****************************************************************************
VARCHAR type
Data in field->ptr is stored as:
@@ -7543,6 +7554,17 @@ int Field_varstring::save_field_metadata(uchar *metadata_ptr)
return 2;
}
+
+bool Field_varstring::memcpy_field_possible(const Field *from) const
+{
+ return (Field_str::memcpy_field_possible(from) &&
+ !compression_method() == !from->compression_method() &&
+ length_bytes == ((Field_varstring*) from)->length_bytes &&
+ (table->file && !(table->file->ha_table_flags() &
+ HA_RECORD_MUST_BE_CLEAN_ON_WRITE)));
+}
+
+
int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
{
DBUG_ASSERT(marked_for_write_or_computed());
@@ -7551,7 +7573,7 @@ int Field_varstring::store(const char *from,size_t length,CHARSET_INFO *cs)
rc= well_formed_copy_with_check((char*) get_data(), field_length,
cs, from, length,
- field_length / field_charset->mbmaxlen,
+ Field_varstring::char_length(),
true, &copy_length);
store_length(copy_length);
@@ -7586,7 +7608,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
DBUG_ASSERT(marked_for_read());
- val_ptr->set((const char*) get_data(), get_length(), field_charset);
+ val_ptr->set((const char*) get_data(), get_length(), field_charset());
return val_ptr;
}
@@ -7606,7 +7628,7 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_len)
+ uint max_len) const
{
uint a_length, b_length;
int diff;
@@ -7623,13 +7645,9 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
}
set_if_smaller(a_length, max_len);
set_if_smaller(b_length, max_len);
- diff= field_charset->coll->strnncollsp(field_charset,
- a_ptr+
- length_bytes,
- a_length,
- b_ptr+
- length_bytes,
- b_length);
+ diff= field_charset()->coll->strnncollsp(field_charset(),
+ a_ptr + length_bytes, a_length,
+ b_ptr + length_bytes, b_length);
return diff;
}
@@ -7639,20 +7657,19 @@ int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
varstring and blob keys are ALWAYS stored with a 2 byte length prefix
*/
-int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
+int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length) const
{
size_t length= length_bytes == 1 ? (uint) *ptr : uint2korr(ptr);
- size_t local_char_length= max_key_length / field_charset->mbmaxlen;
+ size_t local_char_length= max_key_length / mbmaxlen();
- local_char_length= my_charpos(field_charset, ptr + length_bytes,
- ptr + length_bytes + length, local_char_length);
+ local_char_length= my_charpos(field_charset(), ptr + length_bytes,
+ ptr + length_bytes + length, local_char_length);
set_if_smaller(length, local_char_length);
- return field_charset->coll->strnncollsp(field_charset,
- ptr + length_bytes,
- length,
- key_ptr+
- HA_KEY_BLOB_LENGTH,
- uint2korr(key_ptr));
+ return field_charset()->coll->strnncollsp(field_charset(),
+ ptr + length_bytes,
+ length,
+ key_ptr + HA_KEY_BLOB_LENGTH,
+ uint2korr(key_ptr));
}
@@ -7664,13 +7681,13 @@ int Field_varstring::key_cmp(const uchar *key_ptr, uint max_key_length)
(keys are created and compared in key.cc)
*/
-int Field_varstring::key_cmp(const uchar *a,const uchar *b)
+int Field_varstring::key_cmp(const uchar *a,const uchar *b) const
{
- return field_charset->coll->strnncollsp(field_charset,
- a + HA_KEY_BLOB_LENGTH,
- uint2korr(a),
- b + HA_KEY_BLOB_LENGTH,
- uint2korr(b));
+ return field_charset()->coll->strnncollsp(field_charset(),
+ a + HA_KEY_BLOB_LENGTH,
+ uint2korr(a),
+ b + HA_KEY_BLOB_LENGTH,
+ uint2korr(b));
}
@@ -7680,7 +7697,7 @@ void Field_varstring::sort_string(uchar *to,uint length)
val_str(&buf, &buf);
- if (field_charset == &my_charset_bin)
+ if (field_charset() == &my_charset_bin)
{
/* Store length last in high-byte order to sort longer strings first */
if (length_bytes == 1)
@@ -7693,11 +7710,13 @@ void Field_varstring::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
- field_charset->coll->strnxfrm(field_charset, to, length,
- char_length() * field_charset->strxfrm_multiply,
- (const uchar*) buf.ptr(), buf.length(),
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->coll->strnxfrm(field_charset(),
+ to, length,
+ char_length() *
+ field_charset()->strxfrm_multiply,
+ (const uchar*) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(rc == length);
}
@@ -7838,7 +7857,7 @@ uint Field_varstring::get_key_image(uchar *buff, uint length,
val_str(&val, &val);
dbug_tmp_restore_column_map(table->read_set, old_map);
- local_char_length= val.charpos(length / field_charset->mbmaxlen);
+ local_char_length= val.charpos(length / mbmaxlen());
if (local_char_length < val.length())
val.length(local_char_length);
/* Key is always stored with 2 bytes */
@@ -7859,12 +7878,12 @@ uint Field_varstring::get_key_image(uchar *buff, uint length,
void Field_varstring::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff); // Real length is here
- (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset);
+ (void) store((const char*) buff + HA_KEY_BLOB_LENGTH, length, field_charset());
}
int Field_varstring::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
- uint32 max_length)
+ uint32 max_length) const
{
uint32 a_length,b_length;
@@ -7919,7 +7938,7 @@ bool Field_varstring::is_equal(const Column_definition &new_field) const
new_field.length == field_length &&
new_field.char_length == char_length() &&
!new_field.compression_method() == !compression_method() &&
- new_field.charset == field_charset;
+ new_field.charset == field_charset();
}
@@ -7983,10 +8002,10 @@ int Field_longstr::compress(char *to, uint to_length,
uint buf_length;
int rc= 0;
- if (String::needs_conversion_on_storage(length, cs, field_charset) ||
+ if (String::needs_conversion_on_storage(length, cs, field_charset()) ||
max_length < length)
{
- set_if_smaller(max_length, static_cast<ulonglong>(field_charset->mbmaxlen) * length + 1);
+ set_if_smaller(max_length, static_cast<ulonglong>(mbmaxlen()) * length + 1);
if (!(buf= (char*) my_malloc(max_length, MYF(MY_WME))))
{
*out_length= 0;
@@ -8037,7 +8056,7 @@ int Field_longstr::compress(char *to, uint to_length,
*/
String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
- const uchar *from, uint from_length)
+ const uchar *from, uint from_length) const
{
if (from_length)
{
@@ -8046,7 +8065,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
/* Uncompressed data */
if (!method)
{
- val_ptr->set((const char*) from + 1, from_length - 1, field_charset);
+ val_ptr->set((const char*) from + 1, from_length - 1, field_charset());
return val_ptr;
}
@@ -8055,7 +8074,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
if (!compression_methods[method].uncompress(val_buffer, from, from_length,
field_length))
{
- val_buffer->set_charset(field_charset);
+ val_buffer->set_charset(field_charset());
status_var_increment(get_thd()->status_var.column_decompressions);
return val_buffer;
}
@@ -8067,7 +8086,7 @@ String *Field_longstr::uncompress(String *val_buffer, String *val_ptr,
safer route, let's return a zero string and let the general
handler catch the error.
*/
- val_ptr->set("", 0, field_charset);
+ val_ptr->set("", 0, field_charset());
return val_ptr;
}
@@ -8099,7 +8118,7 @@ double Field_varstring_compressed::val_real(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
@@ -8110,13 +8129,13 @@ longlong Field_varstring_compressed::val_int(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_len)
+ uint max_len) const
{
String a, b;
uint a_length, b_length;
@@ -8140,7 +8159,7 @@ int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
if (b.length() > max_len)
b.length(max_len);
- return sortcmp(&a, &b, field_charset);
+ return sortcmp(&a, &b, field_charset());
}
@@ -8185,7 +8204,7 @@ uint32 Field_blob::get_length(const uchar *pos, uint packlength_arg) const
*/
int Field_blob::copy_value(Field_blob *from)
{
- DBUG_ASSERT(field_charset == from->charset());
+ DBUG_ASSERT(field_charset() == from->charset());
DBUG_ASSERT(!compression_method() == !from->compression_method());
int rc= 0;
uint32 length= from->get_length();
@@ -8193,7 +8212,7 @@ int Field_blob::copy_value(Field_blob *from)
if (packlength < from->packlength)
{
set_if_smaller(length, Field_blob::max_data_length());
- length= (uint32) Well_formed_prefix(field_charset,
+ length= (uint32) Well_formed_prefix(field_charset(),
(const char *) data, length).length();
rc= report_if_important_data((const char *) data + length,
(const char *) data + from->get_length(),
@@ -8230,7 +8249,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
if (table && table->blob_storage) // GROUP_CONCAT with ORDER BY | DISTINCT
{
DBUG_ASSERT(!f_is_hex_escape(flags));
- DBUG_ASSERT(field_charset == cs);
+ DBUG_ASSERT(field_charset() == cs);
DBUG_ASSERT(length <= max_data_length());
new_length= length;
@@ -8261,7 +8280,7 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
If content of the 'from'-address is cached in the 'value'-object
it is possible that the content needs a character conversion.
*/
- if (!String::needs_conversion_on_storage(length, cs, field_charset))
+ if (!String::needs_conversion_on_storage(length, cs, field_charset()))
{
Field_blob::store_length(length);
bmove(ptr + packlength, &from, sizeof(char*));
@@ -8272,14 +8291,14 @@ int Field_blob::store(const char *from,size_t length,CHARSET_INFO *cs)
from= tmpstr.ptr();
}
- new_length= MY_MIN(max_data_length(), field_charset->mbmaxlen * length);
+ new_length= MY_MIN(max_data_length(), mbmaxlen() * length);
if (value.alloc(new_length))
goto oom_error;
tmp= const_cast<char*>(value.ptr());
if (f_is_hex_escape(flags))
{
- copy_length= my_copy_with_hex_escaping(field_charset,
+ copy_length= my_copy_with_hex_escaping(field_charset(),
tmp, new_length,
from, length);
Field_blob::store_length(copy_length);
@@ -8367,15 +8386,15 @@ my_decimal *Field_blob::val_decimal(my_decimal *decimal_value)
int Field_blob::cmp(const uchar *a,uint32 a_length, const uchar *b,
- uint32 b_length)
+ uint32 b_length) const
{
- return field_charset->coll->strnncollsp(field_charset,
- a, a_length, b, b_length);
+ return field_charset()->coll->strnncollsp(field_charset(),
+ a, a_length, b, b_length);
}
int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
- uint max_length)
+ uint max_length) const
{
uchar *blob1,*blob2;
memcpy(&blob1, a_ptr+packlength, sizeof(char*));
@@ -8388,7 +8407,7 @@ int Field_blob::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
- uint32 max_length)
+ uint32 max_length) const
{
char *a,*b;
uint diff;
@@ -8408,43 +8427,12 @@ int Field_blob::cmp_binary(const uchar *a_ptr, const uchar *b_ptr,
/* The following is used only when comparing a key */
-uint Field_blob::get_key_image(uchar *buff,uint length, imagetype type_arg)
+uint Field_blob::get_key_image_itRAW(uchar *buff, uint length)
{
size_t blob_length= get_length(ptr);
- uchar *blob;
-
-#ifdef HAVE_SPATIAL
- if (type_arg == itMBR)
- {
- const char *dummy;
- MBR mbr;
- Geometry_buffer buffer;
- Geometry *gobj;
- const uint image_length= SIZEOF_STORED_DOUBLE*4;
-
- if (blob_length < SRID_SIZE)
- {
- bzero(buff, image_length);
- return image_length;
- }
- blob= get_ptr();
- gobj= Geometry::construct(&buffer, (char*) blob, (uint32)blob_length);
- if (!gobj || gobj->get_mbr(&mbr, &dummy))
- bzero(buff, image_length);
- else
- {
- float8store(buff, mbr.xmin);
- float8store(buff+8, mbr.xmax);
- float8store(buff+16, mbr.ymin);
- float8store(buff+24, mbr.ymax);
- }
- return image_length;
- }
-#endif /*HAVE_SPATIAL*/
-
- blob= get_ptr();
- size_t local_char_length= length / field_charset->mbmaxlen;
- local_char_length= my_charpos(field_charset, blob, blob + blob_length,
+ uchar *blob= get_ptr();
+ size_t local_char_length= length / mbmaxlen();
+ local_char_length= my_charpos(field_charset(), blob, blob + blob_length,
local_char_length);
set_if_smaller(blob_length, local_char_length);
@@ -8467,11 +8455,11 @@ void Field_blob::set_key_image(const uchar *buff,uint length)
{
length= uint2korr(buff);
(void) Field_blob::store((const char*) buff+HA_KEY_BLOB_LENGTH, length,
- field_charset);
+ field_charset());
}
-int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
+int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length) const
{
uchar *blob1;
size_t blob_length=get_length(ptr);
@@ -8486,7 +8474,7 @@ int Field_blob::key_cmp(const uchar *key_ptr, uint max_key_length)
uint2korr(key_ptr));
}
-int Field_blob::key_cmp(const uchar *a,const uchar *b)
+int Field_blob::key_cmp(const uchar *a,const uchar *b) const
{
return Field_blob::cmp(a+HA_KEY_BLOB_LENGTH, uint2korr(a),
b+HA_KEY_BLOB_LENGTH, uint2korr(b));
@@ -8529,7 +8517,7 @@ int Field_blob::save_field_metadata(uchar *metadata_ptr)
uint32 Field_blob::sort_length() const
{
return (uint32) (get_thd()->variables.max_sort_length +
- (field_charset == &my_charset_bin ? 0 : packlength));
+ (field_charset() == &my_charset_bin ? 0 : packlength));
}
@@ -8538,11 +8526,11 @@ void Field_blob::sort_string(uchar *to,uint length)
String buf;
val_str(&buf, &buf);
- if (!buf.length() && field_charset->pad_char == 0)
+ if (!buf.length() && field_charset()->pad_char == 0)
bzero(to,length);
else
{
- if (field_charset == &my_charset_bin)
+ if (field_charset() == &my_charset_bin)
{
/*
Store length of blob last in blob to shorter blobs before longer blobs
@@ -8554,10 +8542,10 @@ void Field_blob::sort_string(uchar *to,uint length)
#ifdef DBUG_ASSERT_EXISTS
size_t rc=
#endif
- field_charset->coll->strnxfrm(field_charset, to, length, length,
- (const uchar*) buf.ptr(), buf.length(),
- MY_STRXFRM_PAD_WITH_SPACE |
- MY_STRXFRM_PAD_TO_MAXLEN);
+ field_charset()->coll->strnxfrm(field_charset(), to, length, length,
+ (const uchar*) buf.ptr(), buf.length(),
+ MY_STRXFRM_PAD_WITH_SPACE |
+ MY_STRXFRM_PAD_TO_MAXLEN);
DBUG_ASSERT(rc == length);
}
}
@@ -8692,7 +8680,7 @@ bool Field_blob::is_equal(const Column_definition &new_field) const
return new_field.type_handler() == type_handler() &&
!new_field.compression_method() == !compression_method() &&
new_field.pack_length == pack_length() &&
- new_field.charset == field_charset;
+ new_field.charset == field_charset();
}
@@ -8728,8 +8716,7 @@ int Field_blob_compressed::store(const char *from, size_t length,
DBUG_ASSERT(marked_for_write_or_computed());
uint compressed_length;
uint max_length= max_data_length();
- uint to_length= (uint) MY_MIN(max_length,
- field_charset->mbmaxlen * length + 1);
+ uint to_length= (uint) MY_MIN(max_length, mbmaxlen() * length + 1);
String tmp(from, length, cs);
int rc;
@@ -8763,7 +8750,7 @@ double Field_blob_compressed::val_real(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntod_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
@@ -8774,277 +8761,11 @@ longlong Field_blob_compressed::val_int(void)
THD *thd= get_thd();
String buf;
val_str(&buf, &buf);
- return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset,
+ return Converter_strntoll_with_warn(thd, Warn_filter(thd), field_charset(),
buf.ptr(), buf.length()).result();
}
-#ifdef HAVE_SPATIAL
-/* Values 1-40 reserved for 1-byte options,
- 41-80 for 2-byte options,
- 81-120 for 4-byte options,
- 121-160 for 8-byte options,
- other - varied length in next 1-3 bytes.
-*/
-enum extra2_gis_field_options {
- FIELDGEOM_END=0,
- FIELDGEOM_STORAGE_MODEL=1,
- FIELDGEOM_PRECISION=2,
- FIELDGEOM_SCALE=3,
- FIELDGEOM_SRID=81,
-};
-
-
-uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields)
-{
- uint image_size= 0;
- List_iterator<Create_field> it(create_fields);
- Create_field *field;
- while ((field= it++))
- {
- if (field->real_field_type() != MYSQL_TYPE_GEOMETRY)
- continue;
- if (buff)
- {
- uchar *cbuf= buff + image_size;
-
- cbuf[0]= FIELDGEOM_STORAGE_MODEL;
- cbuf[1]= (uchar) Field_geom::GEOM_STORAGE_WKB;
-
- cbuf[2]= FIELDGEOM_PRECISION;
- cbuf[3]= (uchar) field->length;
-
- cbuf[4]= FIELDGEOM_SCALE;
- cbuf[5]= (uchar) field->decimals;
-
- cbuf[6]= FIELDGEOM_SRID;
- int4store(cbuf + 7, ((uint32) field->srid));
-
- cbuf[11]= FIELDGEOM_END;
- }
- image_size+= 12;
- }
-
- return image_size;
-}
-
-
-uint gis_field_options_read(const uchar *buf, size_t buf_len,
- Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid)
-{
- const uchar *buf_end= buf + buf_len;
- const uchar *cbuf= buf;
- int option_id;
-
- *precision= *scale= *srid= 0;
- *st_type= Field_geom::GEOM_STORAGE_WKB;
-
- if (!buf) /* can only happen with the old FRM file */
- goto end_of_record;
-
- while (cbuf < buf_end)
- {
- switch ((option_id= *(cbuf++)))
- {
- case FIELDGEOM_STORAGE_MODEL:
- *st_type= (Field_geom::storage_type) cbuf[0];
- break;
- case FIELDGEOM_PRECISION:
- *precision= cbuf[0];
- break;
- case FIELDGEOM_SCALE:
- *scale= cbuf[0];
- break;
- case FIELDGEOM_SRID:
- *srid= uint4korr(cbuf);
- break;
- case FIELDGEOM_END:
- goto end_of_record;
- }
- if (option_id > 0 && option_id <= 40)
- cbuf+= 1;
- else if (option_id > 40 && option_id <= 80)
- cbuf+= 2;
- else if (option_id > 80 && option_id <= 120)
- cbuf+= 4;
- else if (option_id > 120 && option_id <= 160)
- cbuf+= 8;
- else /* > 160 and <=255 */
- cbuf+= cbuf[0] ? 1 + cbuf[0] : 3 + uint2korr(cbuf+1);
- }
-
-end_of_record:
- return (uint)(cbuf - buf);
-}
-
-
-
-void Field_geom::sql_type(String &res) const
-{
- CHARSET_INFO *cs= &my_charset_latin1;
- switch (geom_type)
- {
- case GEOM_POINT:
- res.set(STRING_WITH_LEN("point"), cs);
- break;
- case GEOM_LINESTRING:
- res.set(STRING_WITH_LEN("linestring"), cs);
- break;
- case GEOM_POLYGON:
- res.set(STRING_WITH_LEN("polygon"), cs);
- break;
- case GEOM_MULTIPOINT:
- res.set(STRING_WITH_LEN("multipoint"), cs);
- break;
- case GEOM_MULTILINESTRING:
- res.set(STRING_WITH_LEN("multilinestring"), cs);
- break;
- case GEOM_MULTIPOLYGON:
- res.set(STRING_WITH_LEN("multipolygon"), cs);
- break;
- case GEOM_GEOMETRYCOLLECTION:
- res.set(STRING_WITH_LEN("geometrycollection"), cs);
- break;
- default:
- res.set(STRING_WITH_LEN("geometry"), cs);
- }
-}
-
-
-int Field_geom::store(double nr)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store(longlong nr, bool unsigned_val)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store_decimal(const my_decimal *)
-{
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
- return -1;
-}
-
-
-int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
-{
- if (!length)
- bzero(ptr, Field_blob::pack_length());
- else
- {
- if (from == Geometry::bad_geometry_data.ptr())
- goto err;
- // Check given WKB
- uint32 wkb_type;
- if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
- goto err;
- wkb_type= uint4korr(from + SRID_SIZE + 1);
- if (wkb_type < (uint32) Geometry::wkb_point ||
- wkb_type > (uint32) Geometry::wkb_last)
- goto err;
-
- if (geom_type != Field::GEOM_GEOMETRY &&
- geom_type != Field::GEOM_GEOMETRYCOLLECTION &&
- (uint32) geom_type != wkb_type)
- {
- const char *db= table->s->db.str;
- const char *tab_name= table->s->table_name.str;
-
- if (!db)
- db= "";
- if (!tab_name)
- tab_name= "";
-
- my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
- Geometry::ci_collection[geom_type]->m_name.str,
- Geometry::ci_collection[wkb_type]->m_name.str,
- db, tab_name, field_name.str,
- (ulong) table->in_use->get_stmt_da()->
- current_row_for_warning());
- goto err_exit;
- }
-
- Field_blob::store_length(length);
- if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
- from != value.ptr())
- { // Must make a copy
- value.copy(from, length, cs);
- from= value.ptr();
- }
- bmove(ptr + packlength, &from, sizeof(char*));
- }
- return 0;
-
-err:
- my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
- ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
-err_exit:
- bzero(ptr, Field_blob::pack_length());
- return -1;
-}
-
-Field::geometry_type Field_geom::geometry_type_merge(geometry_type a,
- geometry_type b)
-{
- if (a == b)
- return a;
- return Field::GEOM_GEOMETRY;
-}
-
-
-bool Field_geom::is_equal(const Column_definition &new_field) const
-{
- return new_field.type_handler() == type_handler() &&
- /*
- - Allow ALTER..INPLACE to supertype (GEOMETRY),
- e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
- - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
- */
- (new_field.geom_type == geom_type ||
- new_field.geom_type == GEOM_GEOMETRY);
-}
-
-
-bool Field_geom::can_optimize_range(const Item_bool_func *cond,
- const Item *item,
- bool is_eq_func) const
-{
- return item->cmp_type() == STRING_RESULT;
-}
-
-
-bool Field_geom::load_data_set_no_data(THD *thd, bool fixed_format)
-{
- return Field_geom::load_data_set_null(thd);
-}
-
-
-bool Field_geom::load_data_set_null(THD *thd)
-{
- Field_blob::reset();
- if (!maybe_null())
- {
- my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field_name.str,
- thd->get_stmt_da()->current_row_for_warning());
- return true;
- }
- set_null();
- set_has_explicit_value(); // Do not auto-update this field
- return false;
-}
-
-
-#endif /*HAVE_SPATIAL*/
-
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
@@ -9082,17 +8803,17 @@ int Field_enum::store(const char *from,size_t length,CHARSET_INFO *cs)
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion_on_storage(length, cs, field_charset))
+ if (String::needs_conversion_on_storage(length, cs, field_charset()))
{
uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
+ tmpstr.copy(from, length, cs, field_charset(), &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
/* Remove end space */
- length= (uint)field_charset->cset->lengthsp(field_charset, from, length);
- uint tmp=find_type2(typelib, from, length, field_charset);
+ length= (uint)field_charset()->cset->lengthsp(field_charset(), from, length);
+ uint tmp=find_type2(typelib, from, length, field_charset());
if (!tmp)
{
if (length < 6) // Can't be more than 99999 enums
@@ -9153,9 +8874,13 @@ double Field_enum::val_real(void)
longlong Field_enum::val_int(void)
{
DBUG_ASSERT(marked_for_read());
- return read_lowendian(ptr, packlength);
+ return val_int(ptr);
}
+longlong Field_enum::val_int(const uchar *real_ptr) const
+{
+ return read_lowendian(real_ptr, packlength);
+}
/**
Save the field metadata for enum fields.
@@ -9181,22 +8906,18 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
{
uint tmp=(uint) Field_enum::val_int();
if (!tmp || tmp > typelib->count)
- val_ptr->set("", 0, field_charset);
+ val_ptr->set("", 0, field_charset());
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
typelib->type_lengths[tmp-1],
- field_charset);
+ field_charset());
return val_ptr;
}
-int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr)
+int Field_enum::cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
- uchar *old= ptr;
- ptr= (uchar*) a_ptr;
- ulonglong a=Field_enum::val_int();
- ptr= (uchar*) b_ptr;
- ulonglong b=Field_enum::val_int();
- ptr= old;
+ ulonglong a=Field_enum::val_int(a_ptr);
+ ulonglong b=Field_enum::val_int(b_ptr);
return (a < b) ? -1 : (a > b) ? 1 : 0;
}
@@ -9268,14 +8989,14 @@ int Field_set::store(const char *from,size_t length,CHARSET_INFO *cs)
String tmpstr(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if necessary */
- if (String::needs_conversion_on_storage(length, cs, field_charset))
+ if (String::needs_conversion_on_storage(length, cs, field_charset()))
{
uint dummy_errors;
- tmpstr.copy(from, length, cs, field_charset, &dummy_errors);
+ tmpstr.copy(from, length, cs, field_charset(), &dummy_errors);
from= tmpstr.ptr();
length= tmpstr.length();
}
- ulonglong tmp= find_set(typelib, from, length, field_charset,
+ ulonglong tmp= find_set(typelib, from, length, field_charset(),
&not_used, &not_used2, &got_warning);
if (!tmp && length && length < 22)
{
@@ -9335,7 +9056,7 @@ String *Field_set::val_str(String *val_buffer,
return val_buffer;
}
- val_buffer->set_charset(field_charset);
+ val_buffer->set_charset(field_charset());
val_buffer->length(0);
while (tmp && bitnr < (uint) typelib->count)
@@ -9346,7 +9067,7 @@ String *Field_set::val_str(String *val_buffer,
val_buffer->append(&field_separator, 1, &my_charset_latin1);
String str(typelib->type_names[bitnr],
typelib->type_lengths[bitnr],
- field_charset);
+ field_charset());
val_buffer->append(str);
}
tmp>>=1;
@@ -9401,7 +9122,8 @@ bool Field::eq_def(const Field *field) const
@return TRUE if the type names of t1 match those of t2. FALSE otherwise.
*/
-static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2)
+static bool compare_type_names(CHARSET_INFO *charset, const TYPELIB *t1,
+ const TYPELIB *t2)
{
for (uint i= 0; i < t1->count; i++)
if (my_strnncoll(charset,
@@ -9420,7 +9142,7 @@ static bool compare_type_names(CHARSET_INFO *charset, TYPELIB *t1, TYPELIB *t2)
bool Field_enum::eq_def(const Field *field) const
{
- TYPELIB *values;
+ const TYPELIB *values;
if (!Field::eq_def(field))
return FALSE;
@@ -9431,7 +9153,7 @@ bool Field_enum::eq_def(const Field *field) const
if (typelib->count != values->count)
return FALSE;
- return compare_type_names(field_charset, typelib, values);
+ return compare_type_names(field_charset(), typelib, values);
}
@@ -9446,14 +9168,14 @@ bool Field_enum::eq_def(const Field *field) const
bool Field_enum::is_equal(const Column_definition &new_field) const
{
- TYPELIB *values= new_field.interval;
+ const TYPELIB *values= new_field.interval;
/*
The fields are compatible if they have the same flags,
type, charset and have the same underlying length.
*/
if (new_field.type_handler() != type_handler() ||
- new_field.charset != field_charset ||
+ new_field.charset != field_charset() ||
new_field.pack_length != pack_length())
return false;
@@ -9466,7 +9188,7 @@ bool Field_enum::is_equal(const Column_definition &new_field) const
return false;
/* Check whether there are modification before the end. */
- if (! compare_type_names(field_charset, typelib, new_field.interval))
+ if (! compare_type_names(field_charset(), typelib, new_field.interval))
return false;
return true;
@@ -9628,6 +9350,14 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
}
+const DTCollation & Field_bit::dtcollation() const
+{
+ static DTCollation tmp(&my_charset_bin,
+ DERIVATION_IMPLICIT, MY_REPERTOIRE_UNICODE30);
+ return tmp;
+}
+
+
void Field_bit::hash(ulong *nr, ulong *nr2)
{
if (is_null())
@@ -9836,7 +9566,7 @@ my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
The a and b pointer must be pointers to the field in a record
(not the table->record[0] necessarily)
*/
-int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
+int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len) const
{
my_ptrdiff_t a_diff= a - ptr;
my_ptrdiff_t b_diff= b - ptr;
@@ -9854,7 +9584,7 @@ int Field_bit::cmp_max(const uchar *a, const uchar *b, uint max_len)
}
-int Field_bit::key_cmp(const uchar *str, uint length)
+int Field_bit::key_cmp(const uchar *str, uint length) const
{
if (bit_len)
{
@@ -9936,7 +9666,7 @@ int Field_bit::save_field_metadata(uchar *metadata_ptr)
@returns The size of the field based on the field metadata.
*/
-uint Field_bit::pack_length_from_metadata(uint field_metadata)
+uint Field_bit::pack_length_from_metadata(uint field_metadata) const
{
uint const from_len= (field_metadata >> 8U) & 0x00ff;
uint const from_bit_len= field_metadata & 0x00ff;
@@ -9947,9 +9677,9 @@ uint Field_bit::pack_length_from_metadata(uint field_metadata)
bool
Field_bit::compatible_field_size(uint field_metadata,
- Relay_log_info * __attribute__((unused)),
+ const Relay_log_info * __attribute__((unused)),
uint16 mflags,
- int *order_var)
+ int *order_var) const
{
DBUG_ENTER("Field_bit::compatible_field_size");
DBUG_ASSERT((field_metadata >> 16) == 0);
@@ -10179,7 +9909,8 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
{
DBUG_ENTER("Column_definition::create_interval_from_interval_list");
DBUG_ASSERT(!interval);
- if (!(interval= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB))))
+ TYPELIB *tmpint;
+ if (!(interval= tmpint= (TYPELIB*) alloc_root(mem_root, sizeof(TYPELIB))))
DBUG_RETURN(true); // EOM
List_iterator<String> it(interval_list);
@@ -10193,17 +9924,17 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
DBUG_ASSERT(comma_length >= 0 && comma_length <= (int) sizeof(comma_buf));
if (!multi_alloc_root(mem_root,
- &interval->type_names,
+ &tmpint->type_names,
sizeof(char*) * (interval_list.elements + 1),
- &interval->type_lengths,
+ &tmpint->type_lengths,
sizeof(uint) * (interval_list.elements + 1),
NullS))
goto err; // EOM
- interval->name= "";
- interval->count= interval_list.elements;
+ tmpint->name= "";
+ tmpint->count= interval_list.elements;
- for (uint i= 0; i < interval->count; i++)
+ for (uint i= 0; i < interval_list.elements; i++)
{
uint32 dummy;
String *tmp= it++;
@@ -10241,11 +9972,11 @@ bool Column_definition::create_interval_from_interval_list(MEM_ROOT *mem_root,
goto err;
}
}
- interval->type_names[i]= value.str;
- interval->type_lengths[i]= (uint)value.length;
+ tmpint->type_names[i]= value.str;
+ tmpint->type_lengths[i]= (uint)value.length;
}
- interval->type_names[interval->count]= 0; // End marker
- interval->type_lengths[interval->count]= 0;
+ tmpint->type_names[interval_list.elements]= 0; // End marker
+ tmpint->type_lengths[interval_list.elements]= 0;
interval_list.empty(); // Don't need interval_list anymore
DBUG_RETURN(false);
err:
@@ -10356,7 +10087,7 @@ void Column_definition::create_length_to_internal_length_newdecimal()
}
-bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
+bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name,
enum_vcol_info_type type)
{
@@ -10690,7 +10421,6 @@ Column_definition_attributes::Column_definition_attributes(const Field *field)
interval(NULL),
charset(field->charset()), // May be NULL ptr
srid(0),
- geom_type(Field::GEOM_GEOMETRY),
pack_flag(0)
{}
@@ -10922,6 +10652,19 @@ Column_definition::set_compressed_deprecated_column_attribute(THD *thd,
}
+bool Column_definition::check_vcol_for_key(THD *thd) const
+{
+ if (vcol_info && (vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC))
+ {
+ /* use check_expression() to report an error */
+ check_expression(vcol_info, &field_name, VCOL_GENERATED_STORED);
+ DBUG_ASSERT(thd->is_error());
+ return true;
+ }
+ return false;
+}
+
+
Send_field::Send_field(THD *thd, Item *item)
{
item->make_send_field(thd, this);
@@ -10941,11 +10684,11 @@ uint32 Field_blob::max_display_length() const
switch (packlength)
{
case 1:
- return 255 * field_charset->mbmaxlen;
+ return 255 * mbmaxlen();
case 2:
- return 65535 * field_charset->mbmaxlen;
+ return 65535 * mbmaxlen();
case 3:
- return 16777215 * field_charset->mbmaxlen;
+ return 16777215 * mbmaxlen();
case 4:
return (uint32) UINT_MAX32;
default:
@@ -11203,8 +10946,7 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc= false;
THD *thd= get_thd();
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
val_str(&str);
if (!(to->length= str.length()))
@@ -11212,7 +10954,6 @@ bool Field::val_str_nopad(MEM_ROOT *mem_root, LEX_CSTRING *to)
else if ((rc= !(to->str= strmake_root(mem_root, str.ptr(), str.length()))))
to->length= 0;
- thd->variables.sql_mode= sql_mode_backup;
return rc;
}
@@ -11230,7 +10971,7 @@ void Field_string::print_key_value(String *out, uint32 length)
{
if (charset() == &my_charset_bin)
{
- size_t len= field_charset->cset->lengthsp(field_charset, (const char*) ptr, length);
+ size_t len= field_charset()->cset->lengthsp(field_charset(), (const char*) ptr, length);
print_key_value_binary(out, ptr, static_cast<uint32>(len));
}
else
diff --git a/sql/field.h b/sql/field.h
index 79bc55d2323..58bac152ea2 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -60,6 +60,45 @@ enum enum_check_fields
CHECK_FIELD_ERROR_FOR_NULL,
};
+
+enum enum_conv_type
+{
+ CONV_TYPE_PRECISE,
+ CONV_TYPE_VARIANT,
+ CONV_TYPE_SUBSET_TO_SUPERSET,
+ CONV_TYPE_SUPERSET_TO_SUBSET,
+ CONV_TYPE_IMPOSSIBLE
+};
+
+
+class Conv_param
+{
+ uint16 m_table_def_flags;
+public:
+ Conv_param(uint16 table_def_flags)
+ :m_table_def_flags(table_def_flags)
+ { }
+ uint16 table_def_flags() const { return m_table_def_flags; }
+};
+
+
+class Conv_source: public Type_handler_hybrid_field_type
+{
+ uint16 m_metadata;
+ CHARSET_INFO *m_cs;
+public:
+ Conv_source(const Type_handler *h, uint16 metadata, CHARSET_INFO *cs)
+ :Type_handler_hybrid_field_type(h),
+ m_metadata(metadata),
+ m_cs(cs)
+ {
+ DBUG_ASSERT(cs);
+ }
+ uint16 metadata() const { return m_metadata; }
+ uint mbmaxlen() const { return m_cs->mbmaxlen; }
+};
+
+
/*
Common declarations for Field and Item
*/
@@ -410,7 +449,7 @@ public:
{ // Use this when an item is [a part of] a boolean expression
public:
Context_boolean()
- :Context(ANY_SUBST, &type_handler_longlong, &my_charset_bin) { }
+ :Context(ANY_SUBST, &type_handler_slonglong, &my_charset_bin) { }
};
};
@@ -682,12 +721,6 @@ public:
TIMESTAMP_DNUN_FIELD=23, // TIMESTAMP DEFAULT NOW() ON UPDATE NOW()
TMYSQL_COMPRESSED= 24, // Compatibility with TMySQL
};
- enum geometry_type
- {
- GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3,
- GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6,
- GEOM_GEOMETRYCOLLECTION = 7
- };
enum imagetype { itRAW, itMBR};
utype unireg_check;
@@ -748,15 +781,13 @@ public:
const LEX_CSTRING *field_name_arg);
virtual ~Field() {}
- DTCollation dtcollation() const
+ virtual Type_numeric_attributes type_numeric_attributes() const
{
- return DTCollation(charset(), derivation(), repertoire());
+ return Type_numeric_attributes(field_length, decimals(), is_unsigned());
}
- virtual Type_std_attributes type_std_attributes() const
+ Type_std_attributes type_std_attributes() const
{
- return Type_std_attributes(field_length, decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_std_attributes(type_numeric_attributes(), dtcollation());
}
bool is_unsigned() const { return flags & UNSIGNED_FLAG; }
@@ -910,9 +941,9 @@ public:
table, which is located on disk).
*/
virtual uint32 pack_length_in_rec() const { return pack_length(); }
- virtual bool compatible_field_size(uint metadata, Relay_log_info *rli,
- uint16 mflags, int *order);
- virtual uint pack_length_from_metadata(uint field_metadata)
+ virtual bool compatible_field_size(uint metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order) const;
+ virtual uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_ENTER("Field::pack_length_from_metadata");
DBUG_RETURN(field_metadata);
@@ -1025,6 +1056,8 @@ public:
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
+ virtual uint16 key_part_flag() const { return 0; }
+ virtual uint16 key_part_length_bytes() const { return 0; }
virtual uint32 key_length() const { return pack_length(); }
virtual const Type_handler *type_handler() const= 0;
virtual enum_field_types type() const
@@ -1083,19 +1116,34 @@ public:
*/
return type();
}
+ virtual en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ return FIELD_NORMAL;
+ }
+ /*
+ Conversion type for from the source to the current field.
+ */
+ virtual enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+ const= 0;
+ enum_conv_type rpl_conv_type_from_same_data_type(uint16 metadata,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+ const;
inline int cmp(const uchar *str) { return cmp(ptr,str); }
- virtual int cmp_max(const uchar *a, const uchar *b, uint max_len)
+ virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) const
{ return cmp(a, b); }
- virtual int cmp(const uchar *,const uchar *)=0;
- virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U)
+ virtual int cmp(const uchar *,const uchar *) const=0;
+ virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const
{ return memcmp(a,b,pack_length()); }
virtual int cmp_offset(my_ptrdiff_t row_offset)
{ return cmp(ptr,ptr+row_offset); }
virtual int cmp_binary_offset(uint row_offset)
{ return cmp_binary(ptr, ptr+row_offset); };
- virtual int key_cmp(const uchar *a,const uchar *b)
+ virtual int key_cmp(const uchar *a,const uchar *b) const
{ return cmp(a, b); }
- virtual int key_cmp(const uchar *str, uint length)
+ virtual int key_cmp(const uchar *str, uint length) const
{ return cmp(ptr,str); }
/*
Update the value m of the 'min_val' field with the current value v
@@ -1142,6 +1190,8 @@ public:
{
return Information_schema_character_attributes();
}
+ virtual void update_data_type_statistics(Data_type_statistics *st) const
+ { }
/*
Caller beware: sql_type can change str.Ptr, so check
ptr() to see if it changed if you are using your own buffer
@@ -1371,15 +1421,13 @@ public:
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
virtual bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- virtual TYPELIB *get_typelib() const { return NULL; }
- virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
+ virtual const TYPELIB *get_typelib() const { return NULL; }
+ virtual CHARSET_INFO *charset(void) const= 0;
+ virtual const DTCollation &dtcollation() const= 0;
virtual CHARSET_INFO *charset_for_protocol(void) const
{ return binary() ? &my_charset_bin : charset(); }
virtual CHARSET_INFO *sort_charset(void) const { return charset(); }
virtual bool has_charset(void) const { return FALSE; }
- virtual enum Derivation derivation(void) const
- { return DERIVATION_IMPLICIT; }
- virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; }
virtual int set_time() { return 1; }
bool set_warning(Sql_condition::enum_warning_level, unsigned int code,
int cuted_increment, ulong current_row=0) const;
@@ -1531,12 +1579,6 @@ public:
{
return field_length / charset()->mbmaxlen;
}
- virtual geometry_type get_geometry_type() const
- {
- /* shouldn't get here. */
- DBUG_ASSERT(0);
- return GEOM_GEOMETRY;
- }
ha_storage_media field_storage_type() const
{
@@ -1780,9 +1822,14 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const LEX_CSTRING *field_name_arg,
uint8 dec_arg, bool zero_arg, bool unsigned_arg);
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
+ CHARSET_INFO *charset(void) const
+ {
+ return DTCollation_numeric::singleton().collation;
+ }
+ const DTCollation &dtcollation() const
+ {
+ return DTCollation_numeric::singleton();
+ }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item)
{
return (flags & ZEROFILL_FLAG) ?
@@ -1807,7 +1854,8 @@ public:
}
bool is_equal(const Column_definition &new_field) const;
uint row_pack_length() const { return pack_length(); }
- uint32 pack_length_from_metadata(uint field_metadata) {
+ uint32 pack_length_from_metadata(uint field_metadata) const
+ {
uint32 length= pack_length();
DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u",
field_metadata, length));
@@ -1825,10 +1873,10 @@ public:
class Field_str :public Field {
protected:
- // TODO-10.2: Reuse DTCollation instead of these three members
- CHARSET_INFO *field_charset;
- enum Derivation field_derivation;
- uint field_repertoire;
+ DTCollation m_collation;
+ // A short alias for m_collation.collation with non-virtual linkage
+ const CHARSET_INFO *field_charset() const { return m_collation.collation; }
+ uint mbmaxlen() const { return m_collation.collation->mbmaxlen; }
public:
bool can_be_substituted_to_equal_item(const Context &ctx,
const Item_equal *item_equal);
@@ -1852,13 +1900,18 @@ public:
{
return store(str, length, &my_charset_bin);
}
- uint repertoire(void) const { return field_repertoire; }
- CHARSET_INFO *charset(void) const { return field_charset; }
- enum Derivation derivation(void) const { return field_derivation; }
- bool binary() const { return field_charset == &my_charset_bin; }
+ CHARSET_INFO *charset(void) const { return m_collation.collation; }
+ const DTCollation &dtcollation() const
+ {
+ return m_collation;
+ }
+ bool binary() const { return field_charset() == &my_charset_bin; }
uint32 max_display_length() const { return field_length; }
uint32 character_octet_length() const { return field_length; }
- uint32 char_length() const { return field_length / field_charset->mbmaxlen; }
+ uint32 char_length() const
+ {
+ return field_length / mbmaxlen();
+ }
Information_schema_character_attributes
information_schema_character_attributes() const
{
@@ -1907,7 +1960,7 @@ protected:
{
String_copier copier;
- *copy_length= copier.well_formed_copy(field_charset, to, to_length,
+ *copy_length= copier.well_formed_copy(field_charset(), to, to_length,
from_cs, from, from_length,
nchars);
@@ -1923,7 +1976,7 @@ protected:
uint *out_length,
CHARSET_INFO *cs, size_t nchars);
String *uncompress(String *val_buffer, String *val_ptr,
- const uchar *from, uint from_length);
+ const uchar *from, uint from_length) const;
public:
Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -1932,7 +1985,9 @@ public:
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
field_name_arg, collation)
{}
-
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
int store_decimal(const my_decimal *d);
uint32 max_data_length() const;
@@ -1973,6 +2028,9 @@ public:
{
return do_field_real;
}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Information_schema_numeric_attributes
information_schema_numeric_attributes() const
{
@@ -2036,7 +2094,7 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
void overflow(bool negative);
bool zero_pack() const { return 0; }
@@ -2088,6 +2146,9 @@ public:
decimals() == from->decimals() &&
field_length == from->field_length;
}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
int reset(void);
bool store_value(const my_decimal *decimal_value);
bool store_value(const my_decimal *decimal_value, int *native_error);
@@ -2126,7 +2187,7 @@ public:
{
return my_decimal(ptr, precision, dec).to_bool();
}
- int cmp(const uchar *, const uchar *);
+ int cmp(const uchar *, const uchar *) const;
void sort_string(uchar *buff, uint length);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
@@ -2138,10 +2199,10 @@ public:
}
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
- uint pack_length_from_metadata(uint field_metadata);
+ uint pack_length_from_metadata(uint field_metadata) const;
uint row_pack_length() const { return pack_length(); }
- bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
+ bool compatible_field_size(uint field_metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const;
bool is_equal(const Column_definition &new_field) const;
virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
@@ -2160,6 +2221,9 @@ public:
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, 0, zero_arg, unsigned_arg)
{}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
bool memcpy_field_possible(const Field *from) const
{
return real_type() == from->real_type() &&
@@ -2181,7 +2245,7 @@ public:
{
return type_limits_int()->char_length();
}
- Type_std_attributes type_std_attributes() const
+ Type_numeric_attributes type_numeric_attributes() const
{
/*
For integer data types, the user-specified length does not constrain the
@@ -2195,9 +2259,8 @@ public:
*/
uint32 length1= max_display_length();
uint32 length2= field_length;
- return Type_std_attributes(MY_MAX(length1, length2), decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_numeric_attributes(MY_MAX(length1, length2),
+ decimals(), is_unsigned());
}
Information_schema_numeric_attributes
information_schema_numeric_attributes() const
@@ -2216,6 +2279,10 @@ public:
class Field_tiny :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ return is_unsigned() ? &type_handler_utiny : &type_handler_stiny;
+ }
public:
Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2224,7 +2291,7 @@ public:
:Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_tiny; }
+ const Type_handler *type_handler() const { return type_handler_priv(); }
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2235,13 +2302,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
const Type_limits_int *type_limits_int() const
{
- return type_handler_tiny.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
@@ -2267,6 +2334,10 @@ public:
class Field_short :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ return is_unsigned() ? &type_handler_ushort : &type_handler_sshort;
+ }
public:
Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2281,7 +2352,7 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_short; }
+ const Type_handler *type_handler() const { return type_handler_priv(); }
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2292,13 +2363,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
const Type_limits_int *type_limits_int() const
{
- return type_handler_short.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{ return pack_int16(to, from); }
@@ -2314,6 +2385,10 @@ public:
class Field_medium :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ return is_unsigned() ? &type_handler_uint24 : &type_handler_sint24;
+ }
public:
Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2322,7 +2397,7 @@ public:
:Field_int(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, zero_arg, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_int24; }
+ const Type_handler *type_handler() const { return type_handler_priv(); }
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2333,13 +2408,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
const Type_limits_int *type_limits_int() const
{
- return type_handler_int24.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{
@@ -2354,6 +2429,10 @@ public:
class Field_long :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ return is_unsigned() ? &type_handler_ulong : &type_handler_slong;
+ }
public:
Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2368,7 +2447,7 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const { return type_handler_priv(); }
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2379,13 +2458,13 @@ public:
longlong val_int(void);
bool send_binary(Protocol *protocol);
String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
const Type_limits_int *type_limits_int() const
{
- return type_handler_long.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
@@ -2407,6 +2486,10 @@ public:
class Field_longlong :public Field_int
{
+ const Type_handler_general_purpose_int *type_handler_priv() const
+ {
+ return is_unsigned() ? &type_handler_ulonglong : &type_handler_slonglong;
+ }
public:
Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@@ -2421,7 +2504,7 @@ public:
:Field_int((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, 0, unsigned_arg)
{}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return type_handler_priv(); }
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
int store(const char *to,size_t length,CHARSET_INFO *charset);
@@ -2436,13 +2519,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
const Type_limits_int *type_limits_int() const
{
- return type_handler_longlong.type_limits_int_by_unsigned_flag(is_unsigned());
+ return type_handler_priv()->type_limits_int();
}
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
@@ -2537,7 +2620,7 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(float); }
uint row_pack_length() const { return pack_length(); }
@@ -2602,7 +2685,7 @@ public:
ulonglong val_uint(void) { return (ulonglong) val_int_from_real(true); }
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return sizeof(double); }
uint row_pack_length() const { return pack_length(); }
@@ -2631,6 +2714,9 @@ public:
unireg_check_arg, field_name_arg, collation)
{}
const Type_handler *type_handler() const { return &type_handler_null; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Information_schema_character_attributes
information_schema_character_attributes() const
{
@@ -2653,7 +2739,7 @@ public:
String *val_str(String *value,String *value2)
{ value2->length(0); return value2;}
bool is_equal(const Column_definition &new_field) const;
- int cmp(const uchar *a, const uchar *b) { return 0;}
+ int cmp(const uchar *a, const uchar *b) const { return 0;}
void sort_string(uchar *buff, uint length) {}
uint32 pack_length() const { return 0; }
void sql_type(String &str) const;
@@ -2729,9 +2815,14 @@ public:
bool memcpy_field_possible(const Field *from) const;
uint32 max_display_length() const { return field_length; }
bool str_needs_quotes() { return TRUE; }
- enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
- uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
- CHARSET_INFO *charset(void) const { return &my_charset_numeric; }
+ CHARSET_INFO *charset(void) const
+ {
+ return DTCollation_numeric::singleton().collation;
+ }
+ const DTCollation &dtcollation() const
+ {
+ return DTCollation_numeric::singleton();
+ }
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
bool binary() const { return true; }
bool val_bool() { return val_real() != 0e0; }
@@ -2819,6 +2910,9 @@ public:
TABLE_SHARE *share);
const Type_handler *type_handler() const { return &type_handler_timestamp; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Copy_func *get_copy_func(const Field *from) const;
int store(const char *to,size_t length,CHARSET_INFO *charset);
int store(double nr);
@@ -2831,7 +2925,7 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
@@ -2944,7 +3038,7 @@ public:
}
bool val_native(Native *to);
my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const;
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
uint32 pack_length() const { return 4 + sec_part_bytes(dec); }
uint size_of() const { return sizeof(*this); }
};
@@ -2971,18 +3065,21 @@ public:
{}
const Type_handler *type_handler() const { return &type_handler_timestamp2; }
enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
uint32 pack_length() const
{
return my_timestamp_binary_length(dec);
}
uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_ENTER("Field_timestampf::pack_length_from_metadata");
uint tmp= my_timestamp_binary_length(field_metadata);
DBUG_RETURN(tmp);
}
- int cmp(const uchar *a_ptr,const uchar *b_ptr)
+ int cmp(const uchar *a_ptr,const uchar *b_ptr) const
{
return memcmp(a_ptr, b_ptr, pack_length());
}
@@ -3010,6 +3107,9 @@ public:
{
return field_length == 2 ? &type_handler_year2 : &type_handler_year;
}
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Copy_func *get_copy_func(const Field *from) const
{
if (eq_def(from))
@@ -3092,6 +3192,9 @@ public:
unireg_check_arg, field_name_arg) {}
const Type_handler *type_handler() const { return &type_handler_date; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; }
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_date::get_TIME(ltime, ptr, fuzzydate); }
@@ -3099,7 +3202,7 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
@@ -3129,12 +3232,15 @@ public:
{}
const Type_handler *type_handler() const { return &type_handler_newdate; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; }
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
@@ -3172,6 +3278,9 @@ public:
const Item_equal *item_equal);
const Type_handler *type_handler() const { return &type_handler_time; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Copy_func *get_copy_func(const Field *from) const
{
return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344
@@ -3195,7 +3304,7 @@ public:
String *val_str(String*,String *);
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
@@ -3255,7 +3364,7 @@ public:
}
int reset(void);
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return Type_handler_time::hires_bytes(dec); }
uint size_of() const { return sizeof(*this); }
@@ -3284,12 +3393,15 @@ public:
}
const Type_handler *type_handler() const { return &type_handler_time2; }
enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
uint32 pack_length() const
{
return my_time_binary_length(dec);
}
uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_ENTER("Field_timef::pack_length_from_metadata");
uint tmp= my_time_binary_length(field_metadata);
@@ -3300,7 +3412,7 @@ public:
DBUG_ASSERT(length == Field_timef::pack_length());
memcpy(to, ptr, length);
}
- int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ int cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
return memcmp(a_ptr, b_ptr, pack_length());
}
@@ -3329,6 +3441,9 @@ public:
}
const Type_handler *type_handler() const { return &type_handler_datetime; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
int store(const char *to, size_t length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr, bool unsigned_val);
@@ -3338,7 +3453,7 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
bool send_binary(Protocol *protocol);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
@@ -3423,7 +3538,7 @@ public:
{
DBUG_ASSERT(dec);
}
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
uint32 pack_length() const { return Type_handler_datetime::hires_bytes(dec); }
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); }
@@ -3451,18 +3566,21 @@ public:
{}
const Type_handler *type_handler() const { return &type_handler_datetime2; }
enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
uint32 pack_length() const
{
return my_datetime_binary_length(dec);
}
uint row_pack_length() const { return pack_length(); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_ENTER("Field_datetimef::pack_length_from_metadata");
uint tmp= my_datetime_binary_length(field_metadata);
DBUG_RETURN(tmp);
}
- int cmp(const uchar *a_ptr, const uchar *b_ptr)
+ int cmp(const uchar *a_ptr, const uchar *b_ptr) const
{
return memcmp(a_ptr, b_ptr, pack_length());
}
@@ -3559,6 +3677,7 @@ public:
}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const;
bool zero_pack() const { return 0; }
Copy_func *get_copy_func(const Field *from) const;
int reset(void)
@@ -3573,8 +3692,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
+ void update_data_type_statistics(Data_type_statistics *st) const
+ {
+ st->m_fixed_string_count++;
+ st->m_fixed_string_total_length+= pack_length();
+ }
void sql_type(String &str) const;
bool is_equal(const Column_definition &new_field) const;
bool can_be_converted_by_engine(const Column_definition &new_type) const
@@ -3585,15 +3709,15 @@ public:
uint max_length);
virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end,uint param_data);
- uint pack_length_from_metadata(uint field_metadata)
+ uint pack_length_from_metadata(uint field_metadata) const
{
DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata));
if (field_metadata == 0)
return row_pack_length();
return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff);
}
- bool compatible_field_size(uint field_metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
+ bool compatible_field_size(uint field_metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const;
uint row_pack_length() const { return field_length; }
int pack_cmp(const uchar *a,const uchar *b,uint key_length,
bool insert_or_update);
@@ -3659,7 +3783,13 @@ public:
}
const Type_handler *type_handler() const { return &type_handler_varchar; }
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ return FIELD_VARCHAR;
+ }
enum ha_base_keytype key_type() const;
+ uint16 key_part_flag() const { return HA_VAR_LENGTH_PART; }
+ uint16 key_part_length_bytes() const { return HA_KEY_BLOB_LENGTH; }
uint row_pack_length() const { return field_length; }
bool zero_pack() const { return 0; }
int reset(void) { bzero(ptr,field_length+length_bytes); return 0; }
@@ -3667,15 +3797,15 @@ public:
uint32 key_length() const { return (uint32) field_length; }
uint32 sort_length() const
{
- return (uint32) field_length + (field_charset == &my_charset_bin ?
+ return (uint32) field_length + (field_charset() == &my_charset_bin ?
length_bytes : 0);
}
Copy_func *get_copy_func(const Field *from) const;
- bool memcpy_field_possible(const Field *from) const
+ bool memcpy_field_possible(const Field *from) const;
+ void update_data_type_statistics(Data_type_statistics *st) const
{
- return Field_str::memcpy_field_possible(from) &&
- !compression_method() == !from->compression_method() &&
- length_bytes == ((Field_varstring*) from)->length_bytes;
+ st->m_variable_string_count++;
+ st->m_variable_string_total_length+= pack_length();
}
int store(const char *to,size_t length,CHARSET_INFO *charset);
using Field_str::store;
@@ -3683,8 +3813,8 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp_max(const uchar *, const uchar *, uint max_length);
- int cmp(const uchar *a,const uchar *b)
+ int cmp_max(const uchar *, const uchar *, uint max_length) const;
+ int cmp(const uchar *a,const uchar *b) const
{
return cmp_max(a, b, ~0U);
}
@@ -3695,9 +3825,9 @@ public:
virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar* to, const uchar *from,
const uchar *from_end, uint param_data);
- int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const;
+ int key_cmp(const uchar *,const uchar*) const;
+ int key_cmp(const uchar *str, uint length) const;
uint packed_col_length(const uchar *to, uint length);
uint max_packed_col_length(uint max_length);
uint32 data_length();
@@ -3754,16 +3884,16 @@ private:
uint32 character_octet_length() const { return field_length - 1; }
uint32 char_length() const
{
- return (field_length - 1) / field_charset->mbmaxlen;
+ return (field_length - 1) / mbmaxlen();
}
- int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len);
+ int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len) const;
/*
Compressed fields can't have keys as two rows may have different
compression methods or compression levels.
*/
- int key_cmp(const uchar *str, uint length)
+ int key_cmp(const uchar *str, uint length) const
{ DBUG_ASSERT(0); return 0; }
using Field_varstring::key_cmp;
};
@@ -3829,6 +3959,7 @@ protected:
static void do_copy_blob(Copy_field *copy);
static void do_conv_blob(Copy_field *copy);
+ uint get_key_image_itRAW(uchar *buff, uint length);
public:
Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
@@ -3875,19 +4006,28 @@ public:
}
enum ha_base_keytype key_type() const
{ return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; }
- Type_std_attributes type_std_attributes() const
+ uint16 key_part_flag() const { return HA_BLOB_PART; }
+ uint16 key_part_length_bytes() const { return HA_KEY_BLOB_LENGTH; }
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ return FIELD_BLOB;
+ }
+ Type_numeric_attributes type_numeric_attributes() const
{
- return Type_std_attributes(Field_blob::max_display_length(), decimals(),
- MY_TEST(flags & UNSIGNED_FLAG),
- dtcollation());
+ return Type_numeric_attributes(Field_blob::max_display_length(),
+ decimals(), is_unsigned());
}
Information_schema_character_attributes
information_schema_character_attributes() const
{
uint32 octets= Field_blob::character_octet_length();
- uint32 chars= octets / field_charset->mbminlen;
+ uint32 chars= octets / field_charset()->mbminlen;
return Information_schema_character_attributes(octets, chars);
}
+ void update_data_type_statistics(Data_type_statistics *st) const
+ {
+ st->m_blob_count++;
+ }
void make_send_field(Send_field *);
Copy_func *get_copy_func(const Field *from) const
{
@@ -3924,13 +4064,13 @@ public:
longlong val_int(void);
String *val_str(String*,String *);
my_decimal *val_decimal(my_decimal *);
- int cmp_max(const uchar *, const uchar *, uint max_length);
- int cmp(const uchar *a,const uchar *b)
+ int cmp_max(const uchar *, const uchar *, uint max_length) const;
+ int cmp(const uchar *a,const uchar *b) const
{ return cmp_max(a, b, ~0U); }
- int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length);
- int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U);
- int key_cmp(const uchar *,const uchar*);
- int key_cmp(const uchar *str, uint length);
+ int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length) const;
+ int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) const;
+ int key_cmp(const uchar *,const uchar*) const;
+ int key_cmp(const uchar *str, uint length) const;
/* Never update the value of min_val for a blob field */
bool update_min(Field *min_val, bool force_update) { return FALSE; }
/* Never update the value of max_val for a blob field */
@@ -3994,7 +4134,11 @@ public:
set_ptr_offset(0, length, data);
}
int copy_value(Field_blob *from);
- uint get_key_image(uchar *buff,uint length, imagetype type);
+ uint get_key_image(uchar *buff, uint length, imagetype type)
+ {
+ DBUG_ASSERT(type == itRAW);
+ return get_key_image_itRAW(buff, length);
+ }
void set_key_image(const uchar *buff,uint length);
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
@@ -4104,9 +4248,9 @@ private:
{ DBUG_ASSERT(0); return 0; }
void set_key_image(const uchar *buff, uint length)
{ DBUG_ASSERT(0); }
- int key_cmp(const uchar *a, const uchar *b)
+ int key_cmp(const uchar *a, const uchar *b) const
{ DBUG_ASSERT(0); return 0; }
- int key_cmp(const uchar *str, uint length)
+ int key_cmp(const uchar *str, uint length) const
{ DBUG_ASSERT(0); return 0; }
Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
@@ -4115,118 +4259,18 @@ private:
};
-#ifdef HAVE_SPATIAL
-class Field_geom :public Field_blob {
-public:
- enum geometry_type geom_type;
- uint srid;
- uint precision;
- enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1};
- enum storage_type storage;
-
- Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
- enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
- TABLE_SHARE *share, uint blob_pack_length,
- enum geometry_type geom_type_arg, uint field_srid)
- :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
- field_name_arg, share, blob_pack_length, &my_charset_bin)
- { geom_type= geom_type_arg; srid= field_srid; }
- enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; }
- const Type_handler *type_handler() const
- {
- return &type_handler_geometry;
- }
- enum_field_types type() const
- {
- return MYSQL_TYPE_GEOMETRY;
- }
- enum_field_types real_type() const
- {
- return MYSQL_TYPE_GEOMETRY;
- }
- Information_schema_character_attributes
- information_schema_character_attributes() const
- {
- return Information_schema_character_attributes();
- }
- void make_send_field(Send_field *to)
- {
- Field_longstr::make_send_field(to);
- }
- bool can_optimize_range(const Item_bool_func *cond,
- const Item *item,
- bool is_eq_func) const;
- void sql_type(String &str) const;
- Copy_func *get_copy_func(const Field *from) const
- {
- if (type_handler() == from->type_handler() &&
- (geom_type == GEOM_GEOMETRY ||
- geom_type == static_cast<const Field_geom*>(from)->geom_type))
- return get_identical_copy_func();
- return do_conv_blob;
- }
- bool memcpy_field_possible(const Field *from) const
- {
- return type_handler() == from->type_handler() &&
- (geom_type == GEOM_GEOMETRY ||
- geom_type == static_cast<const Field_geom*>(from)->geom_type) &&
- !table->copy_blobs;
- }
- bool is_equal(const Column_definition &new_field) const;
- bool can_be_converted_by_engine(const Column_definition &new_type) const
- {
- return table->file->can_convert_geom(this, new_type);
- }
-
- int store(const char *to, size_t length, CHARSET_INFO *charset);
- int store(double nr);
- int store(longlong nr, bool unsigned_val);
- int store_decimal(const my_decimal *);
- uint size_of() const { return sizeof(*this); }
- /**
- Key length is provided only to support hash joins. (compared byte for byte)
- Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2.
-
- The comparison is not very relevant, as identical geometry might be
- represented differently, but we need to support it either way.
- */
- uint32 key_length() const { return packlength; }
-
- /**
- Non-nullable GEOMETRY types cannot have defaults,
- but the underlying blob must still be reset.
- */
- int reset(void) { return Field_blob::reset() || !maybe_null(); }
- bool load_data_set_null(THD *thd);
- bool load_data_set_no_data(THD *thd, bool fixed_format);
-
- geometry_type get_geometry_type() const { return geom_type; };
- static geometry_type geometry_type_merge(geometry_type, geometry_type);
- uint get_srid() { return srid; }
- void print_key_value(String *out, uint32 length)
- {
- out->append(STRING_WITH_LEN("unprintable_geometry_value"));
- }
-};
-
-uint gis_field_options_image(uchar *buff, List<Create_field> &create_fields);
-uint gis_field_options_read(const uchar *buf, size_t buf_len,
- Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid);
-
-#endif /*HAVE_SPATIAL*/
-
-
class Field_enum :public Field_str {
static void do_field_enum(Copy_field *copy_field);
+ longlong val_int(const uchar *) const;
protected:
uint packlength;
public:
- TYPELIB *typelib;
+ const TYPELIB *typelib;
Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
uint packlength_arg,
- TYPELIB *typelib_arg,
+ const TYPELIB *typelib_arg,
const DTCollation &collation)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, collation),
@@ -4237,6 +4281,9 @@ public:
Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type);
const Type_handler *type_handler() const { return &type_handler_enum; }
enum ha_base_keytype key_type() const;
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
Copy_func *get_copy_func(const Field *from) const
{
if (eq_def(from))
@@ -4280,13 +4327,13 @@ public:
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
- int cmp(const uchar *,const uchar *);
+ int cmp(const uchar *,const uchar *) const;
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return (uint32) packlength; }
void store_type(ulonglong value);
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
- uint pack_length_from_metadata(uint field_metadata)
+ uint pack_length_from_metadata(uint field_metadata) const
{ return (field_metadata & 0x00ff); }
uint row_pack_length() const { return pack_length(); }
virtual bool zero_pack() const { return 0; }
@@ -4296,7 +4343,7 @@ public:
/* enum and set are sorted as integers */
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
uint decimals() const { return 0; }
- TYPELIB *get_typelib() const { return typelib; }
+ const TYPELIB *get_typelib() const { return typelib; }
virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar *to, const uchar *from,
@@ -4331,7 +4378,7 @@ public:
uchar null_bit_arg,
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
uint32 packlength_arg,
- TYPELIB *typelib_arg, const DTCollation &collation)
+ const TYPELIB *typelib_arg, const DTCollation &collation)
:Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
packlength_arg,
@@ -4386,14 +4433,24 @@ public:
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg);
const Type_handler *type_handler() const { return &type_handler_bit; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
+ uint16 key_part_flag() const { return HA_BIT_PART; }
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
uint32 max_data_length() const { return (field_length + 7) / 8; }
uint32 max_display_length() const { return field_length; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const;
+ CHARSET_INFO *charset() const { return &my_charset_bin; }
+ const DTCollation & dtcollation() const;
Information_schema_numeric_attributes
information_schema_numeric_attributes() const
{
return Information_schema_numeric_attributes(field_length);
}
+ void update_data_type_statistics(Data_type_statistics *st) const
+ {
+ st->m_uneven_bit_length+= field_length & 7;
+ }
uint size_of() const { return sizeof(*this); }
int reset(void) {
bzero(ptr, bytes_in_rec);
@@ -4419,7 +4476,7 @@ public:
virtual bool str_needs_quotes() { return TRUE; }
my_decimal *val_decimal(my_decimal *);
bool val_bool() { return val_int() != 0; }
- int cmp(const uchar *a, const uchar *b)
+ virtual int cmp(const uchar *a, const uchar *b) const
{
DBUG_ASSERT(ptr == a || ptr == b);
if (ptr == a)
@@ -4429,10 +4486,10 @@ public:
}
int cmp_binary_offset(uint row_offset)
{ return cmp_offset(row_offset); }
- int cmp_max(const uchar *a, const uchar *b, uint max_length);
- int key_cmp(const uchar *a, const uchar *b)
+ int cmp_max(const uchar *a, const uchar *b, uint max_length) const;
+ int key_cmp(const uchar *a, const uchar *b) const
{ return cmp_binary((uchar *) a, (uchar *) b); }
- int key_cmp(const uchar *str, uint length);
+ int key_cmp(const uchar *str, uint length) const;
int cmp_offset(my_ptrdiff_t row_offset);
bool update_min(Field *min_val, bool force_update)
{
@@ -4475,11 +4532,11 @@ public:
{ get_key_image(buff, length, itRAW); }
uint32 pack_length() const { return (uint32) (field_length + 7) / 8; }
uint32 pack_length_in_rec() const { return bytes_in_rec; }
- uint pack_length_from_metadata(uint field_metadata);
+ uint pack_length_from_metadata(uint field_metadata) const;
uint row_pack_length() const
{ return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); }
- bool compatible_field_size(uint metadata, Relay_log_info *rli,
- uint16 mflags, int *order_var);
+ bool compatible_field_size(uint metadata, const Relay_log_info *rli,
+ uint16 mflags, int *order_var) const;
void sql_type(String &str) const;
virtual uchar *pack(uchar *to, const uchar *from, uint max_length);
virtual const uchar *unpack(uchar *to, const uchar *from,
@@ -4556,6 +4613,18 @@ public:
m_table(NULL)
{}
~Field_row();
+ en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
+ {
+ DBUG_ASSERT(0);
+ return Field::tmp_engine_column_type(use_packed_rows);
+ }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+ {
+ DBUG_ASSERT(0);
+ return CONV_TYPE_IMPOSSIBLE;
+ }
Virtual_tmp_table **virtual_tmp_table_addr() { return &m_table; }
bool sp_prepare_and_store_item(THD *thd, Item **value);
};
@@ -4572,10 +4641,9 @@ public:
*/
ulonglong length;
Field::utype unireg_check;
- TYPELIB *interval; // Which interval to use
+ const TYPELIB *interval; // Which interval to use
CHARSET_INFO *charset;
uint32 srid;
- Field::geometry_type geom_type;
uint pack_flag;
Column_definition_attributes()
:length(0),
@@ -4583,7 +4651,6 @@ public:
interval(NULL),
charset(&my_charset_bin),
srid(0),
- geom_type(Field::GEOM_GEOMETRY),
pack_flag(0)
{ }
Column_definition_attributes(const Field *field);
@@ -4861,7 +4928,6 @@ public:
interval= other.interval;
charset= other.charset;
srid= other.srid;
- geom_type= other.geom_type;
pack_flag= other.pack_flag;
}
@@ -4879,6 +4945,8 @@ public:
{ compression_method_ptr= compression_method_arg; }
Compression_method *compression_method() const
{ return compression_method_ptr; }
+
+ bool check_vcol_for_key(THD *thd) const;
};
@@ -5055,7 +5123,7 @@ public:
LEX_CSTRING change; // If done with alter table
LEX_CSTRING after; // Put column after this one
Field *field; // For alter table
- TYPELIB *save_interval; // Temporary copy for the above
+ const TYPELIB *save_interval; // Temporary copy for the above
// Used only for UCS2 intervals
/** structure with parsed options (for comparing fields in ALTER TABLE) */
@@ -5092,22 +5160,21 @@ class Send_field :public Sql_alloc,
public Type_handler_hybrid_field_type
{
public:
- const char *db_name;
- const char *table_name,*org_table_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name, org_table_name;
LEX_CSTRING col_name, org_col_name;
ulong length;
uint flags, decimals;
- Send_field() {}
Send_field(Field *field)
{
field->make_send_field(this);
- DBUG_ASSERT(table_name != 0);
+ DBUG_ASSERT(table_name.str != 0);
normalize();
}
Send_field(THD *thd, Item *item);
Send_field(Field *field,
- const char *db_name_arg,
- const char *table_name_arg)
+ const LEX_CSTRING &db_name_arg,
+ const LEX_CSTRING &table_name_arg)
:Type_handler_hybrid_field_type(field->type_handler()),
db_name(db_name_arg),
table_name(table_name_arg),
@@ -5162,12 +5229,27 @@ public:
}
// This should move to Type_handler eventually
- bool is_sane() const
+ bool is_sane_float() const
{
return (decimals <= FLOATING_POINT_DECIMALS ||
(type_handler()->field_type() != MYSQL_TYPE_FLOAT &&
type_handler()->field_type() != MYSQL_TYPE_DOUBLE));
}
+ bool is_sane_signess() const
+ {
+ if (type_handler() == type_handler()->type_handler_signed() &&
+ type_handler() == type_handler()->type_handler_unsigned())
+ return true; // Any signess is allowed, e.g. DOUBLE, DECIMAL
+ /*
+ We are here e.g. in case of INT data type.
+ The UNSIGNED_FLAG bit must match in flags and in the type handler.
+ */
+ return ((bool) (flags & UNSIGNED_FLAG)) == type_handler()->is_unsigned();
+ }
+ bool is_sane() const
+ {
+ return is_sane_float() && is_sane_signess();
+ }
};
@@ -5216,7 +5298,7 @@ enum_field_types get_blob_type_from_length(ulong length);
int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
int convert_null_to_field_value_or_error(Field *field);
-bool check_expression(Virtual_column_info *vcol, LEX_CSTRING *name,
+bool check_expression(Virtual_column_info *vcol, const LEX_CSTRING *name,
enum_vcol_info_type type);
/*
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index b6c5db7cd5c..80cb6dd4322 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -72,7 +72,8 @@
#define PAR_ENGINES_OFFSET 12
#define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | \
HA_REC_NOT_IN_SEQ | \
- HA_CAN_REPAIR)
+ HA_CAN_REPAIR | \
+ HA_REUSES_FILE_NAMES)
#define PARTITION_DISABLED_TABLE_FLAGS (HA_CAN_GEOMETRY | \
HA_DUPLICATE_POS | \
HA_CAN_INSERT_DELAYED | \
@@ -125,7 +126,6 @@ static int partition_initialize(void *p)
handlerton *partition_hton;
partition_hton= (handlerton *)p;
- partition_hton->state= SHOW_OPTION_YES;
partition_hton->db_type= DB_TYPE_PARTITION_DB;
partition_hton->create= partition_create_handler;
partition_hton->partition_flags= partition_flags;
@@ -4276,7 +4276,7 @@ int ha_partition::write_row(const uchar * buf)
bool have_auto_increment= table->next_number_field && buf == table->record[0];
my_bitmap_map *old_map;
THD *thd= ha_thd();
- sql_mode_t saved_sql_mode= thd->variables.sql_mode;
+ Sql_mode_save sms(thd);
bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null;
DBUG_ENTER("ha_partition::write_row");
DBUG_PRINT("enter", ("partition this: %p", this));
@@ -4342,7 +4342,6 @@ int ha_partition::write_row(const uchar * buf)
reenable_binlog(thd);
exit:
- thd->variables.sql_mode= saved_sql_mode;
table->auto_increment_field_not_null= saved_auto_inc_field_not_null;
DBUG_RETURN(error);
}
@@ -10233,19 +10232,6 @@ end:
}
-void ha_partition::notify_table_changed()
-{
- handler **file;
-
- DBUG_ENTER("ha_partition::notify_table_changed");
-
- for (file= m_file; *file; file++)
- (*file)->ha_notify_table_changed();
-
- DBUG_VOID_RETURN;
-}
-
-
uint ha_partition::min_of_the_max_uint(
uint (handler::*operator_func)(void) const) const
{
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index de5b4f2a66f..2148926c1ed 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -1388,8 +1388,6 @@ public:
virtual bool commit_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info,
bool commit);
- virtual void notify_table_changed();
-
/*
-------------------------------------------------------------------------
MODULE tablespace support
diff --git a/sql/ha_sequence.cc b/sql/ha_sequence.cc
index beaed6ef7df..87d8339881d 100644
--- a/sql/ha_sequence.cc
+++ b/sql/ha_sequence.cc
@@ -101,7 +101,7 @@ int ha_sequence::open(const char *name, int mode, uint flags)
ha_open() sets the following for us. We have to set this for the
underlying handler
*/
- file->cached_table_flags= file->table_flags();
+ file->cached_table_flags= (file->table_flags() | HA_REUSES_FILE_NAMES);
file->reset_statistics();
internal_tmp_table= file->internal_tmp_table=
@@ -413,7 +413,6 @@ static int sequence_initialize(void *p)
handlerton *local_sequence_hton= (handlerton *)p;
DBUG_ENTER("sequence_initialize");
- local_sequence_hton->state= SHOW_OPTION_YES;
local_sequence_hton->db_type= DB_TYPE_SEQUENCE;
local_sequence_hton->create= sequence_create_handler;
local_sequence_hton->panic= sequence_end;
diff --git a/sql/handle_connections_win.cc b/sql/handle_connections_win.cc
index e5b601d7fe0..3b29ad439ac 100644
--- a/sql/handle_connections_win.cc
+++ b/sql/handle_connections_win.cc
@@ -367,17 +367,14 @@ struct Pipe_Listener : public Listener
static void create_pipe_connection(HANDLE pipe)
{
- CONNECT *connect;
- if (!(connect= new CONNECT) || !(connect->vio= vio_new_win32pipe(pipe)))
+ if (auto connect= new CONNECT(pipe))
+ create_new_thread(connect);
+ else
{
CloseHandle(pipe);
- delete connect;
statistic_increment(aborted_connects, &LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
- return;
}
- connect->host= my_localhost;
- create_new_thread(connect);
}
/* Threadpool callback.*/
diff --git a/sql/handler.cc b/sql/handler.cc
index c4f5febbdcf..94cffd69b75 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -297,7 +297,7 @@ handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
DBUG_ENTER("get_new_handler");
DBUG_PRINT("enter", ("alloc: %p", alloc));
- if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create)
+ if (ha_storage_engine_is_enabled(db_type))
{
if ((file= db_type->create(db_type, share, alloc)))
file->init();
@@ -482,15 +482,8 @@ int ha_finalize_handlerton(st_plugin_int *plugin)
if (!hton)
goto end;
- switch (hton->state) {
- case SHOW_OPTION_NO:
- case SHOW_OPTION_DISABLED:
- break;
- case SHOW_OPTION_YES:
- if (installed_htons[hton->db_type] == hton)
- installed_htons[hton->db_type]= NULL;
- break;
- };
+ if (installed_htons[hton->db_type] == hton)
+ installed_htons[hton->db_type]= NULL;
if (hton->panic)
hton->panic(hton, HA_PANIC_CLOSE);
@@ -557,7 +550,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
if (plugin->plugin->init && plugin->plugin->init(hton))
{
sql_print_error("Plugin '%s' init function returned error.",
- plugin->name.str);
+ plugin->name.str);
goto err;
}
@@ -576,90 +569,78 @@ int ha_initialize_handlerton(st_plugin_int *plugin)
hton->discover_table_existence= full_discover_for_existence;
}
- switch (hton->state) {
- case SHOW_OPTION_NO:
- break;
- case SHOW_OPTION_YES:
- {
- uint tmp;
- ulong fslot;
-
- DBUG_EXECUTE_IF("unstable_db_type", {
- static int i= (int) DB_TYPE_FIRST_DYNAMIC;
- hton->db_type= (enum legacy_db_type)++i;
- });
-
- /* now check the db_type for conflict */
- if (hton->db_type <= DB_TYPE_UNKNOWN ||
- hton->db_type >= DB_TYPE_DEFAULT ||
- installed_htons[hton->db_type])
- {
- int idx= (int) DB_TYPE_FIRST_DYNAMIC;
+ uint tmp;
+ ulong fslot;
- while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
- idx++;
+ DBUG_EXECUTE_IF("unstable_db_type", {
+ static int i= (int) DB_TYPE_FIRST_DYNAMIC;
+ hton->db_type= (enum legacy_db_type)++i;
+ });
- if (idx == (int) DB_TYPE_DEFAULT)
- {
- sql_print_warning("Too many storage engines!");
- goto err_deinit;
- }
- if (hton->db_type != DB_TYPE_UNKNOWN)
- sql_print_warning("Storage engine '%s' has conflicting typecode. "
- "Assigning value %d.", plugin->plugin->name, idx);
- hton->db_type= (enum legacy_db_type) idx;
- }
+ /* now check the db_type for conflict */
+ if (hton->db_type <= DB_TYPE_UNKNOWN ||
+ hton->db_type >= DB_TYPE_DEFAULT ||
+ installed_htons[hton->db_type])
+ {
+ int idx= (int) DB_TYPE_FIRST_DYNAMIC;
- /*
- In case a plugin is uninstalled and re-installed later, it should
- reuse an array slot. Otherwise the number of uninstall/install
- cycles would be limited. So look for a free slot.
- */
- DBUG_PRINT("plugin", ("total_ha: %lu", total_ha));
- for (fslot= 0; fslot < total_ha; fslot++)
- {
- if (!hton2plugin[fslot])
- break;
- }
- if (fslot < total_ha)
- hton->slot= fslot;
- else
- {
- if (total_ha >= MAX_HA)
- {
- sql_print_error("Too many plugins loaded. Limit is %lu. "
- "Failed on '%s'", (ulong) MAX_HA, plugin->name.str);
- goto err_deinit;
- }
- hton->slot= total_ha++;
- }
- installed_htons[hton->db_type]= hton;
- tmp= hton->savepoint_offset;
- hton->savepoint_offset= savepoint_alloc_size;
- savepoint_alloc_size+= tmp;
- hton2plugin[hton->slot]=plugin;
- if (hton->prepare)
- {
- total_ha_2pc++;
- if (tc_log && tc_log != get_tc_log_implementation())
- {
- total_ha_2pc--;
- hton->prepare= 0;
- push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
- ER_UNKNOWN_ERROR,
- "Cannot enable tc-log at run-time. "
- "XA features of %s are disabled",
- plugin->name.str);
- }
- }
+ while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
+ idx++;
+
+ if (idx == (int) DB_TYPE_DEFAULT)
+ {
+ sql_print_warning("Too many storage engines!");
+ goto err_deinit;
+ }
+ if (hton->db_type != DB_TYPE_UNKNOWN)
+ sql_print_warning("Storage engine '%s' has conflicting typecode. "
+ "Assigning value %d.", plugin->plugin->name, idx);
+ hton->db_type= (enum legacy_db_type) idx;
+ }
+
+ /*
+ In case a plugin is uninstalled and re-installed later, it should
+ reuse an array slot. Otherwise the number of uninstall/install
+ cycles would be limited. So look for a free slot.
+ */
+ DBUG_PRINT("plugin", ("total_ha: %lu", total_ha));
+ for (fslot= 0; fslot < total_ha; fslot++)
+ {
+ if (!hton2plugin[fslot])
break;
+ }
+ if (fslot < total_ha)
+ hton->slot= fslot;
+ else
+ {
+ if (total_ha >= MAX_HA)
+ {
+ sql_print_error("Too many plugins loaded. Limit is %lu. "
+ "Failed on '%s'", (ulong) MAX_HA, plugin->name.str);
+ goto err_deinit;
}
- /* fall through */
- default:
- hton->state= SHOW_OPTION_DISABLED;
- break;
+ hton->slot= total_ha++;
}
-
+ installed_htons[hton->db_type]= hton;
+ tmp= hton->savepoint_offset;
+ hton->savepoint_offset= savepoint_alloc_size;
+ savepoint_alloc_size+= tmp;
+ hton2plugin[hton->slot]=plugin;
+ if (hton->prepare)
+ {
+ total_ha_2pc++;
+ if (tc_log && tc_log != get_tc_log_implementation())
+ {
+ total_ha_2pc--;
+ hton->prepare= 0;
+ push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNKNOWN_ERROR,
+ "Cannot enable tc-log at run-time. "
+ "XA features of %s are disabled",
+ plugin->name.str);
+ }
+ }
+
/*
This is entirely for legacy. We will create a new "disk based" hton and a
"memory" hton which will be configurable longterm. We should be able to
@@ -694,10 +675,10 @@ err_deinit:
*/
if (plugin->plugin->deinit)
(void) plugin->plugin->deinit(NULL);
-
+
err:
#ifdef DBUG_ASSERT_EXISTS
- if (hton->prepare && hton->state == SHOW_OPTION_YES)
+ if (hton->prepare)
failed_ha_2pc++;
#endif
my_free(hton);
@@ -742,7 +723,7 @@ static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin,
void *path)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->drop_database)
+ if (hton->drop_database)
hton->drop_database(hton, (char *)path);
return FALSE;
}
@@ -758,7 +739,7 @@ static my_bool checkpoint_state_handlerton(THD *unused1, plugin_ref plugin,
void *disable)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->checkpoint_state)
+ if (hton->checkpoint_state)
hton->checkpoint_state(hton, (int) *(bool*) disable);
return FALSE;
}
@@ -780,7 +761,7 @@ static my_bool commit_checkpoint_request_handlerton(THD *unused1, plugin_ref plu
{
st_commit_checkpoint_request *st= (st_commit_checkpoint_request *)data;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->commit_checkpoint_request)
+ if (hton->commit_checkpoint_request)
{
void *cookie= st->cookie;
if (st->pre_hook)
@@ -807,34 +788,29 @@ ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *))
}
-
-static my_bool closecon_handlerton(THD *thd, plugin_ref plugin,
- void *unused)
-{
- handlerton *hton= plugin_hton(plugin);
- /*
- there's no need to rollback here as all transactions must
- be rolled back already
- */
- if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton))
- {
- if (hton->close_connection)
- hton->close_connection(hton, thd);
- /* make sure ha_data is reset and ha_data_lock is released */
- thd_set_ha_data(thd, hton, NULL);
- }
- return FALSE;
-}
-
/**
@note
don't bother to rollback here, it's done already
+
+ there's no need to rollback here as all transactions must
+ be rolled back already
*/
void ha_close_connection(THD* thd)
{
- plugin_foreach_with_mask(thd, closecon_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN,
- PLUGIN_IS_DELETED|PLUGIN_IS_READY, 0);
+ for (auto i= 0; i < MAX_HA; i++)
+ {
+ if (thd->ha_data[i].lock)
+ {
+ handlerton *hton= plugin_hton(thd->ha_data[i].lock);
+ if (hton->close_connection)
+ hton->close_connection(hton, thd);
+ /* make sure SE didn't reset ha_data in close_connection() */
+ DBUG_ASSERT(thd->ha_data[i].lock);
+ /* make sure ha_data is reset and ha_data_lock is released */
+ thd_set_ha_data(thd, hton, 0);
+ }
+ DBUG_ASSERT(!thd->ha_data[i].ha_ptr);
+ }
}
static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
@@ -842,8 +818,7 @@ static my_bool kill_handlerton(THD *thd, plugin_ref plugin,
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->kill_query &&
- thd_get_ha_data(thd, hton))
+ if (hton->kill_query && thd_get_ha_data(thd, hton))
hton->kill_query(hton, thd, *(enum thd_kill_levels *) level);
return FALSE;
}
@@ -864,7 +839,7 @@ static my_bool plugin_prepare_for_backup(THD *unused1, plugin_ref plugin,
void *not_used)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->prepare_for_backup)
+ if (hton->prepare_for_backup)
hton->prepare_for_backup();
return FALSE;
}
@@ -880,7 +855,7 @@ static my_bool plugin_end_backup(THD *unused1, plugin_ref plugin,
void *not_used)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->end_backup)
+ if (hton->end_backup)
hton->end_backup();
return FALSE;
}
@@ -1958,7 +1933,7 @@ static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
@@ -1970,7 +1945,7 @@ static my_bool xarollback_handlerton(THD *unused1, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid);
((struct xahton_st *)arg)->result= 0;
@@ -2101,7 +2076,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
struct xarecover_st *info= (struct xarecover_st *) arg;
int got;
- if (hton->state == SHOW_OPTION_YES && hton->recover)
+ if (hton->recover)
{
while ((got= hton->recover(hton, info->list, info->len)) > 0 )
{
@@ -2446,8 +2421,7 @@ static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES &&
- hton->start_consistent_snapshot)
+ if (hton->start_consistent_snapshot)
{
if (hton->start_consistent_snapshot(hton, thd))
return TRUE;
@@ -2493,28 +2467,14 @@ static my_bool flush_handlerton(THD *thd, plugin_ref plugin,
void *arg)
{
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
- hton->flush_logs(hton))
- return TRUE;
- return FALSE;
+ return hton->flush_logs && hton->flush_logs(hton);
}
-bool ha_flush_logs(handlerton *db_type)
+bool ha_flush_logs()
{
- if (db_type == NULL)
- {
- if (plugin_foreach(NULL, flush_handlerton,
- MYSQL_STORAGE_ENGINE_PLUGIN, 0))
- return TRUE;
- }
- else
- {
- if (db_type->state != SHOW_OPTION_YES ||
- (db_type->flush_logs && db_type->flush_logs(db_type)))
- return TRUE;
- }
- return FALSE;
+ return plugin_foreach(NULL, flush_handlerton,
+ MYSQL_STORAGE_ENGINE_PLUGIN, 0);
}
@@ -2598,9 +2558,10 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
it's not an error if the table doesn't exist in the engine.
warn the user, but still report DROP being a success
*/
- bool intercept= error == ENOENT || error == HA_ERR_NO_SUCH_TABLE;
+ bool intercept= (error == ENOENT || error == HA_ERR_NO_SUCH_TABLE ||
+ error == HA_ERR_UNSUPPORTED);
- if (!intercept || generate_warning)
+ if ((!intercept || generate_warning) && ! thd->is_error())
{
/* Fill up strucutures that print_error may need */
dummy_share.path.str= (char*) path;
@@ -2613,7 +2574,10 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
file->print_error(error, MYF(intercept ? ME_WARNING : 0));
}
if (intercept)
+ {
+ thd->clear_error();
error= 0;
+ }
}
delete file;
@@ -2690,10 +2654,6 @@ double handler::keyread_time(uint index, uint ranges, ha_rows rows)
return cost;
}
-void **handler::ha_data(THD *thd) const
-{
- return thd_ha_data(thd, ht);
-}
THD *handler::ha_thd(void) const
{
@@ -4065,7 +4025,7 @@ int handler::check_collation_compatibility()
cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */
cs_number == 26)) || /* cp1250_general_ci - bug #29461 */
(mysql_version < 50124 &&
- (cs_number == 33 || /* utf8_general_ci - bug #27877 */
+ (cs_number == 33 || /* utf8mb3_general_ci - bug #27877 */
cs_number == 35))) /* ucs2_general_ci - bug #27877 */
return HA_ADMIN_NEEDS_UPGRADE;
}
@@ -5348,7 +5308,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin,
{
TABLE_SHARE *share= (TABLE_SHARE *)arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->discover_table)
+ if (hton->discover_table)
{
share->db_plugin= plugin;
int error= hton->discover_table(hton, thd, share);
@@ -5424,7 +5384,7 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin,
{
st_discover_existence_args *args= (st_discover_existence_args*)arg;
handlerton *ht= plugin_hton(plugin);
- if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence)
+ if (!ht->discover_table_existence)
return args->frm_exists;
args->hton= ht;
@@ -5714,7 +5674,7 @@ static my_bool discover_names(THD *thd, plugin_ref plugin,
st_discover_names_args *args= (st_discover_names_args *)arg;
handlerton *ht= plugin_hton(plugin);
- if (ht->state == SHOW_OPTION_YES && ht->discover_table_names)
+ if (ht->discover_table_names)
{
size_t old_elements= args->result->tables->elements();
if (ht->discover_table_names(ht, args->db, args->dirp, args->result))
@@ -5759,6 +5719,8 @@ int ha_discover_table_names(THD *thd, LEX_CSTRING *db, MY_DIR *dirp,
error= ext_table_discovery_simple(dirp, result) ||
plugin_foreach(thd, discover_names,
MYSQL_STORAGE_ENGINE_PLUGIN, &args);
+ if (args.possible_duplicates > 0)
+ result->remove_duplicates();
}
else
{
@@ -6113,7 +6075,7 @@ static my_bool showstat_handlerton(THD *thd, plugin_ref plugin,
{
enum ha_stat_type stat= *(enum ha_stat_type *) arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->state == SHOW_OPTION_YES && hton->show_status &&
+ if (hton->show_status &&
hton->show_status(hton, thd, stat_print, stat))
return TRUE;
return FALSE;
@@ -6145,17 +6107,8 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
}
else
{
- if (db_type->state != SHOW_OPTION_YES)
- {
- const LEX_CSTRING *name= hton_name(db_type);
- result= stat_print(thd, name->str, name->length,
- "", 0, "DISABLED", 8) ? 1 : 0;
- }
- else
- {
- result= db_type->show_status &&
- db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
- }
+ result= db_type->show_status &&
+ db_type->show_status(db_type, thd, stat_print, stat) ? 1 : 0;
}
/*
@@ -7684,7 +7637,8 @@ static bool is_versioning_timestamp(const Create_field *f)
static bool is_some_bigint(const Create_field *f)
{
- return f->type_handler() == &type_handler_longlong ||
+ return f->type_handler() == &type_handler_slonglong ||
+ f->type_handler() == &type_handler_ulonglong ||
f->type_handler() == &type_handler_vers_trx_id;
}
diff --git a/sql/handler.h b/sql/handler.h
index f3a95022b4f..63d0bf2215c 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -52,7 +52,6 @@ class Rowid_filter;
class Field_string;
class Field_varstring;
class Field_blob;
-class Field_geom;
class Column_definition;
// the following is for checking tables
@@ -213,7 +212,8 @@ enum enum_alter_inplace_result {
#define HA_HAS_NEW_CHECKSUM (1ULL << 38)
#define HA_CAN_VIRTUAL_COLUMNS (1ULL << 39)
#define HA_MRR_CANT_SORT (1ULL << 40)
-#define HA_RECORD_MUST_BE_CLEAN_ON_WRITE (1ULL << 41) /* unused */
+/* All of VARCHAR is stored, including bytes after real varchar data */
+#define HA_RECORD_MUST_BE_CLEAN_ON_WRITE (1ULL << 41)
/*
This storage engine supports condition pushdown
@@ -297,6 +297,9 @@ enum enum_alter_inplace_result {
#define HA_PERSISTENT_TABLE (1ULL << 48)
+/* If storage engine uses another engine as a base */
+#define HA_REUSES_FILE_NAMES (1ULL << 49)
+
/*
Set of all binlog flags. Currently only contain the capabilities
flags.
@@ -511,6 +514,7 @@ enum legacy_db_type
DB_TYPE_BINLOG=21,
DB_TYPE_PBXT=23,
DB_TYPE_PERFORMANCE_SCHEMA=28,
+ DB_TYPE_S3=41,
DB_TYPE_ARIA=42,
DB_TYPE_TOKUDB=43,
DB_TYPE_SEQUENCE=44,
@@ -1019,11 +1023,7 @@ enum enum_schema_tables
SCH_TABLE_PRIVILEGES,
SCH_TRIGGERS,
SCH_USER_PRIVILEGES,
- SCH_VIEWS,
-#ifdef HAVE_SPATIAL
- SCH_GEOMETRY_COLUMNS,
- SCH_SPATIAL_REF_SYS,
-#endif /*HAVE_SPATIAL*/
+ SCH_VIEWS
};
struct TABLE_SHARE;
@@ -1237,11 +1237,6 @@ typedef struct st_order ORDER;
struct handlerton
{
/*
- Historical marker for if the engine is available of not
- */
- SHOW_COMP_OPTION state;
-
- /*
Historical number used for frm file to determine the correct
storage engine. This is going away and new engines will just use
"name" for this.
@@ -1640,6 +1635,14 @@ struct handlerton
int (*discover_table_structure)(handlerton *hton, THD* thd,
TABLE_SHARE *share, HA_CREATE_INFO *info);
+ /*
+ Notify the storage engine that the definition of the table (and the .frm
+ file) has changed. Returns 0 if ok.
+ */
+ int (*notify_tabledef_changed)(handlerton *hton, LEX_CSTRING *db,
+ LEX_CSTRING *table_name, LEX_CUSTRING *frm,
+ LEX_CUSTRING *org_tabledef_version);
+
/*
System Versioning
*/
@@ -1944,11 +1947,13 @@ enum enum_stats_auto_recalc { HA_STATS_AUTO_RECALC_DEFAULT= 0,
It stores the "schema_specification" part of the CREATE/ALTER statements and
is passed to mysql_create_db() and mysql_alter_db().
- Currently consists only of the schema default character set and collation.
+ Currently consists of the schema default character set, collation
+ and schema_comment.
*/
struct Schema_specification_st
{
CHARSET_INFO *default_table_charset;
+ LEX_CSTRING *schema_comment;
void init()
{
bzero(this, sizeof(*this));
@@ -4268,7 +4273,7 @@ public:
*) Update SQL-layer data-dictionary by installing .FRM file for the new version
of the table.
*) Inform the storage engine about this change by calling the
- handler::ha_notify_table_changed() method.
+ hton::notify_table_changed()
*) Destroy the Alter_inplace_info and handler_ctx objects.
*/
@@ -4335,16 +4340,6 @@ public:
bool commit);
- /**
- Public function wrapping the actual handler call.
- @see notify_table_changed()
- */
- void ha_notify_table_changed()
- {
- notify_table_changed();
- }
-
-
protected:
/**
Allows the storage engine to update internal structures with concurrent
@@ -4443,14 +4438,6 @@ protected:
return false;
}
-
- /**
- Notify the storage engine that the table structure (.FRM) has been updated.
-
- @note No errors are allowed during notify_table_changed().
- */
- virtual void notify_table_changed() { }
-
public:
/* End of On-line/in-place ALTER TABLE interface. */
@@ -4474,7 +4461,6 @@ public:
TABLE_SHARE* get_table_share() { return table_share; }
protected:
/* Service methods for use by storage engines. */
- void **ha_data(THD *) const;
THD *ha_thd(void) const;
/**
@@ -4833,11 +4819,6 @@ public:
{
return false;
}
- virtual bool can_convert_geom(const Field_geom *field,
- const Column_definition &new_type) const
- {
- return false;
- }
protected:
Handler_share *get_ha_share_ptr();
@@ -4891,8 +4872,7 @@ static inline bool ha_check_storage_engine_flag(const handlerton *db_type, uint3
static inline bool ha_storage_engine_is_enabled(const handlerton *db_type)
{
- return (db_type && db_type->create) ?
- (db_type->state == SHOW_OPTION_YES) : FALSE;
+ return db_type && db_type->create;
}
#define view_pseudo_hton ((handlerton *)1)
@@ -4908,7 +4888,7 @@ TYPELIB *ha_known_exts(void);
int ha_panic(enum ha_panic_function flag);
void ha_close_connection(THD* thd);
void ha_kill_query(THD* thd, enum thd_kill_levels level);
-bool ha_flush_logs(handlerton *db_type);
+bool ha_flush_logs();
void ha_drop_database(char* path);
void ha_checkpoint_state(bool disable);
void ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *));
diff --git a/sql/item.cc b/sql/item.cc
index eaec0a2a737..162e82c57ea 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -329,6 +329,7 @@ my_decimal *Item::val_decimal_from_real(my_decimal *decimal_value)
my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value)
{
+ DBUG_ASSERT(is_fixed());
longlong nr= val_int();
if (null_value)
return 0;
@@ -448,7 +449,7 @@ const TABLE_SHARE *Item::field_table_or_null()
tables.
*/
Item::Item(THD *thd, Item *item):
- Type_all_attributes(item),
+ Type_all_attributes(*item),
join_tab_idx(item->join_tab_idx),
is_expensive_cache(-1),
rsize(0),
@@ -623,33 +624,34 @@ Item* Item::set_expr_cache(THD *thd)
Item_ident::Item_ident(THD *thd, Name_resolution_context *context_arg,
- const char *db_name_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg)
+ const LEX_CSTRING &db_name_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg)
:Item_result_field(thd), orig_db_name(db_name_arg),
orig_table_name(table_name_arg),
- orig_field_name(*field_name_arg), context(context_arg),
+ orig_field_name(field_name_arg), context(context_arg),
db_name(db_name_arg), table_name(table_name_arg),
- field_name(*field_name_arg),
+ field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(0), depended_from(0), can_be_depended(TRUE)
{
- name= *field_name_arg;
+ name= field_name_arg;
}
Item_ident::Item_ident(THD *thd, TABLE_LIST *view_arg,
- const LEX_CSTRING *field_name_arg)
- :Item_result_field(thd), orig_db_name(NullS),
- orig_table_name(view_arg->table_name.str),
- orig_field_name(*field_name_arg),
+ const LEX_CSTRING &field_name_arg)
+ :Item_result_field(thd), orig_db_name(null_clex_str),
+ orig_table_name(view_arg->table_name),
+ orig_field_name(field_name_arg),
/* TODO: suspicious use of first_select_lex */
context(&view_arg->view->first_select_lex()->context),
- db_name(NullS), table_name(view_arg->alias.str),
- field_name(*field_name_arg),
+ db_name(null_clex_str), table_name(view_arg->alias),
+ field_name(field_name_arg),
alias_name_used(FALSE), cached_field_index(NO_CACHED_FIELD_INDEX),
cached_table(NULL), depended_from(NULL), can_be_depended(TRUE)
{
- name= *field_name_arg;
+ name= field_name_arg;
}
@@ -780,10 +782,10 @@ bool Item_field::rename_fields_processor(void *arg)
while ((def=def_it++))
{
if (def->change.str &&
- (!db_name || !db_name[0] ||
- !my_strcasecmp(table_alias_charset, db_name, rename->db_name.str)) &&
- (!table_name || !table_name[0] ||
- !my_strcasecmp(table_alias_charset, table_name, rename->table_name.str)) &&
+ (!db_name.str || !db_name.str[0] ||
+ !my_strcasecmp(table_alias_charset, db_name.str, rename->db_name.str)) &&
+ (!table_name.str || !table_name.str[0] ||
+ !my_strcasecmp(table_alias_charset, table_name.str, rename->table_name.str)) &&
!my_strcasecmp(system_charset_info, field_name.str, def->change.str))
{
field_name= def->field_name;
@@ -977,7 +979,7 @@ bool Item::check_type_general_purpose_string(const char *opname) const
bool Item::check_type_traditional_scalar(const char *opname) const
{
const Type_handler *handler= type_handler();
- if (handler->is_traditional_type() && handler->is_scalar_type())
+ if (handler->is_traditional_scalar_type())
return false;
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
handler->name().ptr(), opname);
@@ -1291,7 +1293,7 @@ Item *Item::const_charset_converter(THD *thd, CHARSET_INFO *tocs,
uint conv_errors;
Item_string *conv= (func_name ?
new (mem_root)
- Item_static_string_func(thd, func_name,
+ Item_static_string_func(thd, Lex_cstring_strlen(func_name),
s, tocs, &conv_errors,
collation.derivation,
collation.repertoire) :
@@ -1410,7 +1412,7 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
THD *thd= table->in_use;
enum_check_fields tmp= thd->count_cuted_fields;
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
- sql_mode_t sql_mode= thd->variables.sql_mode;
+ Sql_mode_save sms(thd);
thd->variables.sql_mode&= ~(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE);
thd->variables.sql_mode|= MODE_INVALID_DATES;
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -1419,7 +1421,6 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
thd->count_cuted_fields= tmp;
dbug_tmp_restore_column_map(table->write_set, old_map);
- thd->variables.sql_mode= sql_mode;
return res;
}
@@ -2014,7 +2015,7 @@ Item_name_const::Item_name_const(THD *thd, Item *name_arg, Item *val):
Item::maybe_null= TRUE;
if (name_item->basic_const_item() &&
(name_str= name_item->val_str(&name_buffer))) // Can't have a NULL name
- set_name(thd, name_str->ptr(), name_str->length(), name_str->charset());
+ set_name(thd, name_str->lex_cstring(), name_str->charset());
}
@@ -2059,7 +2060,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
return TRUE;
}
if (value_item->collation.derivation == DERIVATION_NUMERIC)
- collation.set_numeric();
+ collation= DTCollation_numeric();
else
collation.set(value_item->collation.collation, DERIVATION_IMPLICIT);
max_length= value_item->max_length;
@@ -2089,8 +2090,8 @@ class Item_aggregate_ref : public Item_ref
{
public:
Item_aggregate_ref(THD *thd, Name_resolution_context *context_arg,
- Item **item, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ Item **item, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ref(thd, context_arg, item, table_name_arg, field_name_arg) {}
virtual inline void print (String *str, enum_query_type query_type)
@@ -2212,8 +2213,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_direct_ref(thd,
&thd->lex->current_select->context,
- &ref_pointer_array[el], 0,
- &name))))
+ &ref_pointer_array[el],
+ null_clex_str, name))))
return; // fatal_error is set
}
else
@@ -2221,8 +2222,8 @@ void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array,
if (!(item_ref= (new (thd->mem_root)
Item_aggregate_ref(thd,
&thd->lex->current_select->context,
- &ref_pointer_array[el], 0,
- &name))))
+ &ref_pointer_array[el],
+ null_clex_str, name))))
return; // fatal_error is set
}
if (type() == SUM_FUNC_ITEM)
@@ -2888,7 +2889,8 @@ Item* Item_ref::build_clone(THD *thd)
/**********************************************/
Item_field::Item_field(THD *thd, Field *f)
- :Item_ident(thd, 0, NullS, *f->table_name, &f->field_name),
+ :Item_ident(thd, 0, null_clex_str,
+ Lex_cstring_strlen(*f->table_name), f->field_name),
item_equal(0),
have_privileges(0), any_privileges(0)
{
@@ -2912,8 +2914,8 @@ Item_field::Item_field(THD *thd, Field *f)
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Field *f)
- :Item_ident(thd, context_arg, f->table->s->db.str, *f->table_name,
- &f->field_name),
+ :Item_ident(thd, context_arg, f->table->s->db,
+ Lex_cstring_strlen(*f->table_name), f->field_name),
item_equal(0),
have_privileges(0), any_privileges(0)
{
@@ -2935,13 +2937,12 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
procedures).
*/
{
- if (db_name)
- orig_db_name= thd->strdup(db_name);
- if (table_name)
- orig_table_name= thd->strdup(table_name);
+ if (db_name.str)
+ orig_db_name= thd->strmake_lex_cstring(db_name);
+ if (table_name.str)
+ orig_table_name= thd->strmake_lex_cstring(table_name);
if (field_name.str)
- thd->make_lex_string(&orig_field_name, field_name.str,
- field_name.length);
+ orig_field_name= thd->strmake_lex_cstring(field_name);
/*
We don't restore 'name' in cleanup because it's not changed
during execution. Still we need it to point to persistent
@@ -2955,8 +2956,9 @@ Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
Item_field::Item_field(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg)
+ const LEX_CSTRING &db_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg)
:Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
field(0), item_equal(0),
have_privileges(0), any_privileges(0)
@@ -2989,9 +2991,9 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
Type_std_attributes::set(field_par->type_std_attributes());
- table_name= *field_par->table_name;
+ table_name= Lex_cstring_strlen(*field_par->table_name);
field_name= field_par->field_name;
- db_name= field_par->table->s->db.str;
+ db_name= field_par->table->s->db;
alias_name_used= field_par->table->alias_name_used;
fixed= 1;
@@ -3074,24 +3076,24 @@ bool Item_field::switch_to_nullable_fields_processor(void *arg)
const char *Item_ident::full_name() const
{
char *tmp;
- if (!table_name || !field_name.str)
+ if (!table_name.str || !field_name.str)
return field_name.str ? field_name.str : name.str ? name.str : "tmp_field";
- if (db_name && db_name[0])
+ if (db_name.str && db_name.str[0])
{
THD *thd= current_thd;
- tmp=(char*) thd->alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
+ tmp=(char*) thd->alloc((uint) db_name.length+ (uint) table_name.length +
(uint) field_name.length+3);
- strxmov(tmp,db_name,".",table_name,".",field_name.str,NullS);
+ strxmov(tmp,db_name.str,".",table_name.str,".",field_name.str,NullS);
}
else
{
- if (table_name[0])
+ if (table_name.str[0])
{
THD *thd= current_thd;
- tmp= (char*) thd->alloc((uint) strlen(table_name) +
+ tmp= (char*) thd->alloc((uint) table_name.length +
field_name.length + 2);
- strxmov(tmp, table_name, ".", field_name.str, NullS);
+ strxmov(tmp, table_name.str, ".", field_name.str, NullS);
}
else
return field_name.str;
@@ -3103,12 +3105,14 @@ void Item_ident::print(String *str, enum_query_type query_type)
{
THD *thd= current_thd;
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
- const char *d_name= db_name, *t_name= table_name;
- bool use_table_name= table_name && table_name[0];
- bool use_db_name= use_table_name && db_name && db_name[0] && !alias_name_used;
+ LEX_CSTRING d_name= db_name;
+ LEX_CSTRING t_name= table_name;
+ bool use_table_name= table_name.str && table_name.str[0];
+ bool use_db_name= use_table_name && db_name.str && db_name.str[0] &&
+ !alias_name_used;
if (use_db_name && (query_type & QT_ITEM_IDENT_SKIP_DB_NAMES))
- use_db_name= !thd->db.str || strcmp(thd->db.str, db_name);
+ use_db_name= !thd->db.str || strcmp(thd->db.str, db_name.str);
if (use_db_name)
use_db_name= !(cached_table && cached_table->belong_to_view &&
@@ -3142,27 +3146,27 @@ void Item_ident::print(String *str, enum_query_type query_type)
{
if (use_table_name)
{
- strmov(t_name_buff, table_name);
+ strmov(t_name_buff, table_name.str);
my_casedn_str(files_charset_info, t_name_buff);
- t_name= t_name_buff;
+ t_name= Lex_cstring_strlen(t_name_buff);
}
if (use_db_name)
{
- strmov(d_name_buff, db_name);
+ strmov(d_name_buff, db_name.str);
my_casedn_str(files_charset_info, d_name_buff);
- d_name= d_name_buff;
+ d_name= Lex_cstring_strlen(d_name_buff);
}
}
if (use_db_name)
{
- append_identifier(thd, str, d_name, (uint)strlen(d_name));
+ append_identifier(thd, str, d_name.str, (uint) d_name.length);
str->append('.');
DBUG_ASSERT(use_table_name);
}
if (use_table_name)
{
- append_identifier(thd, str, t_name, (uint) strlen(t_name));
+ append_identifier(thd, str, t_name.str, (uint) t_name.length);
str->append('.');
}
append_identifier(thd, str, &field_name);
@@ -3310,12 +3314,12 @@ bool Item_field::eq(const Item *item, bool binary_cmp) const
*/
return (!lex_string_cmp(system_charset_info, &item_field->name,
&field_name) &&
- (!item_field->table_name || !table_name ||
- (!my_strcasecmp(table_alias_charset, item_field->table_name,
- table_name) &&
- (!item_field->db_name || !db_name ||
- (item_field->db_name && !strcmp(item_field->db_name,
- db_name))))));
+ (!item_field->table_name.str || !table_name.str ||
+ (!my_strcasecmp(table_alias_charset, item_field->table_name.str,
+ table_name.str) &&
+ (!item_field->db_name.str || !db_name.str ||
+ (item_field->db_name.str && !strcmp(item_field->db_name.str,
+ db_name.str))))));
}
@@ -3874,7 +3878,6 @@ void Item_param::sync_clones()
c->null_value= null_value;
c->Type_std_attributes::operator=(*this);
c->Type_handler_hybrid_field_type::operator=(*this);
- c->Type_geometry_attributes::operator=(*this);
c->state= state;
c->m_empty_string_is_null= m_empty_string_is_null;
@@ -3920,7 +3923,7 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
DBUG_ASSERT(value.type_handler()->cmp_type() == INT_RESULT);
value.integer= (longlong) i;
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= max_length_arg;
decimals= 0;
maybe_null= 0;
@@ -3934,7 +3937,7 @@ void Item_param::set_double(double d)
DBUG_ASSERT(value.type_handler()->cmp_type() == REAL_RESULT);
value.real= d;
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= DBL_DIG + 8;
decimals= NOT_FIXED_DEC;
maybe_null= 0;
@@ -3965,7 +3968,7 @@ void Item_param::set_decimal(const char *str, ulong length)
str2my_decimal(E_DEC_FATAL_ERROR, str, &value.m_decimal, &end);
state= SHORT_DATA_VALUE;
decimals= value.m_decimal.frac;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length=
my_decimal_precision_to_length_no_truncation(value.m_decimal.precision(),
decimals, unsigned_flag);
@@ -3982,7 +3985,7 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
my_decimal2decimal(dv, &value.m_decimal);
decimals= (uint8) value.m_decimal.frac;
- collation.set_numeric();
+ collation= DTCollation_numeric();
unsigned_flag= unsigned_arg;
max_length= my_decimal_precision_to_length(value.m_decimal.intg + decimals,
decimals, unsigned_flag);
@@ -3994,7 +3997,7 @@ void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
{
state= SHORT_DATA_VALUE;
- collation.set_numeric();
+ collation= DTCollation_numeric();
max_length= max_length_arg;
decimals= decimals_arg;
maybe_null= 0;
@@ -4560,9 +4563,9 @@ Item *Item_param::value_clone_item(THD *thd)
case DECIMAL_RESULT:
return 0; // Should create Item_decimal. See MDEV-11361.
case STRING_RESULT:
- return new (mem_root) Item_string(thd, name.str,
- value.m_string.c_ptr_quick(),
- value.m_string.length(),
+ return new (mem_root) Item_string(thd, name,
+ Lex_cstring(value.m_string.c_ptr_quick(),
+ value.m_string.length()),
value.m_string.charset(),
collation.derivation,
collation.repertoire);
@@ -4943,10 +4946,10 @@ static bool mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
DBUG_RETURN(TRUE);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
- const char *db_name= (resolved_item->db_name ?
- resolved_item->db_name : "");
- const char *table_name= (resolved_item->table_name ?
- resolved_item->table_name : "");
+ const char *db_name= (resolved_item->db_name.str ?
+ resolved_item->db_name.str : "");
+ const char *table_name= (resolved_item->table_name.str ?
+ resolved_item->table_name.str : "");
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_WARN_FIELD_RESOLVED,
ER_THD(thd,ER_WARN_FIELD_RESOLVED),
@@ -5040,9 +5043,9 @@ void mark_select_range_as_dependent(THD *thd,
static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
- const char *db_name;
- const char *table_name;
- LEX_CSTRING *field_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name;
+ LEX_CSTRING field_name;
ORDER *found_group= NULL;
int found_match_degree= 0;
char name_buff[SAFE_NAME_LEN+1];
@@ -5052,30 +5055,30 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
{
db_name= ((Item_ident*) find_item)->db_name;
table_name= ((Item_ident*) find_item)->table_name;
- field_name= &((Item_ident*) find_item)->field_name;
+ field_name= ((Item_ident*) find_item)->field_name;
}
else
return NULL;
- if (db_name && lower_case_table_names)
+ if (db_name.str && lower_case_table_names)
{
/* Convert database to lower case for comparison */
- strmake_buf(name_buff, db_name);
+ strmake_buf(name_buff, db_name.str);
my_casedn_str(files_charset_info, name_buff);
- db_name= name_buff;
+ db_name= Lex_cstring_strlen(name_buff);
}
- DBUG_ASSERT(field_name->str != 0);
+ DBUG_ASSERT(field_name.str != 0);
for (ORDER *cur_group= group_list ; cur_group ; cur_group= cur_group->next)
{
int cur_match_degree= 0;
/* SELECT list element with explicit alias */
- if ((*(cur_group->item))->name.str && !table_name &&
+ if ((*(cur_group->item))->name.str && !table_name.str &&
!(*(cur_group->item))->is_autogenerated_name &&
!lex_string_cmp(system_charset_info,
- &(*(cur_group->item))->name, field_name))
+ &(*(cur_group->item))->name, &field_name))
{
++cur_match_degree;
}
@@ -5084,30 +5087,30 @@ static Item** find_field_in_group_list(Item *find_item, ORDER *group_list)
(*(cur_group->item))->type() == Item::REF_ITEM )
{
Item_ident *cur_field= (Item_ident*) *cur_group->item;
- const char *l_db_name= cur_field->db_name;
- const char *l_table_name= cur_field->table_name;
+ const char *l_db_name= cur_field->db_name.str;
+ const char *l_table_name= cur_field->table_name.str;
LEX_CSTRING *l_field_name= &cur_field->field_name;
DBUG_ASSERT(l_field_name->str != 0);
if (!lex_string_cmp(system_charset_info,
- l_field_name, field_name))
+ l_field_name, &field_name))
++cur_match_degree;
else
continue;
- if (l_table_name && table_name)
+ if (l_table_name && table_name.str)
{
/* If field_name is qualified by a table name. */
- if (my_strcasecmp(table_alias_charset, l_table_name, table_name))
+ if (my_strcasecmp(table_alias_charset, l_table_name, table_name.str))
/* Same field names, different tables. */
return NULL;
++cur_match_degree;
- if (l_db_name && db_name)
+ if (l_db_name && db_name.str)
{
/* If field_name is also qualified by a database name. */
- if (strcmp(l_db_name, db_name))
+ if (strcmp(l_db_name, db_name.str))
/* Same field names, different databases. */
return NULL;
++cur_match_degree;
@@ -5576,14 +5579,14 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
rf= (place == IN_HAVING ?
new (thd->mem_root)
Item_ref(thd, context, ref, table_name,
- &field_name, alias_name_used) :
+ field_name, alias_name_used) :
(!select->group_list.elements ?
new (thd->mem_root)
Item_direct_ref(thd, context, ref, table_name,
- &field_name, alias_name_used) :
+ field_name, alias_name_used) :
new (thd->mem_root)
Item_outer_ref(thd, context, ref, table_name,
- &field_name, alias_name_used)));
+ field_name, alias_name_used)));
*ref= save;
if (!rf)
return -1;
@@ -5628,9 +5631,9 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference)
{
Item_ref *rf;
rf= new (thd->mem_root) Item_ref(thd, context,
- (*from_field)->table->s->db.str,
- (*from_field)->table->alias.c_ptr(),
- &field_name);
+ (*from_field)->table->s->db,
+ Lex_cstring_strlen((*from_field)->table->alias.c_ptr()),
+ field_name);
if (!rf)
return -1;
thd->change_item_tree(reference, rf);
@@ -5778,7 +5781,7 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item_field created by the parser with the new Item_ref.
*/
Item_ref *rf= new (thd->mem_root)
- Item_ref(thd, context, db_name, table_name, &field_name);
+ Item_ref(thd, context, db_name, table_name, field_name);
if (!rf)
return 1;
bool err= rf->fix_fields(thd, (Item **) &rf) || rf->check_cols(1);
@@ -5961,7 +5964,7 @@ bool Item_field::post_fix_fields_part_expr_processor(void *int_arg)
/*
Update table_name to be real table name, not the alias. Because alias is
reallocated for every statement, and this item has a long life time */
- table_name= field->table->s->table_name.str;
+ table_name= field->table->s->table_name;
return FALSE;
}
@@ -6158,10 +6161,10 @@ Item *Item_field::replace_equal_field(THD *thd, uchar *arg)
void Item::init_make_send_field(Send_field *tmp_field,
const Type_handler *h)
{
- tmp_field->db_name= "";
- tmp_field->org_table_name= "";
+ tmp_field->db_name= empty_clex_str;
+ tmp_field->org_table_name= empty_clex_str;
tmp_field->org_col_name= empty_clex_str;
- tmp_field->table_name= "";
+ tmp_field->table_name= empty_clex_str;
tmp_field->col_name= name;
tmp_field->flags= (maybe_null ? 0 : NOT_NULL_FLAG) |
(my_binary_compare(charset_for_protocol()) ?
@@ -6320,15 +6323,15 @@ bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs)
void Item_field::make_send_field(THD *thd, Send_field *tmp_field)
{
field->make_send_field(tmp_field);
- DBUG_ASSERT(tmp_field->table_name != 0);
+ DBUG_ASSERT(tmp_field->table_name.str != 0);
if (name.str)
{
DBUG_ASSERT(name.length == strlen(name.str));
tmp_field->col_name= name; // Use user supplied name
}
- if (table_name)
+ if (table_name.str)
tmp_field->table_name= table_name;
- if (db_name)
+ if (db_name.str)
tmp_field->db_name= db_name;
}
@@ -6554,8 +6557,7 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
Item *Item_string::clone_item(THD *thd)
{
return new (thd->mem_root)
- Item_string(thd, name.str, str_value.ptr(),
- str_value.length(), collation.collation);
+ Item_string(thd, name, str_value.lex_cstring(), collation.collation);
}
@@ -7164,7 +7166,7 @@ Item *Item_field::update_value_transformer(THD *thd, uchar *select_arg)
all_fields->push_front((Item*)this, thd->mem_root);
ref= new (thd->mem_root)
Item_ref(thd, &select->context, &ref_pointer_array[el],
- table_name, &field_name);
+ table_name, field_name);
return ref;
}
return this;
@@ -7390,8 +7392,7 @@ Item *get_field_item_for_having(THD *thd, Item *item, st_select_lex *sel)
if (field_item)
{
Item_ref *ref= new (thd->mem_root) Item_ref(thd, &sel->context,
- NullS, NullS,
- &field_item->field_name);
+ field_item->field_name);
return ref;
}
DBUG_ASSERT(0);
@@ -7553,10 +7554,10 @@ void Item_temptable_field::print(String *str, enum_query_type query_type)
Item_ref::Item_ref(THD *thd, Name_resolution_context *context_arg,
- Item **item, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg,
+ Item **item, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
- Item_ident(thd, context_arg, NullS, table_name_arg, field_name_arg),
+ Item_ident(thd, context_arg, null_clex_str, table_name_arg, field_name_arg),
ref(item), reference_trough_name(0)
{
alias_name_used= alias_name_used_arg;
@@ -7603,7 +7604,7 @@ public:
};
Item_ref::Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
Item_ident(thd, view_arg, field_name_arg),
ref(item), reference_trough_name(0)
@@ -8037,7 +8038,7 @@ void Item_ref::print(String *str, enum_query_type query_type)
if ((*ref)->type() != Item::CACHE_ITEM &&
(*ref)->type() != Item::WINDOW_FUNC_ITEM &&
ref_type() != VIEW_REF &&
- !table_name && name.str && alias_name_used)
+ !table_name.str && name.str && alias_name_used)
{
THD *thd= current_thd;
append_identifier(thd, str, &(*ref)->real_item()->name);
@@ -8253,13 +8254,13 @@ void Item_ref::make_send_field(THD *thd, Send_field *field)
/* Non-zero in case of a view */
if (name.str)
field->col_name= name;
- if (table_name)
+ if (table_name.str)
field->table_name= table_name;
- if (db_name)
+ if (db_name.str)
field->db_name= db_name;
if (orig_field_name.str)
field->org_col_name= orig_field_name;
- if (orig_table_name)
+ if (orig_table_name.str)
field->org_table_name= orig_table_name;
}
diff --git a/sql/item.h b/sql/item.h
index 5cda78d42fa..d220f171aed 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -782,10 +782,11 @@ protected:
/**
Create a field based on the exact data type handler.
*/
- Field *create_table_field_from_handler(TABLE *table)
+ Field *create_table_field_from_handler(MEM_ROOT *root, TABLE *table)
{
const Type_handler *h= type_handler();
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ return h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
*this, table);
}
/**
@@ -798,11 +799,12 @@ protected:
@retval NULL error
@retval !NULL on success
*/
- Field *tmp_table_field_from_field_type(TABLE *table)
+ Field *tmp_table_field_from_field_type(MEM_ROOT *root, TABLE *table)
{
DBUG_ASSERT(is_fixed());
const Type_handler *h= type_handler()->type_handler_for_tmp_table(this);
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ return h->make_and_init_table_field(root, &name,
+ Record_addr(maybe_null),
*this, table);
}
/**
@@ -814,17 +816,20 @@ protected:
- does not need to set Field::is_created_from_null_item for the result
See create_tmp_field_ex() for details on parameters and return values.
*/
- Field *create_tmp_field_ex_simple(TABLE *table,
+ Field *create_tmp_field_ex_simple(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!param->make_copy_field());
DBUG_ASSERT(!is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(root, table);
}
- Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
- Field *tmp_table_field_from_field_type_maybe_null(TABLE *table,
+ Field *create_tmp_field_int(MEM_ROOT *root, TABLE *table,
+ uint convert_int_length);
+ Field *tmp_table_field_from_field_type_maybe_null(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param,
bool is_explicit_null);
@@ -945,6 +950,11 @@ public:
#endif
} /*lint -e1509 */
void set_name(THD *thd, const char *str, size_t length, CHARSET_INFO *cs);
+ void set_name(THD *thd, const LEX_CSTRING &str,
+ CHARSET_INFO *cs= system_charset_info)
+ {
+ set_name(thd, str.str, str.length, cs);
+ }
void set_name_no_truncate(THD *thd, const char *str, uint length,
CHARSET_INFO *cs);
void init_make_send_field(Send_field *tmp_field, const Type_handler *h);
@@ -1108,9 +1118,9 @@ public:
{
return type_handler()->max_display_length(this);
}
- TYPELIB *get_typelib() const { return NULL; }
+ const TYPELIB *get_typelib() const { return NULL; }
void set_maybe_null(bool maybe_null_arg) { maybe_null= maybe_null_arg; }
- void set_typelib(TYPELIB *typelib)
+ void set_typelib(const TYPELIB *typelib)
{
// Non-field Items (e.g. hybrid functions) never have ENUM/SET types yet.
DBUG_ASSERT(0);
@@ -1499,8 +1509,7 @@ public:
int save_str_value_in_field(Field *field, String *result);
virtual Field *get_tmp_table_field() { return 0; }
- virtual Field *create_field_for_create_select(TABLE *table);
- virtual Field *create_field_for_schema(THD *thd, TABLE *table);
+ virtual Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table);
virtual const char *full_name() const { return name.str ? name.str : "???"; }
const char *field_name_or_null()
{ return real_item()->type() == Item::FIELD_ITEM ? name.str : NULL; }
@@ -2066,7 +2075,8 @@ public:
const Type_handler *type_handler_long_or_longlong() const
{
- return Type_handler::type_handler_long_or_longlong(max_char_length());
+ return Type_handler::type_handler_long_or_longlong(max_char_length(),
+ unsigned_flag);
}
/**
@@ -2077,7 +2087,8 @@ public:
@retval NULL (on error)
@retval a pointer to a newly create Field (on success)
*/
- virtual Field *create_tmp_field_ex(TABLE *table,
+ virtual Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)= 0;
virtual Item_field *field_for_view_update() { return 0; }
@@ -2203,14 +2214,6 @@ public:
is_expensive_cache= walk(&Item::is_expensive_processor, 0, NULL);
return MY_TEST(is_expensive_cache);
}
- virtual Field::geometry_type get_geometry_type() const
- { return Field::GEOM_GEOMETRY; };
- uint uint_geometry_type() const
- { return get_geometry_type(); }
- void set_geometry_type(uint type)
- {
- DBUG_ASSERT(0);
- }
String *check_well_formed_result(String *str, bool send_error= 0);
bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs);
bool too_big_for_varchar() const
@@ -2421,56 +2424,6 @@ public:
};
-class Type_geometry_attributes
-{
- uint m_geometry_type;
- static const uint m_geometry_type_unknown= Field::GEOM_GEOMETRYCOLLECTION + 1;
- void copy(const Type_handler *handler, const Type_all_attributes *gattr)
- {
- // Ignore implicit NULLs
- m_geometry_type= handler == &type_handler_geometry ?
- gattr->uint_geometry_type() :
- m_geometry_type_unknown;
- }
-public:
- Type_geometry_attributes()
- :m_geometry_type(m_geometry_type_unknown)
- { }
- Type_geometry_attributes(const Type_handler *handler,
- const Type_all_attributes *gattr)
- :m_geometry_type(m_geometry_type_unknown)
- {
- copy(handler, gattr);
- }
- void join(const Item *item)
- {
- // Ignore implicit NULLs
- if (m_geometry_type == m_geometry_type_unknown)
- copy(item->type_handler(), item);
- else if (item->type_handler() == &type_handler_geometry)
- {
- m_geometry_type=
- Field_geom::geometry_type_merge((Field_geom::geometry_type)
- m_geometry_type,
- (Field_geom::geometry_type)
- item->uint_geometry_type());
- }
- }
- Field::geometry_type get_geometry_type() const
- {
- return m_geometry_type == m_geometry_type_unknown ?
- Field::GEOM_GEOMETRY :
- (Field::geometry_type) m_geometry_type;
- }
- void set_geometry_type(uint type)
- {
- DBUG_ASSERT(type <= m_geometry_type_unknown);
- m_geometry_type= type;
- }
-};
-
-
-
/**
Compare two Items for List<Item>::add_unique()
*/
@@ -2709,7 +2662,8 @@ protected:
}
Item_basic_value(THD *thd): Item(thd) {}
public:
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -2721,7 +2675,8 @@ public:
DECLARE c CURSOR FOR SELECT 'test';
OPEN c;
*/
- return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ return tmp_table_field_from_field_type_maybe_null(root,
+ table, src, param,
type() == Item::NULL_ITEM);
}
bool eq(const Item *item, bool binary_cmp) const;
@@ -2793,10 +2748,11 @@ public:
inline bool const_item() const;
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
inline int save_in_field(Field *field, bool no_conversions);
inline bool send(Protocol *protocol, st_value *buffer);
@@ -2899,8 +2855,8 @@ public:
The inherited implementation would create a column
based on result_type(), which is less exact.
*/
- Field *create_field_for_create_select(TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
bool is_valid_limit_clause_variable_with_error() const
{
@@ -3089,7 +3045,8 @@ public:
return TRUE;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
@@ -3097,7 +3054,7 @@ public:
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
OPEN c;
*/
- return tmp_table_field_from_field_type_maybe_null(table, src, param,
+ return tmp_table_field_from_field_type_maybe_null(root, table, src, param,
type() == Item::NULL_ITEM);
}
int save_in_field(Field *field, bool no_conversions)
@@ -3133,7 +3090,7 @@ public:
class Item_num: public Item_literal
{
public:
- Item_num(THD *thd): Item_literal(thd) { collation.set_numeric(); }
+ Item_num(THD *thd): Item_literal(thd) { collation= DTCollation_numeric(); }
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
@@ -3157,7 +3114,7 @@ public:
{}
~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param);
/*
@@ -3185,14 +3142,14 @@ protected:
updated during fix_fields() to values from Field object and life-time
of those is shorter than life-time of Item_field.
*/
- const char *orig_db_name;
- const char *orig_table_name;
+ LEX_CSTRING orig_db_name;
+ LEX_CSTRING orig_table_name;
LEX_CSTRING orig_field_name;
public:
Name_resolution_context *context;
- const char *db_name;
- const char *table_name;
+ LEX_CSTRING db_name;
+ LEX_CSTRING table_name;
LEX_CSTRING field_name;
bool alias_name_used; /* true if item was resolved against alias */
/*
@@ -3222,10 +3179,10 @@ public:
*/
bool can_be_depended;
Item_ident(THD *thd, Name_resolution_context *context_arg,
- const char *db_name_arg, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg);
+ const LEX_CSTRING &db_name_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg);
Item_ident(THD *thd, Item_ident *item);
- Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING *field_name_arg);
+ Item_ident(THD *thd, TABLE_LIST *view_arg, const LEX_CSTRING &field_name_arg);
const char *full_name() const;
void cleanup();
st_select_lex *get_depended_from() const;
@@ -3260,8 +3217,15 @@ public:
/* field need any privileges (for VIEW creation) */
bool any_privileges;
Item_field(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg,const char *table_name_arg,
- const LEX_CSTRING *field_name_arg);
+ const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg);
+ Item_field(THD *thd, Name_resolution_context *context_arg,
+ const LEX_CSTRING &field_name_arg)
+ :Item_field(thd, context_arg, null_clex_str, null_clex_str, field_name_arg)
+ { }
+ Item_field(THD *thd, Name_resolution_context *context_arg)
+ :Item_field(thd, context_arg, null_clex_str, null_clex_str, null_clex_str)
+ { }
/*
Constructor needed to process subselect with temporary tables (see Item)
*/
@@ -3338,12 +3302,13 @@ public:
return &type_handler_null;
return field->type_handler();
}
- Field *create_tmp_field_from_item_field(TABLE *new_table,
+ Field *create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root,
+ TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
- TYPELIB *get_typelib() const { return field->get_typelib(); }
+ const TYPELIB *get_typelib() const { return field->get_typelib(); }
enum_monotonicity_info get_monotonicity_info() const
{
return MONOTONIC_STRICT_INCREASING;
@@ -3456,11 +3421,6 @@ public:
DBUG_ASSERT(fixed);
return field->table->pos_in_table_list->outer_join;
}
- Field::geometry_type get_geometry_type() const
- {
- DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY);
- return field->get_geometry_type();
- }
bool check_index_dependence(void *arg);
friend class Item_default_value;
friend class Item_insert_value;
@@ -3589,7 +3549,7 @@ public:
{
return result_field->type();
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -3636,8 +3596,7 @@ public:
class Item_param :public Item_basic_value,
private Settable_routine_parameter,
public Rewritable_query_parameter,
- private Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ private Type_handler_hybrid_field_type
{
/*
NO_VALUE is a special value meaning that the parameter has not been
@@ -3796,12 +3755,6 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field::geometry_type get_geometry_type() const
- { return Type_geometry_attributes::get_geometry_type(); };
-
- void set_geometry_type(uint type)
- { Type_geometry_attributes::set_geometry_type(type); }
-
Item_param(THD *thd, const LEX_CSTRING *name_arg,
uint pos_in_query_arg, uint len_in_query_arg);
@@ -3944,7 +3897,7 @@ public:
bool set_limit_clause_param(longlong nr)
{
- value.set_handler(&type_handler_longlong);
+ value.set_handler(&type_handler_slonglong);
set_int(nr, MY_INT64_NUM_DECIMAL_DIGITS);
return !unsigned_flag && value.integer < 0;
}
@@ -4064,8 +4017,8 @@ public:
Item_int(THD *thd, const char *str_arg, size_t length=64);
const Type_handler *type_handler() const
{ return type_handler_long_or_longlong(); }
- Field *create_field_for_create_select(TABLE *table)
- { return tmp_table_field_from_field_type(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return tmp_table_field_from_field_type(root, table); }
const longlong *const_ptr_longlong() const { return &value; }
longlong val_int() { return value; }
longlong val_int_min() const { return value; }
@@ -4259,7 +4212,7 @@ protected:
const Metadata metadata)
{
fix_from_value(dv, metadata);
- set_name(thd, str_value.ptr(), str_value.length(), str_value.charset());
+ set_name(thd, str_value.lex_cstring(), str_value.charset());
}
protected:
/* Just create an item and do not fill string representation */
@@ -4306,21 +4259,21 @@ public:
fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire));
}
// Constructors with an externally provided item name
- Item_string(THD *thd, const char *name_par, const char *str, size_t length,
+ Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
:Item_literal(thd)
{
- str_value.set_or_copy_aligned(str, length, cs);
+ str_value.set_or_copy_aligned(str.str, str.length, cs);
fix_from_value(dv, Metadata(&str_value));
- set_name(thd, name_par,safe_strlen(name_par), system_charset_info);
+ set_name(thd, name_par);
}
- Item_string(THD *thd, const char *name_par, const char *str, size_t length,
+ Item_string(THD *thd, const LEX_CSTRING &name_par, const LEX_CSTRING &str,
CHARSET_INFO *cs, Derivation dv, uint repertoire)
:Item_literal(thd)
{
- str_value.set_or_copy_aligned(str, length, cs);
+ str_value.set_or_copy_aligned(str.str, str.length, cs);
fix_from_value(dv, Metadata(&str_value, repertoire));
- set_name(thd, name_par, safe_strlen(name_par), system_charset_info);
+ set_name(thd, name_par);
}
void print_value(String *to) const
{
@@ -4395,13 +4348,13 @@ public:
class Item_string_with_introducer :public Item_string
{
public:
- Item_string_with_introducer(THD *thd, const char *str, uint length,
+ Item_string_with_introducer(THD *thd, const LEX_CSTRING &str,
CHARSET_INFO *cs):
- Item_string(thd, str, length, cs)
+ Item_string(thd, str.str, str.length, cs)
{ }
- Item_string_with_introducer(THD *thd, const char *name_arg,
- const char *str, uint length, CHARSET_INFO *tocs):
- Item_string(thd, name_arg, str, length, tocs)
+ Item_string_with_introducer(THD *thd, const LEX_CSTRING &name_arg,
+ const LEX_CSTRING &str, CHARSET_INFO *tocs):
+ Item_string(thd, name_arg, str, tocs)
{ }
virtual bool is_cs_specified() const
{
@@ -4438,14 +4391,14 @@ public:
class Item_static_string_func :public Item_string
{
- const char *func_name;
+ const LEX_CSTRING func_name;
public:
- Item_static_string_func(THD *thd, const char *name_par, const char *str,
- uint length, CHARSET_INFO *cs,
+ Item_static_string_func(THD *thd, const LEX_CSTRING &name_par,
+ const LEX_CSTRING &str, CHARSET_INFO *cs,
Derivation dv= DERIVATION_COERCIBLE):
- Item_string(thd, NullS, str, length, cs, dv), func_name(name_par)
+ Item_string(thd, LEX_CSTRING({NullS,0}), str, cs, dv), func_name(name_par)
{}
- Item_static_string_func(THD *thd, const char *name_par,
+ Item_static_string_func(THD *thd, const LEX_CSTRING &name_par,
const String *str,
CHARSET_INFO *tocs, uint *conv_errors,
Derivation dv, uint repertoire):
@@ -4454,7 +4407,7 @@ public:
{}
Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs)
{
- return const_charset_converter(thd, tocs, true, func_name);
+ return const_charset_converter(thd, tocs, true, func_name.str);
}
virtual inline void print(String *str, enum_query_type query_type)
@@ -4467,7 +4420,7 @@ public:
bool check_vcol_func_processor(void *arg)
{ // VCOL_TIME_FUNC because the value is not constant, but does not
// require fix_fields() to be re-run for every statement.
- return mark_unsupported_function(func_name, arg, VCOL_TIME_FUNC);
+ return mark_unsupported_function(func_name.str, arg, VCOL_TIME_FUNC);
}
};
@@ -4476,53 +4429,16 @@ public:
class Item_partition_func_safe_string: public Item_string
{
public:
- Item_partition_func_safe_string(THD *thd, const char *name_arg, uint length,
- CHARSET_INFO *cs= NULL):
- Item_string(thd, name_arg, length, cs)
- {}
- bool check_vcol_func_processor(void *arg)
- {
- return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE);
- }
-};
-
-
-class Item_return_date_time :public Item_partition_func_safe_string
-{
- enum_field_types date_time_field_type;
-public:
- Item_return_date_time(THD *thd, const char *name_arg, uint length_arg,
- enum_field_types field_type_arg, uint dec_arg= 0):
- Item_partition_func_safe_string(thd, name_arg, length_arg, &my_charset_bin),
- date_time_field_type(field_type_arg)
- { decimals= dec_arg; }
- const Type_handler *type_handler() const
+ Item_partition_func_safe_string(THD *thd, const LEX_CSTRING &name_arg,
+ uint length, CHARSET_INFO *cs):
+ Item_string(thd, name_arg, LEX_CSTRING({0,0}), cs)
{
- return Type_handler::get_handler_by_field_type(date_time_field_type);
- }
-};
-
-
-class Item_blob :public Item_partition_func_safe_string
-{
-public:
- Item_blob(THD *thd, const char *name_arg, uint length):
- Item_partition_func_safe_string(thd, name_arg, (uint) safe_strlen(name_arg),
- &my_charset_bin)
- { max_length= length; }
- enum Type type() const { return TYPE_HOLDER; }
- const Type_handler *type_handler() const
- {
- return Type_handler::blob_type_handler(max_length);
+ max_length= length;
}
- const Type_handler *real_type_handler() const
+ bool check_vcol_func_processor(void *arg)
{
- // Should not be called, Item_blob is used for SHOW purposes only.
- DBUG_ASSERT(0);
- return &type_handler_varchar;
+ return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE);
}
- Field *create_field_for_schema(THD *thd, TABLE *table)
- { return tmp_table_field_from_field_type(table); }
};
@@ -4535,15 +4451,15 @@ public:
class Item_empty_string :public Item_partition_func_safe_string
{
public:
- Item_empty_string(THD *thd, const char *header,uint length,
- CHARSET_INFO *cs= NULL):
- Item_partition_func_safe_string(thd, "", 0,
- cs ? cs : &my_charset_utf8_general_ci)
- {
- name.str= header;
- name.length= strlen(name.str);
- max_length= length * collation.collation->mbmaxlen;
- }
+ Item_empty_string(THD *thd, const LEX_CSTRING &header, uint length,
+ CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci)
+ :Item_partition_func_safe_string(thd, header, length * cs->mbmaxlen, cs)
+ { }
+ Item_empty_string(THD *thd, const char *header, uint length,
+ CHARSET_INFO *cs= &my_charset_utf8mb3_general_ci)
+ :Item_partition_func_safe_string(thd, LEX_CSTRING({header, strlen(header)}),
+ length * cs->mbmaxlen, cs)
+ { }
void make_send_field(THD *thd, Send_field *field);
};
@@ -4560,7 +4476,9 @@ public:
}
const Type_handler *type_handler() const
{
- return Type_handler::get_handler_by_field_type(int_field_type);
+ const Type_handler *h=
+ Type_handler::get_handler_by_field_type(int_field_type);
+ return unsigned_flag ? h->type_handler_unsigned() : h;
}
};
@@ -4740,14 +4658,14 @@ public:
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime)
:Item_literal(thd)
{
- collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
+ collation= DTCollation_numeric();
decimals= 0;
cached_time= *ltime;
}
Item_temporal_literal(THD *thd, const MYSQL_TIME *ltime, uint dec_arg):
Item_literal(thd)
{
- collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII);
+ collation= DTCollation_numeric();
decimals= dec_arg;
cached_time= *ltime;
}
@@ -5133,10 +5051,14 @@ public:
Item **ref;
bool reference_trough_name;
Item_ref(THD *thd, Name_resolution_context *context_arg,
- const char *db_arg, const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ const LEX_CSTRING &db_arg, const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ident(thd, context_arg, db_arg, table_name_arg, field_name_arg),
set_properties_only(0), ref(0), reference_trough_name(1) {}
+ Item_ref(THD *thd, Name_resolution_context *context_arg,
+ const LEX_CSTRING &field_name_arg)
+ :Item_ref(thd, context_arg, null_clex_str, null_clex_str, field_name_arg)
+ { }
/*
This constructor is used in two scenarios:
A) *item = NULL
@@ -5152,10 +5074,10 @@ public:
with Bar, and if we have a more broader set of problems like this.
*/
Item_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg, const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE);
Item_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg, bool alias_name_used_arg= FALSE);
+ const LEX_CSTRING &field_name_arg, bool alias_name_used_arg= FALSE);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item)
@@ -5200,7 +5122,7 @@ public:
Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
Item* propagate_equal_fields(THD *, const Context &, COND_EQUAL *);
table_map used_tables() const;
@@ -5237,7 +5159,7 @@ public:
{
return ref ? (*ref)->real_item() : this;
}
- TYPELIB *get_typelib() const
+ const TYPELIB *get_typelib() const
{
return ref ? (*ref)->get_typelib() : NULL;
}
@@ -5370,8 +5292,8 @@ class Item_direct_ref :public Item_ref
{
public:
Item_direct_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE):
Item_ref(thd, context_arg, item, table_name_arg,
field_name_arg, alias_name_used_arg)
@@ -5379,7 +5301,7 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
Item_direct_ref(THD *thd, TABLE_LIST *view_arg, Item **item,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &field_name_arg,
bool alias_name_used_arg= FALSE):
Item_ref(thd, view_arg, item, field_name_arg,
alias_name_used_arg)
@@ -5419,7 +5341,7 @@ class Item_direct_ref_to_ident :public Item_direct_ref
public:
Item_direct_ref_to_ident(THD *thd, Item_ident *item):
Item_direct_ref(thd, item->context, (Item**)&item, item->table_name,
- &item->field_name, FALSE)
+ item->field_name, FALSE)
{
ident= item;
ref= (Item**)&ident;
@@ -5611,8 +5533,8 @@ class Item_direct_view_ref :public Item_direct_ref
public:
Item_direct_view_ref(THD *thd, Name_resolution_context *context_arg,
Item **item,
- const char *table_name_arg,
- LEX_CSTRING *field_name_arg,
+ LEX_CSTRING &table_name_arg,
+ LEX_CSTRING &field_name_arg,
TABLE_LIST *view_arg):
Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg),
item_equal(0), view(view_arg),
@@ -5785,7 +5707,7 @@ public:
Item_outer_ref(THD *thd, Name_resolution_context *context_arg,
Item_field *outer_field_arg):
Item_direct_ref(thd, context_arg, 0, outer_field_arg->table_name,
- &outer_field_arg->field_name),
+ outer_field_arg->field_name),
outer_ref(outer_field_arg), in_sum_func(0),
found_in_select_list(0), found_in_group_by(0)
{
@@ -5794,7 +5716,7 @@ public:
fixed= 0; /* reset flag set in set_properties() */
}
Item_outer_ref(THD *thd, Name_resolution_context *context_arg, Item **item,
- const char *table_name_arg, LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &table_name_arg, LEX_CSTRING &field_name_arg,
bool alias_name_used_arg):
Item_direct_ref(thd, context_arg, item, table_name_arg, field_name_arg,
alias_name_used_arg),
@@ -5835,8 +5757,8 @@ protected:
public:
Item_ref_null_helper(THD *thd, Name_resolution_context *context_arg,
Item_in_subselect* master, Item **item,
- const char *table_name_arg,
- const LEX_CSTRING *field_name_arg):
+ const LEX_CSTRING &table_name_arg,
+ const LEX_CSTRING &field_name_arg):
Item_ref(thd, context_arg, item, table_name_arg, field_name_arg),
owner(master) {}
void save_val(Field *to);
@@ -5880,14 +5802,11 @@ public:
};
#ifdef MYSQL_SERVER
-#include "gstream.h"
-#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
#include "item_row.h"
#include "item_cmpfunc.h"
#include "item_strfunc.h"
-#include "item_geofunc.h"
#include "item_timefunc.h"
#include "item_subselect.h"
#include "item_xmlfunc.h"
@@ -5964,7 +5883,7 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -6204,16 +6123,13 @@ class Item_default_value : public Item_field
public:
Item *arg;
Item_default_value(THD *thd, Name_resolution_context *context_arg)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(NULL) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(a) {}
Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(NULL) {}
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
@@ -6300,8 +6216,7 @@ class Item_insert_value : public Item_field
public:
Item *arg;
Item_insert_value(THD *thd, Name_resolution_context *context_arg, Item *a)
- :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL,
- &null_clex_str),
+ :Item_field(thd, context_arg),
arg(a) {}
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
@@ -6362,10 +6277,9 @@ public:
Item_trigger_field(THD *thd, Name_resolution_context *context_arg,
row_version_type row_ver_arg,
- const LEX_CSTRING *field_name_arg,
+ const LEX_CSTRING &field_name_arg,
ulong priv, const bool ro)
- :Item_field(thd, context_arg,
- (const char *)NULL, (const char *)NULL, field_name_arg),
+ :Item_field(thd, context_arg, field_name_arg),
row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv),
want_privilege(priv), table_grants(NULL), read_only (ro)
{}
@@ -6487,10 +6401,10 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
virtual void keep_array() {}
@@ -6590,8 +6504,6 @@ class Item_cache_int: public Item_cache
protected:
longlong value;
public:
- Item_cache_int(THD *thd): Item_cache(thd, &type_handler_longlong),
- value(0) {}
Item_cache_int(THD *thd, const Type_handler *handler):
Item_cache(thd, handler), value(0) {}
@@ -6988,11 +6900,10 @@ public:
single SP/PS execution.
*/
class Item_type_holder: public Item,
- public Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ public Type_handler_hybrid_field_type
{
protected:
- TYPELIB *enum_set_typelib;
+ const TYPELIB *enum_set_typelib;
public:
Item_type_holder(THD *thd, Item *item)
:Item(thd, item),
@@ -7009,7 +6920,6 @@ public:
bool maybe_null_arg)
:Item(thd),
Type_handler_hybrid_field_type(handler),
- Type_geometry_attributes(handler, attr),
enum_set_typelib(attr->get_typelib())
{
name= item->name;
@@ -7028,27 +6938,19 @@ public:
}
enum Type type() const { return TYPE_HOLDER; }
- TYPELIB *get_typelib() const { return enum_set_typelib; }
+ const TYPELIB *get_typelib() const { return enum_set_typelib; }
double val_real();
longlong val_int();
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return Item_type_holder::real_type_handler()->
- make_and_init_table_field(&name, Record_addr(maybe_null),
+ make_and_init_table_field(root, &name, Record_addr(maybe_null),
*this, table);
}
- Field::geometry_type get_geometry_type() const
- {
- return Type_geometry_attributes::get_geometry_type();
- }
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
Item* get_copy(THD *thd) { return 0; }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 02fc7719fbc..24ffaeab98e 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2119,7 +2119,7 @@ bool Item_func_between::fix_length_and_dec_numeric(THD *thd)
if (cvt_arg1 && cvt_arg2)
{
// Works for all types
- m_comparator.set_handler(&type_handler_longlong);
+ m_comparator.set_handler(&type_handler_slonglong);
}
}
}
@@ -4461,7 +4461,7 @@ bool Item_func_in::value_list_convert_const_to_int(THD *thd)
all_converted= false;
}
if (all_converted)
- m_comparator.set_handler(&type_handler_longlong);
+ m_comparator.set_handler(&type_handler_slonglong);
}
}
return thd->is_fatal_error; // Catch errrors in convert_const_to_int
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 63c131cd8f4..0e9b573f106 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1421,7 +1421,7 @@ public:
((Item_int*) item)->unsigned_flag= (bool)
((packed_longlong*) base)[pos].unsigned_flag;
}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
friend int cmp_longlong(void *cmp_arg, packed_longlong *a,packed_longlong *b);
};
@@ -2794,7 +2794,6 @@ class Regexp_processor_pcre
bool m_conversion_is_needed;
bool m_is_const;
int m_library_flags;
- CHARSET_INFO *m_data_charset;
CHARSET_INFO *m_library_charset;
String m_prev_pattern;
int m_pcre_exec_rc;
@@ -2811,8 +2810,7 @@ public:
Regexp_processor_pcre() :
m_pcre(NULL), m_conversion_is_needed(true), m_is_const(0),
m_library_flags(0),
- m_data_charset(&my_charset_utf8_general_ci),
- m_library_charset(&my_charset_utf8_general_ci)
+ m_library_charset(&my_charset_utf8mb3_general_ci)
{
m_pcre_extra.flags= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
m_pcre_extra.match_limit_recursion= 100L;
@@ -2829,7 +2827,7 @@ public:
// Convert text data to utf-8.
m_library_charset= data_charset == &my_charset_bin ?
- &my_charset_bin : &my_charset_utf8_general_ci;
+ &my_charset_bin : &my_charset_utf8mb3_general_ci;
m_conversion_is_needed= (data_charset != &my_charset_bin) &&
!my_charset_same(data_charset, m_library_charset);
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 9b949835e27..7fabb90b5ef 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -35,6 +35,7 @@
#include "sp.h"
#include "item_inetfunc.h"
#include "sql_time.h"
+#include "sql_type_geom.h"
/*
=============================================================================
@@ -43,109 +44,6 @@
*/
/**
- Adapter for functions that takes exactly zero arguments.
-*/
-
-class Create_func_arg0 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list);
-
- /**
- Builder method, with no arguments.
- @param thd The current thread
- @return An item representing the function call
- */
- virtual Item *create_builder(THD *thd) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg0() {}
- /** Destructor. */
- virtual ~Create_func_arg0() {}
-};
-
-
-/**
- Adapter for functions that takes exactly one argument.
-*/
-
-class Create_func_arg1 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /**
- Builder method, with one argument.
- @param thd The current thread
- @param arg1 The first argument of the function
- @return An item representing the function call
- */
- virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg1() {}
- /** Destructor. */
- virtual ~Create_func_arg1() {}
-};
-
-
-/**
- Adapter for functions that takes exactly two arguments.
-*/
-
-class Create_func_arg2 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /**
- Builder method, with two arguments.
- @param thd The current thread
- @param arg1 The first argument of the function
- @param arg2 The second argument of the function
- @return An item representing the function call
- */
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg2() {}
- /** Destructor. */
- virtual ~Create_func_arg2() {}
-};
-
-
-/**
- Adapter for functions that takes exactly three arguments.
-*/
-
-class Create_func_arg3 : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /**
- Builder method, with three arguments.
- @param thd The current thread
- @param arg1 The first argument of the function
- @param arg2 The second argument of the function
- @param arg3 The third argument of the function
- @return An item representing the function call
- */
- virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
-
-protected:
- /** Constructor. */
- Create_func_arg3() {}
- /** Destructor. */
- virtual ~Create_func_arg3() {}
-};
-
-
-/**
Function builder for Stored Functions.
*/
@@ -165,30 +63,6 @@ protected:
};
-#ifndef HAVE_SPATIAL
-/**
- Common (non) builder for geometry functions.
- This builder is used in <code>--without-geometry</code> builds only,
- to report an error.
-*/
-
-class Create_func_no_geom : public Create_func
-{
-public:
- virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- /** Singleton. */
- static Create_func_no_geom s_singleton;
-
-protected:
- /** Constructor. */
- Create_func_no_geom() {}
- /** Destructor. */
- virtual ~Create_func_no_geom() {}
-};
-#endif
-
-
/*
Concrete functions builders (native functions).
Please keep this list sorted in alphabetical order,
@@ -260,51 +134,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_area : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_area s_singleton;
-
-protected:
- Create_func_area() {}
- virtual ~Create_func_area() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_as_wkb : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_as_wkb s_singleton;
-
-protected:
- Create_func_as_wkb() {}
- virtual ~Create_func_as_wkb() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_as_wkt : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_as_wkt s_singleton;
-
-protected:
- Create_func_as_wkt() {}
- virtual ~Create_func_as_wkt() {}
-};
-#endif
-
-
class Create_func_asin : public Create_func_arg1
{
public:
@@ -409,20 +238,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_centroid : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_centroid s_singleton;
-
-protected:
- Create_func_centroid() {}
- virtual ~Create_func_centroid() {}
-};
-
-
class Create_func_chr : public Create_func_arg1
{
public:
@@ -436,35 +251,6 @@ protected:
};
-class Create_func_convexhull : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_convexhull s_singleton;
-
-protected:
- Create_func_convexhull() {}
- virtual ~Create_func_convexhull() {}
-};
-
-
-class Create_func_pointonsurface : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_pointonsurface s_singleton;
-
-protected:
- Create_func_pointonsurface() {}
- virtual ~Create_func_pointonsurface() {}
-};
-
-
-#endif /*HAVE_SPATIAL*/
-
-
class Create_func_char_length : public Create_func_arg1
{
public:
@@ -630,34 +416,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_contains : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_contains s_singleton;
-
- protected:
- Create_func_mbr_contains() {}
- virtual ~Create_func_mbr_contains() {}
-};
-
-
-class Create_func_contains : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_contains s_singleton;
-
-protected:
- Create_func_contains() {}
- virtual ~Create_func_contains() {}
-};
-#endif
-
-
class Create_func_nvl2 : public Create_func_arg3
{
public:
@@ -736,21 +494,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_crosses : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_crosses s_singleton;
-
-protected:
- Create_func_crosses() {}
- virtual ~Create_func_crosses() {}
-};
-#endif
-
-
class Create_func_datediff : public Create_func_arg2
{
public:
@@ -855,62 +598,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_dimension : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_dimension s_singleton;
-
-protected:
- Create_func_dimension() {}
- virtual ~Create_func_dimension() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_disjoint : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_disjoint s_singleton;
-
- protected:
- Create_func_mbr_disjoint() {}
- virtual ~Create_func_mbr_disjoint() {}
-};
-
-
-class Create_func_disjoint : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_disjoint s_singleton;
-
-protected:
- Create_func_disjoint() {}
- virtual ~Create_func_disjoint() {}
-};
-
-
-class Create_func_distance : public Create_func_arg2
-{
- public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_distance s_singleton;
-
- protected:
- Create_func_distance() {}
- virtual ~Create_func_distance() {}
-};
-#endif
-
-
class Create_func_elt : public Create_native_func
{
public:
@@ -950,76 +637,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_endpoint : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_endpoint s_singleton;
-
-protected:
- Create_func_endpoint() {}
- virtual ~Create_func_endpoint() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_envelope : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_envelope s_singleton;
-
-protected:
- Create_func_envelope() {}
- virtual ~Create_func_envelope() {}
-};
-
-class Create_func_boundary : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_boundary s_singleton;
-
-protected:
- Create_func_boundary() {}
- virtual ~Create_func_boundary() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_equals : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_equals s_singleton;
-
- protected:
- Create_func_mbr_equals() {}
- virtual ~Create_func_mbr_equals() {}
-};
-
-
-class Create_func_equals : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_equals s_singleton;
-
-protected:
- Create_func_equals() {}
- virtual ~Create_func_equals() {}
-};
-#endif
-
-
class Create_func_exp : public Create_func_arg1
{
public:
@@ -1046,21 +663,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_exteriorring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_exteriorring s_singleton;
-
-protected:
- Create_func_exteriorring() {}
- virtual ~Create_func_exteriorring() {}
-};
-#endif
-
-
class Create_func_field : public Create_native_func
{
public:
@@ -1165,94 +767,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_text : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_text s_singleton;
-
-protected:
- Create_func_geometry_from_text() {}
- virtual ~Create_func_geometry_from_text() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_wkb : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_wkb s_singleton;
-
-protected:
- Create_func_geometry_from_wkb() {}
- virtual ~Create_func_geometry_from_wkb() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_from_json : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_geometry_from_json s_singleton;
-
-protected:
- Create_func_geometry_from_json() {}
- virtual ~Create_func_geometry_from_json() {}
-};
-
-
-class Create_func_as_geojson : public Create_native_func
-{
-public:
- virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
-
- static Create_func_as_geojson s_singleton;
-
-protected:
- Create_func_as_geojson() {}
- virtual ~Create_func_as_geojson() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometry_type : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_geometry_type s_singleton;
-
-protected:
- Create_func_geometry_type() {}
- virtual ~Create_func_geometry_type() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_geometryn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_geometryn s_singleton;
-
-protected:
- Create_func_geometryn() {}
- virtual ~Create_func_geometryn() {}
-};
-#endif
-
-
class Create_func_get_lock : public Create_func_arg2
{
public:
@@ -1266,36 +780,6 @@ protected:
};
-#if defined(HAVE_SPATIAL) && !defined(DBUG_OFF)
-class Create_func_gis_debug : public Create_func_arg1
-{
- public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_gis_debug s_singleton;
-
- protected:
- Create_func_gis_debug() {}
- virtual ~Create_func_gis_debug() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_glength : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_glength s_singleton;
-
-protected:
- Create_func_glength() {}
- virtual ~Create_func_glength() {}
-};
-#endif
-
-
class Create_func_greatest : public Create_native_func
{
public:
@@ -1452,127 +936,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_interiorringn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_interiorringn s_singleton;
-
-protected:
- Create_func_interiorringn() {}
- virtual ~Create_func_interiorringn() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_relate : public Create_func_arg3
-{
-public:
- virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
-
- static Create_func_relate s_singleton;
-
-protected:
- Create_func_relate() {}
- virtual ~Create_func_relate() {}
-};
-
-
-class Create_func_mbr_intersects : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_intersects s_singleton;
-
- protected:
- Create_func_mbr_intersects() {}
- virtual ~Create_func_mbr_intersects() {}
-};
-
-
-class Create_func_intersects : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_intersects s_singleton;
-
-protected:
- Create_func_intersects() {}
- virtual ~Create_func_intersects() {}
-};
-
-
-class Create_func_intersection : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_intersection s_singleton;
-
-protected:
- Create_func_intersection() {}
- virtual ~Create_func_intersection() {}
-};
-
-
-class Create_func_difference : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_difference s_singleton;
-
-protected:
- Create_func_difference() {}
- virtual ~Create_func_difference() {}
-};
-
-
-class Create_func_union : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_union s_singleton;
-
-protected:
- Create_func_union() {}
- virtual ~Create_func_union() {}
-};
-
-
-class Create_func_symdifference : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_symdifference s_singleton;
-
-protected:
- Create_func_symdifference() {}
- virtual ~Create_func_symdifference() {}
-};
-
-
-class Create_func_buffer : public Create_func_arg2
-{
-public:
- virtual Item* create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_buffer s_singleton;
-
-protected:
- Create_func_buffer() {}
- virtual ~Create_func_buffer() {}
-};
-#endif /*HAVE_SPATIAL*/
-
-
class Create_func_is_free_lock : public Create_func_arg1
{
public:
@@ -1599,49 +962,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_isclosed : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isclosed s_singleton;
-
-protected:
- Create_func_isclosed() {}
- virtual ~Create_func_isclosed() {}
-};
-
-
-class Create_func_isring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isring s_singleton;
-
-protected:
- Create_func_isring() {}
- virtual ~Create_func_isring() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_isempty : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_isempty s_singleton;
-
-protected:
- Create_func_isempty() {}
- virtual ~Create_func_isempty() {}
-};
-#endif
-
-
class Create_func_isnull : public Create_func_arg1
{
public:
@@ -1655,21 +975,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_issimple : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_issimple s_singleton;
-
-protected:
- Create_func_issimple() {}
- virtual ~Create_func_issimple() {}
-};
-#endif
-
-
class Create_func_json_exists : public Create_func_arg2
{
public:
@@ -2378,51 +1683,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_numgeometries : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numgeometries s_singleton;
-
-protected:
- Create_func_numgeometries() {}
- virtual ~Create_func_numgeometries() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_numinteriorring : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numinteriorring s_singleton;
-
-protected:
- Create_func_numinteriorring() {}
- virtual ~Create_func_numinteriorring() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_numpoints : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_numpoints s_singleton;
-
-protected:
- Create_func_numpoints() {}
- virtual ~Create_func_numpoints() {}
-};
-#endif
-
-
class Create_func_oct : public Create_func_arg1
{
public:
@@ -2449,34 +1709,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_overlaps : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_overlaps s_singleton;
-
- protected:
- Create_func_mbr_overlaps() {}
- virtual ~Create_func_mbr_overlaps() {}
-};
-
-
-class Create_func_overlaps : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_overlaps s_singleton;
-
-protected:
- Create_func_overlaps() {}
- virtual ~Create_func_overlaps() {}
-};
-#endif
-
-
class Create_func_period_add : public Create_func_arg2
{
public:
@@ -2516,21 +1748,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_pointn : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_pointn s_singleton;
-
-protected:
- Create_func_pointn() {}
- virtual ~Create_func_pointn() {}
-};
-#endif
-
-
class Create_func_pow : public Create_func_arg2
{
public:
@@ -2848,36 +2065,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_srid : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_srid s_singleton;
-
-protected:
- Create_func_srid() {}
- virtual ~Create_func_srid() {}
-};
-#endif
-
-
-#ifdef HAVE_SPATIAL
-class Create_func_startpoint : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_startpoint s_singleton;
-
-protected:
- Create_func_startpoint() {}
- virtual ~Create_func_startpoint() {}
-};
-#endif
-
-
class Create_func_str_to_date : public Create_func_arg2
{
public:
@@ -3034,21 +2221,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_touches : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_touches s_singleton;
-
-protected:
- Create_func_touches() {}
- virtual ~Create_func_touches() {}
-};
-#endif
-
-
class Create_func_ucase : public Create_func_arg1
{
public:
@@ -3179,33 +2351,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_mbr_within : public Create_func_arg2
-{
- public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_mbr_within s_singleton;
-
- protected:
- Create_func_mbr_within() {}
- virtual ~Create_func_mbr_within() {}
-};
-
-
-class Create_func_within : public Create_func_arg2
-{
-public:
- virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
-
- static Create_func_within s_singleton;
-
-protected:
- Create_func_within() {}
- virtual ~Create_func_within() {}
-};
-#endif
-
#ifdef WITH_WSREP
class Create_func_wsrep_last_written_gtid : public Create_func_arg0
{
@@ -3246,20 +2391,6 @@ protected:
};
#endif /* WITH_WSREP */
-#ifdef HAVE_SPATIAL
-class Create_func_x : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_x s_singleton;
-
-protected:
- Create_func_x() {}
- virtual ~Create_func_x() {}
-};
-#endif
-
class Create_func_xml_extractvalue : public Create_func_arg2
{
@@ -3287,21 +2418,6 @@ protected:
};
-#ifdef HAVE_SPATIAL
-class Create_func_y : public Create_func_arg1
-{
-public:
- virtual Item *create_1_arg(THD *thd, Item *arg1);
-
- static Create_func_y s_singleton;
-
-protected:
- Create_func_y() {}
- virtual ~Create_func_y() {}
-};
-#endif
-
-
class Create_func_year_week : public Create_native_func
{
public:
@@ -3344,21 +2460,6 @@ static bool has_named_parameters(List<Item> *params)
return false;
}
-#ifndef HAVE_SPATIAL
-Create_func_no_geom Create_func_no_geom::s_singleton;
-
-Item*
-Create_func_no_geom::create_func(THD * /* unused */,
- LEX_CSTRING /* unused */,
- List<Item> * /* unused */)
-{
- /* FIXME: error message can't be translated. */
- my_error(ER_FEATURE_DISABLED, MYF(0),
- sym_group_geom.name, sym_group_geom.needed_define);
- return NULL;
-}
-#endif
-
Item*
Create_qfunc::create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list)
@@ -3710,39 +2811,6 @@ Create_func_aes_decrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_area Create_func_area::s_singleton;
-
-Item*
-Create_func_area::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_area(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_as_wkb Create_func_as_wkb::s_singleton;
-
-Item*
-Create_func_as_wkb::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_as_wkt Create_func_as_wkt::s_singleton;
-
-Item*
-Create_func_as_wkt::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
-}
-#endif
-
-
Create_func_asin Create_func_asin::s_singleton;
Item*
@@ -3854,16 +2922,6 @@ Create_func_ceiling::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_centroid Create_func_centroid::s_singleton;
-
-Item*
-Create_func_centroid::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_centroid(thd, arg1);
-}
-
-
Create_func_chr Create_func_chr::s_singleton;
Item*
@@ -3874,25 +2932,6 @@ Create_func_chr::create_1_arg(THD *thd, Item *arg1)
}
-Create_func_convexhull Create_func_convexhull::s_singleton;
-
-Item*
-Create_func_convexhull::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_convexhull(thd, arg1);
-}
-
-
-Create_func_pointonsurface Create_func_pointonsurface::s_singleton;
-
-Item*
-Create_func_pointonsurface::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
-}
-#endif /*HAVE_SPATIAL*/
-
-
Create_func_char_length Create_func_char_length::s_singleton;
Item*
@@ -4050,28 +3089,6 @@ Create_func_connection_id::create_builder(THD *thd)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
-
-Item*
-Create_func_mbr_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_CONTAINS_FUNC);
-}
-
-
-Create_func_contains Create_func_contains::s_singleton;
-
-Item*
-Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_CONTAINS_FUNC);
-}
-#endif
-
-
Create_func_nvl2 Create_func_nvl2::s_singleton;
Item*
@@ -4125,19 +3142,6 @@ Create_func_crc32::create_1_arg(THD *thd, Item *arg1)
return new (thd->mem_root) Item_func_crc32(thd, arg1);
}
-
-#ifdef HAVE_SPATIAL
-Create_func_crosses Create_func_crosses::s_singleton;
-
-Item*
-Create_func_crosses::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_CROSSES_FUNC);
-}
-#endif
-
-
Create_func_datediff Create_func_datediff::s_singleton;
Item*
@@ -4270,48 +3274,6 @@ Create_func_des_encrypt::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_dimension Create_func_dimension::s_singleton;
-
-Item*
-Create_func_dimension::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_dimension(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
-
-Item*
-Create_func_mbr_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_DISJOINT_FUNC);
-}
-
-
-Create_func_disjoint Create_func_disjoint::s_singleton;
-
-Item*
-Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_DISJOINT_FUNC);
-}
-
-
-Create_func_distance Create_func_distance::s_singleton;
-
-Item*
-Create_func_distance::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
-}
-#endif
-
-
Create_func_elt Create_func_elt::s_singleton;
Item*
@@ -4380,60 +3342,6 @@ Create_func_encrypt::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_endpoint Create_func_endpoint::s_singleton;
-
-Item*
-Create_func_endpoint::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_ENDPOINT);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_envelope Create_func_envelope::s_singleton;
-
-Item*
-Create_func_envelope::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_envelope(thd, arg1);
-}
-
-
-Create_func_boundary Create_func_boundary::s_singleton;
-
-Item*
-Create_func_boundary::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_boundary(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
-
-Item*
-Create_func_mbr_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_EQUALS_FUNC);
-}
-
-
-Create_func_equals Create_func_equals::s_singleton;
-
-Item*
-Create_func_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_EQUALS_FUNC);
-}
-#endif
-
-
Create_func_exp Create_func_exp::s_singleton;
Item*
@@ -4496,18 +3404,6 @@ Create_func_export_set::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_exteriorring Create_func_exteriorring::s_singleton;
-
-Item*
-Create_func_exteriorring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_EXTERIORRING);
-}
-#endif
-
-
Create_func_field Create_func_field::s_singleton;
Item*
@@ -4650,203 +3546,6 @@ Create_func_from_unixtime::create_native(THD *thd, LEX_CSTRING *name,
}
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton;
-
-Item*
-Create_func_geometry_from_text::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *param_1= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *param_1= item_list->pop();
- Item *param_2= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton;
-
-Item*
-Create_func_geometry_from_wkb::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *param_1= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *param_1= item_list->pop();
- Item *param_2= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
-
-Item*
-Create_func_geometry_from_json::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *json= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *json= item_list->pop();
- Item *options= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
- break;
- }
- case 3:
- {
- Item *json= item_list->pop();
- Item *options= item_list->pop();
- Item *srid= item_list->pop();
- func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
- srid);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-
-
-Create_func_as_geojson Create_func_as_geojson::s_singleton;
-
-Item*
-Create_func_as_geojson::create_native(THD *thd, LEX_CSTRING *name,
- List<Item> *item_list)
-{
- Item *func= NULL;
- int arg_count= 0;
-
- if (item_list != NULL)
- arg_count= item_list->elements;
-
- switch (arg_count) {
- case 1:
- {
- Item *geom= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
- thd->lex->uncacheable(UNCACHEABLE_RAND);
- break;
- }
- case 2:
- {
- Item *geom= item_list->pop();
- Item *max_dec= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
- break;
- }
- case 3:
- {
- Item *geom= item_list->pop();
- Item *max_dec= item_list->pop();
- Item *options= item_list->pop();
- func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
- break;
- }
- default:
- {
- my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
- break;
- }
- }
-
- return func;
-}
-#endif /*HAVE_SPATIAL*/
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometry_type Create_func_geometry_type::s_singleton;
-
-Item*
-Create_func_geometry_type::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_geometryn Create_func_geometryn::s_singleton;
-
-Item*
-Create_func_geometryn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_GEOMETRYN);
-}
-#endif
-
Create_func_get_lock Create_func_get_lock::s_singleton;
@@ -4859,28 +3558,6 @@ Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#if defined(HAVE_SPATIAL) && !defined(DBUG_OFF)
-Create_func_gis_debug Create_func_gis_debug::s_singleton;
-
-Item*
-Create_func_gis_debug::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_glength Create_func_glength::s_singleton;
-
-Item*
-Create_func_glength::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_glength(thd, arg1);
-}
-#endif
-
-
Create_func_greatest Create_func_greatest::s_singleton;
Item*
@@ -5001,98 +3678,6 @@ Create_func_instr::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_interiorringn Create_func_interiorringn::s_singleton;
-
-Item*
-Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_INTERIORRINGN);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_relate Create_func_relate::s_singleton;
-
-Item*
-Create_func_relate::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *matrix)
-{
- return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, matrix);
-}
-
-
-Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
-
-Item*
-Create_func_mbr_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_INTERSECTS_FUNC);
-}
-
-
-Create_func_intersects Create_func_intersects::s_singleton;
-
-Item*
-Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_INTERSECTS_FUNC);
-}
-
-
-Create_func_intersection Create_func_intersection::s_singleton;
-
-Item*
-Create_func_intersection::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_intersection);
-}
-
-
-Create_func_difference Create_func_difference::s_singleton;
-
-Item*
-Create_func_difference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_difference);
-}
-
-
-Create_func_union Create_func_union::s_singleton;
-
-Item*
-Create_func_union::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_union);
-}
-
-
-Create_func_symdifference Create_func_symdifference::s_singleton;
-
-Item*
-Create_func_symdifference::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
- Gcalc_function::op_symdifference);
-}
-
-
-Create_func_buffer Create_func_buffer::s_singleton;
-
-Item*
-Create_func_buffer::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
-}
-#endif /*HAVE_SPATAI*/
-
-
Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
Item*
@@ -5115,35 +3700,6 @@ Create_func_is_used_lock::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_isclosed Create_func_isclosed::s_singleton;
-
-Item*
-Create_func_isclosed::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isclosed(thd, arg1);
-}
-
-
-Create_func_isring Create_func_isring::s_singleton;
-
-Item*
-Create_func_isring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isring(thd, arg1);
-}
-
-
-Create_func_isempty Create_func_isempty::s_singleton;
-
-Item*
-Create_func_isempty::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_isempty(thd, arg1);
-}
-#endif /*HAVE_SPATIAL*/
-
-
Create_func_isnull Create_func_isnull::s_singleton;
Item*
@@ -5153,17 +3709,6 @@ Create_func_isnull::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_issimple Create_func_issimple::s_singleton;
-
-Item*
-Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_issimple(thd, arg1);
-}
-#endif
-
-
Create_func_json_exists Create_func_json_exists::s_singleton;
Item*
@@ -6211,39 +4756,6 @@ Create_func_nullif::create_2_arg(THD *thd, Item *arg1, Item *arg2)
}
-#ifdef HAVE_SPATIAL
-Create_func_numgeometries Create_func_numgeometries::s_singleton;
-
-Item*
-Create_func_numgeometries::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
-
-Item*
-Create_func_numinteriorring::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_numpoints Create_func_numpoints::s_singleton;
-
-Item*
-Create_func_numpoints::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_numpoints(thd, arg1);
-}
-#endif
-
-
Create_func_oct Create_func_oct::s_singleton;
Item*
@@ -6264,28 +4776,6 @@ Create_func_ord::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
-
-Item*
-Create_func_mbr_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_OVERLAPS_FUNC);
-}
-
-
-Create_func_overlaps Create_func_overlaps::s_singleton;
-
-Item*
-Create_func_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_OVERLAPS_FUNC);
-}
-#endif
-
-
Create_func_period_add Create_func_period_add::s_singleton;
Item*
@@ -6313,18 +4803,6 @@ Create_func_pi::create_builder(THD *thd)
}
-#ifdef HAVE_SPATIAL
-Create_func_pointn Create_func_pointn::s_singleton;
-
-Item*
-Create_func_pointn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
- Item_func::SP_POINTN);
-}
-#endif
-
-
Create_func_pow Create_func_pow::s_singleton;
Item*
@@ -6663,29 +5141,6 @@ Create_func_sqrt::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_srid Create_func_srid::s_singleton;
-
-Item*
-Create_func_srid::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_srid(thd, arg1);
-}
-#endif
-
-
-#ifdef HAVE_SPATIAL
-Create_func_startpoint Create_func_startpoint::s_singleton;
-
-Item*
-Create_func_startpoint::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
- Item_func::SP_STARTPOINT);
-}
-#endif
-
-
Create_func_str_to_date Create_func_str_to_date::s_singleton;
Item*
@@ -6819,18 +5274,6 @@ Create_func_to_seconds::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_touches Create_func_touches::s_singleton;
-
-Item*
-Create_func_touches::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_TOUCHES_FUNC);
-}
-#endif
-
-
Create_func_ucase Create_func_ucase::s_singleton;
Item*
@@ -6933,9 +5376,9 @@ Item*
Create_func_version::create_builder(THD *thd)
{
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
- return new (thd->mem_root) Item_static_string_func(thd, "version()",
- server_version,
- (uint) strlen(server_version),
+ static Lex_cstring name(STRING_WITH_LEN("version()"));
+ return new (thd->mem_root) Item_static_string_func(thd, name,
+ Lex_cstring_strlen(server_version),
system_charset_info,
DERIVATION_SYSCONST);
}
@@ -6960,27 +5403,6 @@ Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1)
}
-#ifdef HAVE_SPATIAL
-Create_func_mbr_within Create_func_mbr_within::s_singleton;
-
-Item*
-Create_func_mbr_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
- Item_func::SP_WITHIN_FUNC);
-}
-
-
-Create_func_within Create_func_within::s_singleton;
-
-Item*
-Create_func_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
-{
- return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
- Item_func::SP_WITHIN_FUNC);
-}
-#endif
-
#ifdef WITH_WSREP
Create_func_wsrep_last_written_gtid
Create_func_wsrep_last_written_gtid::s_singleton;
@@ -7039,17 +5461,6 @@ Create_func_wsrep_sync_wait_upto::create_native(THD *thd,
}
#endif /* WITH_WSREP */
-#ifdef HAVE_SPATIAL
-Create_func_x Create_func_x::s_singleton;
-
-Item*
-Create_func_x::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_x(thd, arg1);
-}
-#endif
-
-
Create_func_xml_extractvalue Create_func_xml_extractvalue::s_singleton;
Item*
@@ -7068,17 +5479,6 @@ Create_func_xml_update::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg
}
-#ifdef HAVE_SPATIAL
-Create_func_y Create_func_y::s_singleton;
-
-Item*
-Create_func_y::create_1_arg(THD *thd, Item *arg1)
-{
- return new (thd->mem_root) Item_func_y(thd, arg1);
-}
-#endif
-
-
Create_func_year_week Create_func_year_week::s_singleton;
Item*
@@ -7119,12 +5519,6 @@ Create_func_year_week::create_native(THD *thd, LEX_CSTRING *name,
#define BUILDER(F) & F::s_singleton
-#ifdef HAVE_SPATIAL
- #define GEOM_BUILDER(F) & F::s_singleton
-#else
- #define GEOM_BUILDER(F) & Create_func_no_geom::s_singleton
-#endif
-
/*
MySQL native functions.
MAINTAINER:
@@ -7143,12 +5537,7 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("ADDTIME") }, BUILDER(Create_func_addtime)},
{ { STRING_WITH_LEN("AES_DECRYPT") }, BUILDER(Create_func_aes_decrypt)},
{ { STRING_WITH_LEN("AES_ENCRYPT") }, BUILDER(Create_func_aes_encrypt)},
- { { STRING_WITH_LEN("AREA") }, GEOM_BUILDER(Create_func_area)},
- { { STRING_WITH_LEN("ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
{ { STRING_WITH_LEN("ASIN") }, BUILDER(Create_func_asin)},
- { { STRING_WITH_LEN("ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
{ { STRING_WITH_LEN("ATAN") }, BUILDER(Create_func_atan)},
{ { STRING_WITH_LEN("ATAN2") }, BUILDER(Create_func_atan)},
{ { STRING_WITH_LEN("BENCHMARK") }, BUILDER(Create_func_benchmark)},
@@ -7156,11 +5545,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("BINLOG_GTID_POS") }, BUILDER(Create_func_binlog_gtid_pos)},
{ { STRING_WITH_LEN("BIT_COUNT") }, BUILDER(Create_func_bit_count)},
{ { STRING_WITH_LEN("BIT_LENGTH") }, BUILDER(Create_func_bit_length)},
- { { STRING_WITH_LEN("BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
- { { STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
{ { STRING_WITH_LEN("CEIL") }, BUILDER(Create_func_ceiling)},
{ { STRING_WITH_LEN("CEILING") }, BUILDER(Create_func_ceiling)},
- { { STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
{ { STRING_WITH_LEN("CHARACTER_LENGTH") }, BUILDER(Create_func_char_length)},
{ { STRING_WITH_LEN("CHAR_LENGTH") }, BUILDER(Create_func_char_length)},
{ { STRING_WITH_LEN("CHR") }, BUILDER(Create_func_chr)},
@@ -7176,11 +5562,9 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("CONNECTION_ID") }, BUILDER(Create_func_connection_id)},
{ { STRING_WITH_LEN("CONV") }, BUILDER(Create_func_conv)},
{ { STRING_WITH_LEN("CONVERT_TZ") }, BUILDER(Create_func_convert_tz)},
- { { STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
{ { STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)},
{ { STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)},
{ { STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)},
- { { STRING_WITH_LEN("CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
{ { STRING_WITH_LEN("DATEDIFF") }, BUILDER(Create_func_datediff)},
{ { STRING_WITH_LEN("DAYNAME") }, BUILDER(Create_func_dayname)},
{ { STRING_WITH_LEN("DAYOFMONTH") }, BUILDER(Create_func_dayofmonth)},
@@ -7191,17 +5575,11 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("DECODE_ORACLE") }, BUILDER(Create_func_decode_oracle)},
{ { STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)},
{ { STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)},
- { { STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
- { { STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
{ { STRING_WITH_LEN("ELT") }, BUILDER(Create_func_elt)},
{ { STRING_WITH_LEN("ENCODE") }, BUILDER(Create_func_encode)},
{ { STRING_WITH_LEN("ENCRYPT") }, BUILDER(Create_func_encrypt)},
- { { STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
- { { STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
{ { STRING_WITH_LEN("EXP") }, BUILDER(Create_func_exp)},
{ { STRING_WITH_LEN("EXPORT_SET") }, BUILDER(Create_func_export_set)},
- { { STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
{ { STRING_WITH_LEN("EXTRACTVALUE") }, BUILDER(Create_func_xml_extractvalue)},
{ { STRING_WITH_LEN("FIELD") }, BUILDER(Create_func_field)},
{ { STRING_WITH_LEN("FIND_IN_SET") }, BUILDER(Create_func_find_in_set)},
@@ -7211,18 +5589,7 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("FROM_BASE64") }, BUILDER(Create_func_from_base64)},
{ { STRING_WITH_LEN("FROM_DAYS") }, BUILDER(Create_func_from_days)},
{ { STRING_WITH_LEN("FROM_UNIXTIME") }, BUILDER(Create_func_from_unixtime)},
- { { STRING_WITH_LEN("GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
- { { STRING_WITH_LEN("GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
- { { STRING_WITH_LEN("GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("GET_LOCK") }, BUILDER(Create_func_get_lock)},
- { { STRING_WITH_LEN("GLENGTH") }, GEOM_BUILDER(Create_func_glength)},
{ { STRING_WITH_LEN("GREATEST") }, BUILDER(Create_func_greatest)},
{ { STRING_WITH_LEN("HEX") }, BUILDER(Create_func_hex)},
{ { STRING_WITH_LEN("IFNULL") }, BUILDER(Create_func_ifnull)},
@@ -7235,13 +5602,7 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("IS_IPV4_COMPAT") }, BUILDER(Create_func_is_ipv4_compat)},
{ { STRING_WITH_LEN("IS_IPV4_MAPPED") }, BUILDER(Create_func_is_ipv4_mapped)},
{ { STRING_WITH_LEN("INSTR") }, BUILDER(Create_func_instr)},
- { { STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
- { { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
- { { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
- { { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
{ { STRING_WITH_LEN("ISNULL") }, BUILDER(Create_func_isnull)},
- { { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)},
- { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
{ { STRING_WITH_LEN("IS_FREE_LOCK") }, BUILDER(Create_func_is_free_lock)},
{ { STRING_WITH_LEN("IS_USED_LOCK") }, BUILDER(Create_func_is_used_lock)},
{ { STRING_WITH_LEN("JSON_ARRAY") }, BUILDER(Create_func_json_array)},
@@ -7282,10 +5643,6 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("LIKE_RANGE_MIN") }, BUILDER(Create_func_like_range_min)},
{ { STRING_WITH_LEN("LIKE_RANGE_MAX") }, BUILDER(Create_func_like_range_max)},
#endif
- { { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("LN") }, BUILDER(Create_func_ln)},
{ { STRING_WITH_LEN("LOAD_FILE") }, BUILDER(Create_func_load_file)},
{ { STRING_WITH_LEN("LOCATE") }, BUILDER(Create_func_locate)},
@@ -7302,50 +5659,18 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("MAKE_SET") }, BUILDER(Create_func_make_set)},
{ { STRING_WITH_LEN("MASTER_GTID_WAIT") }, BUILDER(Create_func_master_gtid_wait)},
{ { STRING_WITH_LEN("MASTER_POS_WAIT") }, BUILDER(Create_func_master_pos_wait)},
- { { STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
- { { STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
- { { STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)},
- { { STRING_WITH_LEN("MBREQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
- { { STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
- { { STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
- { { STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
- { { STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
{ { STRING_WITH_LEN("MD5") }, BUILDER(Create_func_md5)},
- { { STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("MONTHNAME") }, BUILDER(Create_func_monthname)},
- { { STRING_WITH_LEN("MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("NAME_CONST") }, BUILDER(Create_func_name_const)},
{ { STRING_WITH_LEN("NVL") }, BUILDER(Create_func_ifnull)},
{ { STRING_WITH_LEN("NVL2") }, BUILDER(Create_func_nvl2)},
{ { STRING_WITH_LEN("NULLIF") }, BUILDER(Create_func_nullif)},
- { { STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
- { { STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
- { { STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
{ { STRING_WITH_LEN("OCT") }, BUILDER(Create_func_oct)},
{ { STRING_WITH_LEN("OCTET_LENGTH") }, BUILDER(Create_func_octet_length)},
{ { STRING_WITH_LEN("ORD") }, BUILDER(Create_func_ord)},
- { { STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
{ { STRING_WITH_LEN("PERIOD_ADD") }, BUILDER(Create_func_period_add)},
{ { STRING_WITH_LEN("PERIOD_DIFF") }, BUILDER(Create_func_period_diff)},
{ { STRING_WITH_LEN("PI") }, BUILDER(Create_func_pi)},
- { { STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)},
- { { STRING_WITH_LEN("POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
- { { STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
{ { STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)},
{ { STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)},
{ { STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)},
@@ -7373,90 +5698,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("SOUNDEX") }, BUILDER(Create_func_soundex)},
{ { STRING_WITH_LEN("SPACE") }, BUILDER(Create_func_space)},
{ { STRING_WITH_LEN("SQRT") }, BUILDER(Create_func_sqrt)},
- { { STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
- { { STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
{ { STRING_WITH_LEN("STRCMP") }, BUILDER(Create_func_strcmp)},
{ { STRING_WITH_LEN("STR_TO_DATE") }, BUILDER(Create_func_str_to_date)},
- { { STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
- { { STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ST_ASGEOJSON") }, GEOM_BUILDER(Create_func_as_geojson)},
- { { STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
- { { STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
- { { STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
- { { STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
- { { STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
- { { STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
- { { STRING_WITH_LEN("ST_CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
- { { STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
- { { STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)},
- { { STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
- { { STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
- { { STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
- { { STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
- { { STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
- { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
- { { STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
- { { STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
- { { STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
- { { STRING_WITH_LEN("ST_GEOMFROMGEOJSON") }, GEOM_BUILDER(Create_func_geometry_from_json)},
- { { STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
-#ifndef DBUG_OFF
- { { STRING_WITH_LEN("ST_GIS_DEBUG") }, GEOM_BUILDER(Create_func_gis_debug)},
-#endif
- { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
- { { STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
- { { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
- { { STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)},
- { { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
- { { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
- { { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)},
- { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
- { { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
- { { STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
- { { STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
- { { STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
- { { STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
- { { STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)},
- { { STRING_WITH_LEN("ST_POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
- { { STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
- { { STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
- { { STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)},
- { { STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
- { { STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
- { { STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
- { { STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
- { { STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
- { { STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
- { { STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
- { { STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
{ { STRING_WITH_LEN("SUBSTR_ORACLE") },
BUILDER(Create_func_substr_oracle)},
{ { STRING_WITH_LEN("SUBSTRING_INDEX") }, BUILDER(Create_func_substr_index)},
@@ -7465,7 +5708,6 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("TIMEDIFF") }, BUILDER(Create_func_timediff)},
{ { STRING_WITH_LEN("TIME_FORMAT") }, BUILDER(Create_func_time_format)},
{ { STRING_WITH_LEN("TIME_TO_SEC") }, BUILDER(Create_func_time_to_sec)},
- { { STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
{ { STRING_WITH_LEN("TO_BASE64") }, BUILDER(Create_func_to_base64)},
{ { STRING_WITH_LEN("TO_DAYS") }, BUILDER(Create_func_to_days)},
{ { STRING_WITH_LEN("TO_SECONDS") }, BUILDER(Create_func_to_seconds)},
@@ -7481,14 +5723,11 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("VERSION") }, BUILDER(Create_func_version)},
{ { STRING_WITH_LEN("WEEKDAY") }, BUILDER(Create_func_weekday)},
{ { STRING_WITH_LEN("WEEKOFYEAR") }, BUILDER(Create_func_weekofyear)},
- { { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
#ifdef WITH_WSREP
{ { STRING_WITH_LEN("WSREP_LAST_WRITTEN_GTID") }, BUILDER(Create_func_wsrep_last_written_gtid)},
{ { STRING_WITH_LEN("WSREP_LAST_SEEN_GTID") }, BUILDER(Create_func_wsrep_last_seen_gtid)},
{ { STRING_WITH_LEN("WSREP_SYNC_WAIT_UPTO_GTID") }, BUILDER(Create_func_wsrep_sync_wait_upto)},
#endif /* WITH_WSREP */
- { { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
- { { STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
{ { STRING_WITH_LEN("YEARWEEK") }, BUILDER(Create_func_year_week)},
{ {0, 0}, NULL}
@@ -7525,7 +5764,15 @@ int item_create_init()
MYF(0)))
DBUG_RETURN(1);
- DBUG_RETURN(item_create_append(func_array));
+ if (item_create_append(func_array))
+ DBUG_RETURN(1);
+
+#ifdef HAVE_SPATIAL
+ if (function_collection_geometry.init())
+ DBUG_RETURN(1);
+#endif
+
+ DBUG_RETURN(0);
}
int item_create_append(Native_func_registry array[])
@@ -7562,6 +5809,9 @@ void item_create_cleanup()
{
DBUG_ENTER("item_create_cleanup");
my_hash_free(& native_functions_hash);
+#ifdef HAVE_SPATIAL
+ function_collection_geometry.cleanup();
+#endif
DBUG_VOID_RETURN;
}
@@ -7581,6 +5831,12 @@ find_native_function_builder(THD *thd, const LEX_CSTRING *name)
builder= func->builder;
}
+#ifdef HAVE_SPATIAL
+ if (!builder)
+ builder= function_collection_geometry.find_native_function_builder(thd,
+ *name);
+#endif
+
return builder;
}
diff --git a/sql/item_create.h b/sql/item_create.h
index 5890e8ad057..3cbf8a70181 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -69,6 +69,111 @@ protected:
/**
+ Adapter for functions that takes exactly zero arguments.
+*/
+
+class Create_func_arg0 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list);
+
+ /**
+ Builder method, with no arguments.
+ @param thd The current thread
+ @return An item representing the function call
+ */
+ virtual Item *create_builder(THD *thd) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg0() {}
+ /** Destructor. */
+ virtual ~Create_func_arg0() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly one argument.
+*/
+
+class Create_func_arg1 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with one argument.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg1() {}
+ /** Destructor. */
+ virtual ~Create_func_arg1() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly two arguments.
+*/
+
+class Create_func_arg2 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with two arguments.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @param arg2 The second argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg2() {}
+ /** Destructor. */
+ virtual ~Create_func_arg2() {}
+};
+
+
+/**
+ Adapter for functions that takes exactly three arguments.
+*/
+
+class Create_func_arg3 : public Create_func
+{
+public:
+ virtual Item *create_func(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ /**
+ Builder method, with three arguments.
+ @param thd The current thread
+ @param arg1 The first argument of the function
+ @param arg2 The second argument of the function
+ @param arg3 The third argument of the function
+ @return An item representing the function call
+ */
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
+
+protected:
+ /** Constructor. */
+ Create_func_arg3() {}
+ /** Destructor. */
+ virtual ~Create_func_arg3() {}
+};
+
+
+
+
+/**
Adapter for native functions with a variable number of arguments.
The main use of this class is to discard the following calls:
<code>foo(expr1 AS name1, expr2 AS name2, ...)</code>
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ce01ef1a686..913442ee22d 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -647,16 +647,6 @@ bool Item_func::is_expensive_processor(uchar *arg)
}
*/
-my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
-{
- DBUG_ASSERT(fixed);
- longlong nr= val_int();
- if (null_value)
- return 0; /* purecov: inspected */
- int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
- return decimal_value;
-}
-
bool Item_hybrid_func::fix_attributes(Item **items, uint nitems)
{
@@ -1198,7 +1188,10 @@ void Item_func_minus::fix_unsigned_flag()
{
if (unsigned_flag &&
(current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
+ {
unsigned_flag=0;
+ set_handler(Item_func_minus::type_handler()->type_handler_signed());
+ }
}
@@ -1817,7 +1810,7 @@ void Item_func_neg::fix_length_and_dec_int()
Ensure that result is converted to DECIMAL, as longlong can't hold
the negated number
*/
- set_handler_by_result_type(DECIMAL_RESULT);
+ set_handler(&type_handler_newdecimal);
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
}
}
@@ -4401,7 +4394,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
set_handler(&type_handler_double);
break;
case INT_RESULT:
- set_handler(Type_handler::type_handler_long_or_longlong(max_char_length()));
+ set_handler(Type_handler::type_handler_long_or_longlong(max_char_length(),
+ unsigned_flag));
break;
case DECIMAL_RESULT:
set_handler(&type_handler_newdecimal);
@@ -4993,7 +4987,7 @@ void Item_func_set_user_var::make_send_field(THD *thd, Send_field *tmp_field)
if (result_field)
{
result_field->make_send_field(tmp_field);
- DBUG_ASSERT(tmp_field->table_name != 0);
+ DBUG_ASSERT(tmp_field->table_name.str != 0);
if (Item::name.str)
tmp_field->col_name= Item::name; // Use user supplied name
}
@@ -5302,21 +5296,25 @@ bool Item_func_get_user_var::fix_length_and_dec()
unsigned_flag= m_var_entry->unsigned_flag;
max_length= (uint32)m_var_entry->length;
collation.set(m_var_entry->charset(), DERIVATION_IMPLICIT);
- set_handler_by_result_type(m_var_entry->type);
- switch (result_type()) {
+ switch (m_var_entry->type) {
case REAL_RESULT:
fix_char_length(DBL_DIG + 8);
+ set_handler(&type_handler_double);
break;
case INT_RESULT:
fix_char_length(MAX_BIGINT_WIDTH);
decimals=0;
+ set_handler(unsigned_flag ? &type_handler_ulonglong :
+ &type_handler_slonglong);
break;
case STRING_RESULT:
max_length= MAX_BLOB_WIDTH - 1;
+ set_handler(&type_handler_long_blob);
break;
case DECIMAL_RESULT:
fix_char_length(DECIMAL_MAX_STR_LENGTH);
decimals= DECIMAL_MAX_SCALE;
+ set_handler(&type_handler_newdecimal);
break;
case ROW_RESULT: // Keep compiler happy
case TIME_RESULT:
@@ -5513,7 +5511,7 @@ bool Item_func_get_system_var::fix_length_and_dec()
case SHOW_SINT:
case SHOW_SLONG:
case SHOW_SLONGLONG:
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(MY_INT64_NUM_DECIMAL_DIGITS);
decimals=0;
break;
@@ -5547,13 +5545,13 @@ bool Item_func_get_system_var::fix_length_and_dec()
break;
case SHOW_BOOL:
case SHOW_MY_BOOL:
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(1);
decimals=0;
break;
case SHOW_DOUBLE:
decimals= 6;
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(DBL_DIG + 6);
break;
default:
@@ -5599,11 +5597,12 @@ const Type_handler *Item_func_get_system_var::type_handler() const
case SHOW_SINT:
case SHOW_SLONG:
case SHOW_SLONGLONG:
+ return &type_handler_slonglong;
case SHOW_UINT:
case SHOW_ULONG:
case SHOW_ULONGLONG:
case SHOW_HA_ROWS:
- return &type_handler_longlong;
+ return &type_handler_ulonglong;
case SHOW_CHAR:
case SHOW_CHAR_PTR:
case SHOW_LEX_STRING:
diff --git a/sql/item_func.h b/sql/item_func.h
index 610adb4bb46..c7b23a49114 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -188,12 +188,10 @@ public:
void signal_divide_by_null();
friend class udf_handler;
- Field *create_field_for_create_select(TABLE *table)
- { return tmp_table_field_from_field_type(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return tmp_table_field_from_field_type(root, table); }
Item *get_tmp_table_item(THD *thd);
- my_decimal *val_decimal(my_decimal *);
-
void fix_char_length_ulonglong(ulonglong max_char_length_arg)
{
ulonglong max_result_length= max_char_length_arg *
@@ -406,13 +404,13 @@ public:
class Item_real_func :public Item_func
{
public:
- Item_real_func(THD *thd): Item_func(thd) { collation.set_numeric(); }
+ Item_real_func(THD *thd): Item_func(thd) { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, Item *a): Item_func(thd, a)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_real_func(THD *thd, List<Item> &list): Item_func(thd, list)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *decimal_value);
longlong val_int()
@@ -436,8 +434,7 @@ public:
Functions whose returned field type is determined at fix_fields() time.
*/
class Item_hybrid_func: public Item_func,
- public Type_handler_hybrid_field_type,
- public Type_geometry_attributes
+ public Type_handler_hybrid_field_type
{
protected:
bool fix_attributes(Item **item, uint nitems);
@@ -452,12 +449,6 @@ public:
:Item_func(thd, item), Type_handler_hybrid_field_type(item) { }
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
- Field::geometry_type get_geometry_type() const
- { return Type_geometry_attributes::get_geometry_type(); };
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
};
@@ -730,19 +721,19 @@ public:
public:
Item_func_hybrid_field_type(THD *thd):
Item_hybrid_func(thd)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a):
Item_hybrid_func(thd, a)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b):
Item_hybrid_func(thd, a, b)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, Item *a, Item *b, Item *c):
Item_hybrid_func(thd, a, b, c)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
Item_func_hybrid_field_type(THD *thd, List<Item> &list):
Item_hybrid_func(thd, list)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
double val_real()
{
@@ -943,7 +934,12 @@ public:
/* Base class for operations like '+', '-', '*' */
class Item_num_op :public Item_func_numhybrid
{
- public:
+protected:
+ bool check_arguments() const
+ {
+ return false; // Checked by aggregate_for_num_op()
+ }
+public:
Item_num_op(THD *thd, Item *a, Item *b): Item_func_numhybrid(thd, a, b) {}
virtual void result_precision()= 0;
@@ -954,7 +950,7 @@ class Item_num_op :public Item_func_numhybrid
bool fix_type_handler(const Type_aggregator *aggregator);
void fix_length_and_dec_double()
{
- count_real_length(args, arg_count);
+ aggregate_numeric_attributes_real(args, arg_count);
max_length= float_length(decimals);
}
void fix_length_and_dec_decimal()
@@ -991,22 +987,26 @@ public:
Min signed = -9,223,372,036,854,775,808 = 19 digits, 20 characters
*/
Item_int_func(THD *thd): Item_func(thd)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a): Item_func(thd, a)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b): Item_func(thd, a, b)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b, Item *c): Item_func(thd, a, b, c)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item *a, Item *b, Item *c, Item *d):
Item_func(thd, a, b, c, d)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, List<Item> &list): Item_func(thd, list)
- { collation.set_numeric(); fix_char_length(21); }
+ { collation= DTCollation_numeric(); fix_char_length(21); }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
double val_real();
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{ return get_date_from_int(thd, ltime, fuzzydate); }
const Type_handler *type_handler() const= 0;
@@ -1023,7 +1023,12 @@ public:
Item_long_func(THD *thd, Item *a, Item *b, Item *c): Item_int_func(thd, a, b, c) {}
Item_long_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { }
Item_long_func(THD *thd, Item_long_func *item) :Item_int_func(thd, item) {}
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulong;
+ return &type_handler_slong;
+ }
bool fix_length_and_dec() { max_length= 11; return FALSE; }
};
@@ -1035,7 +1040,7 @@ public:
{}
longlong val_int();
bool fix_length_and_dec();
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const { return &type_handler_slong; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_hash>(thd, this); }
const char *func_name() const { return "<hash>"; }
@@ -1052,7 +1057,12 @@ public:
Item_int_func(thd, a, b, c, d) {}
Item_longlong_func(THD *thd, List<Item> &list): Item_int_func(thd, list) { }
Item_longlong_func(THD *thd, Item_longlong_func *item) :Item_int_func(thd, item) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ if (unsigned_flag)
+ return &type_handler_ulonglong;
+ return &type_handler_slonglong;
+ }
};
@@ -1120,7 +1130,10 @@ public:
}
const char *func_name() const { return "cast_as_signed"; }
const Type_handler *type_handler() const
- { return type_handler_long_or_longlong(); }
+ {
+ return Type_handler::type_handler_long_or_longlong(max_char_length(),
+ false);
+ }
longlong val_int()
{
longlong value= args[0]->val_int_signed_typecast();
@@ -1179,8 +1192,8 @@ public:
const Type_handler *type_handler() const
{
if (max_char_length() <= MY_INT32_NUM_DECIMAL_DIGITS - 1)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_ulong;
+ return &type_handler_ulonglong;
}
longlong val_int()
{
@@ -1207,7 +1220,7 @@ public:
:Item_func(thd, a)
{
decimals= (uint8) dec;
- collation.set_numeric();
+ collation= DTCollation_numeric();
fix_char_length(my_decimal_precision_to_length_no_truncation(len, dec,
unsigned_flag));
}
@@ -1805,6 +1818,10 @@ class Item_func_min_max :public Item_hybrid_func
String tmp_value;
int cmp_sign;
protected:
+ bool check_arguments() const
+ {
+ return false; // Checked by aggregate_for_min_max()
+ }
bool fix_attributes(Item **item, uint nitems);
public:
Item_func_min_max(THD *thd, List<Item> &list, int cmp_sign_arg):
@@ -2422,8 +2439,16 @@ public:
Item_udf_func(thd, udf_arg, list) {}
longlong val_int();
double val_real() { return (double) Item_func_udf_int::val_int(); }
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
String *val_str(String *str);
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ return unsigned_flag ? &type_handler_ulonglong :
+ &type_handler_slonglong;
+ }
bool fix_length_and_dec() { decimals= 0; max_length= 21; return FALSE; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_udf_int>(thd, this); }
@@ -2515,7 +2540,7 @@ public:
Item_int_func(thd) {}
Item_func_udf_int(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_int_func(thd, list) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -2527,7 +2552,7 @@ public:
Item_int_func(thd) {}
Item_func_udf_decimal(THD *thd, udf_func *udf_arg, List<Item> &list):
Item_int_func(thd, list) {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
};
@@ -2680,10 +2705,10 @@ public:
Item_func_user_var(THD *thd, Item_func_user_var *item)
:Item_hybrid_func(thd, item),
m_var_entry(item->m_var_entry), name(item->name) { }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
- Field *create_field_for_create_select(TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
bool check_vcol_func_processor(void *arg);
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
@@ -2858,7 +2883,7 @@ public:
{
return 0;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -3110,12 +3135,15 @@ public:
set(handler, 0, 0);
}
const Type_handler *type_handler() const { return m_type_handler; }
- Item *create_typecast_item(THD *thd, Item *item, CHARSET_INFO *cs= NULL)
+ Item *create_typecast_item(THD *thd, Item *item,
+ CHARSET_INFO *cs= NULL) const
{
return m_type_handler->
create_typecast_item(thd, item,
Type_cast_attributes(length(), dec(), cs));
}
+ Item *create_typecast_item_or_error(THD *thd, Item *item,
+ CHARSET_INFO *cs= NULL) const;
};
@@ -3177,13 +3205,13 @@ public:
const Type_handler *type_handler() const;
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
- Field *create_field_for_create_select(TABLE *table)
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
return result_type() != STRING_RESULT ?
sp_result_field :
- create_table_field_from_handler(table);
+ create_table_field_from_handler(root, table);
}
void make_send_field(THD *thd, Send_field *tmp_field);
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 9e6c8ea9008..4cec7dd0f26 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -38,6 +38,7 @@
#ifdef HAVE_SPATIAL
#include <m_ctype.h>
#include "opt_range.h"
+#include "item_geofunc.h"
bool Item_geometry_func::fix_length_and_dec()
@@ -324,12 +325,6 @@ String *Item_func_geometry_type::val_str_ascii(String *str)
}
-Field::geometry_type Item_func_envelope::get_geometry_type() const
-{
- return Field::GEOM_POLYGON;
-}
-
-
String *Item_func_envelope::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -478,12 +473,6 @@ mem_error:
}
-Field::geometry_type Item_func_centroid::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
String *Item_func_centroid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -901,12 +890,6 @@ err:
*/
-Field::geometry_type Item_func_point::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
String *Item_func_point::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -1080,9 +1063,17 @@ Item_func_spatial_rel::get_mm_leaf(RANGE_OPT_PARAM *param,
if (param->using_real_indexes &&
!field->optimize_range(param->real_keynr[key_part->key],
key_part->part))
- DBUG_RETURN(0);
+ DBUG_RETURN(0);
- if (value->save_in_field_no_warnings(field, 1))
+ Field_geom *field_geom= dynamic_cast<Field_geom*>(field);
+ DBUG_ASSERT(field_geom);
+ const Type_handler_geometry *sav_geom_type= field_geom->type_handler_geom();
+ // We have to be able to store all sorts of spatial features here
+ field_geom->set_type_handler(&type_handler_geometry);
+ bool rc= value->save_in_field_no_warnings(field, 1);
+ field_geom->set_type_handler(sav_geom_type);
+
+ if (rc)
DBUG_RETURN(&sel_arg_impossible); // Bad GEOMETRY value
DBUG_ASSERT(!field->real_maybe_null()); // SPATIAL keys do not support NULL
@@ -2631,12 +2622,6 @@ mem_error:
}
-Field::geometry_type Item_func_pointonsurface::get_geometry_type() const
-{
- return Field::GEOM_POINT;
-}
-
-
#ifndef DBUG_OFF
longlong Item_func_gis_debug::val_int()
{
@@ -2645,4 +2630,1338 @@ longlong Item_func_gis_debug::val_int()
}
#endif
+
+/**********************************************************************/
+
+
+class Create_func_area : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_area(thd, arg1);
+ }
+
+ static Create_func_area s_singleton;
+
+protected:
+ Create_func_area() {}
+ virtual ~Create_func_area() {}
+};
+
+
+class Create_func_as_wkb : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_as_wkb(thd, arg1);
+ }
+
+ static Create_func_as_wkb s_singleton;
+
+protected:
+ Create_func_as_wkb() {}
+ virtual ~Create_func_as_wkb() {}
+};
+
+
+class Create_func_as_wkt : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_as_wkt(thd, arg1);
+ }
+
+ static Create_func_as_wkt s_singleton;
+
+protected:
+ Create_func_as_wkt() {}
+ virtual ~Create_func_as_wkt() {}
+};
+
+
+
+class Create_func_centroid : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_centroid(thd, arg1);
+ }
+
+ static Create_func_centroid s_singleton;
+
+protected:
+ Create_func_centroid() {}
+ virtual ~Create_func_centroid() {}
+};
+
+
+class Create_func_convexhull : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_convexhull(thd, arg1);
+ }
+
+ static Create_func_convexhull s_singleton;
+
+protected:
+ Create_func_convexhull() {}
+ virtual ~Create_func_convexhull() {}
+};
+
+
+class Create_func_pointonsurface : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_pointonsurface(thd, arg1);
+ }
+
+ static Create_func_pointonsurface s_singleton;
+
+protected:
+ Create_func_pointonsurface() {}
+ virtual ~Create_func_pointonsurface() {}
+};
+
+
+class Create_func_mbr_contains : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_CONTAINS_FUNC);
+ }
+
+ static Create_func_mbr_contains s_singleton;
+
+protected:
+ Create_func_mbr_contains() {}
+ virtual ~Create_func_mbr_contains() {}
+};
+
+
+class Create_func_contains : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_CONTAINS_FUNC);
+ }
+ static Create_func_contains s_singleton;
+
+protected:
+ Create_func_contains() {}
+ virtual ~Create_func_contains() {}
+};
+
+
+class Create_func_crosses : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_CROSSES_FUNC);
+ }
+ static Create_func_crosses s_singleton;
+
+protected:
+ Create_func_crosses() {}
+ virtual ~Create_func_crosses() {}
+};
+
+
+class Create_func_dimension : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_dimension(thd, arg1);
+ }
+
+ static Create_func_dimension s_singleton;
+
+protected:
+ Create_func_dimension() {}
+ virtual ~Create_func_dimension() {}
+};
+
+
+class Create_func_mbr_disjoint : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_DISJOINT_FUNC);
+ }
+
+ static Create_func_mbr_disjoint s_singleton;
+
+protected:
+ Create_func_mbr_disjoint() {}
+ virtual ~Create_func_mbr_disjoint() {}
+};
+
+
+class Create_func_disjoint : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_DISJOINT_FUNC);
+ }
+ static Create_func_disjoint s_singleton;
+
+protected:
+ Create_func_disjoint() {}
+ virtual ~Create_func_disjoint() {}
+};
+
+
+class Create_func_distance : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_distance(thd, arg1, arg2);
+ }
+
+ static Create_func_distance s_singleton;
+
+protected:
+ Create_func_distance() {}
+ virtual ~Create_func_distance() {}
+};
+
+
+
+class Create_func_endpoint : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_ENDPOINT);
+ }
+
+ static Create_func_endpoint s_singleton;
+
+protected:
+ Create_func_endpoint() {}
+ virtual ~Create_func_endpoint() {}
+};
+
+
+class Create_func_envelope : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_envelope(thd, arg1);
+ }
+
+ static Create_func_envelope s_singleton;
+
+protected:
+ Create_func_envelope() {}
+ virtual ~Create_func_envelope() {}
+};
+
+class Create_func_boundary : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_boundary(thd, arg1);
+ }
+
+ static Create_func_boundary s_singleton;
+
+protected:
+ Create_func_boundary() {}
+ virtual ~Create_func_boundary() {}
+};
+
+
+class Create_func_mbr_equals : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_EQUALS_FUNC);
+ }
+
+ static Create_func_mbr_equals s_singleton;
+
+protected:
+ Create_func_mbr_equals() {}
+ virtual ~Create_func_mbr_equals() {}
+};
+
+
+class Create_func_equals : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_EQUALS_FUNC);
+ }
+
+ static Create_func_equals s_singleton;
+
+protected:
+ Create_func_equals() {}
+ virtual ~Create_func_equals() {}
+};
+
+
+class Create_func_exteriorring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_EXTERIORRING);
+ }
+
+ static Create_func_exteriorring s_singleton;
+
+protected:
+ Create_func_exteriorring() {}
+ virtual ~Create_func_exteriorring() {}
+};
+
+
+
+class Create_func_geometry_from_text : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_text s_singleton;
+
+protected:
+ Create_func_geometry_from_text() {}
+ virtual ~Create_func_geometry_from_text() {}
+};
+
+
+Item*
+Create_func_geometry_from_text::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *param_1= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_text(thd, param_1, param_2);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_from_wkb : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_wkb s_singleton;
+
+protected:
+ Create_func_geometry_from_wkb() {}
+ virtual ~Create_func_geometry_from_wkb() {}
+};
+
+
+Item*
+Create_func_geometry_from_wkb::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *param_1= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *param_1= item_list->pop();
+ Item *param_2= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_wkb(thd, param_1, param_2);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_from_json : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_geometry_from_json s_singleton;
+
+protected:
+ Create_func_geometry_from_json() {}
+ virtual ~Create_func_geometry_from_json() {}
+};
+
+
+Item*
+Create_func_geometry_from_json::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *json= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *json= item_list->pop();
+ Item *options= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options);
+ break;
+ }
+ case 3:
+ {
+ Item *json= item_list->pop();
+ Item *options= item_list->pop();
+ Item *srid= item_list->pop();
+ func= new (thd->mem_root) Item_func_geometry_from_json(thd, json, options,
+ srid);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_as_geojson : public Create_native_func
+{
+public:
+ Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
+
+ static Create_func_as_geojson s_singleton;
+
+protected:
+ Create_func_as_geojson() {}
+ virtual ~Create_func_as_geojson() {}
+};
+
+
+Item*
+Create_func_as_geojson::create_native(THD *thd, LEX_CSTRING *name,
+ List<Item> *item_list)
+{
+ Item *func= NULL;
+ int arg_count= 0;
+
+ if (item_list != NULL)
+ arg_count= item_list->elements;
+
+ switch (arg_count) {
+ case 1:
+ {
+ Item *geom= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom);
+ thd->lex->uncacheable(UNCACHEABLE_RAND);
+ break;
+ }
+ case 2:
+ {
+ Item *geom= item_list->pop();
+ Item *max_dec= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec);
+ break;
+ }
+ case 3:
+ {
+ Item *geom= item_list->pop();
+ Item *max_dec= item_list->pop();
+ Item *options= item_list->pop();
+ func= new (thd->mem_root) Item_func_as_geojson(thd, geom, max_dec, options);
+ break;
+ }
+ default:
+ {
+ my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
+ break;
+ }
+ }
+
+ return func;
+}
+
+
+class Create_func_geometry_type : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_geometry_type(thd, arg1);
+ }
+
+ static Create_func_geometry_type s_singleton;
+
+protected:
+ Create_func_geometry_type() {}
+ virtual ~Create_func_geometry_type() {}
+};
+
+
+class Create_func_geometryn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_GEOMETRYN);
+ }
+
+ static Create_func_geometryn s_singleton;
+
+protected:
+ Create_func_geometryn() {}
+ virtual ~Create_func_geometryn() {}
+};
+
+
+#if !defined(DBUG_OFF)
+class Create_func_gis_debug : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_gis_debug(thd, arg1);
+ }
+
+ static Create_func_gis_debug s_singleton;
+
+protected:
+ Create_func_gis_debug() {}
+ virtual ~Create_func_gis_debug() {}
+};
+#endif
+
+
+class Create_func_glength : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_glength(thd, arg1);
+ }
+
+ static Create_func_glength s_singleton;
+
+protected:
+ Create_func_glength() {}
+ virtual ~Create_func_glength() {}
+};
+
+
+class Create_func_interiorringn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_INTERIORRINGN);
+ }
+
+ static Create_func_interiorringn s_singleton;
+
+protected:
+ Create_func_interiorringn() {}
+ virtual ~Create_func_interiorringn() {}
+};
+
+
+class Create_func_relate : public Create_func_arg3
+{
+public:
+ Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) override
+ {
+ return new (thd->mem_root) Item_func_spatial_relate(thd, arg1, arg2, arg3);
+ }
+
+ static Create_func_relate s_singleton;
+
+protected:
+ Create_func_relate() {}
+ virtual ~Create_func_relate() {}
+};
+
+
+class Create_func_mbr_intersects : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_INTERSECTS_FUNC);
+ }
+
+ static Create_func_mbr_intersects s_singleton;
+
+protected:
+ Create_func_mbr_intersects() {}
+ virtual ~Create_func_mbr_intersects() {}
+};
+
+
+class Create_func_intersects : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_INTERSECTS_FUNC);
+ }
+
+ static Create_func_intersects s_singleton;
+
+protected:
+ Create_func_intersects() {}
+ virtual ~Create_func_intersects() {}
+};
+
+
+class Create_func_intersection : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_intersection);
+ }
+
+ static Create_func_intersection s_singleton;
+
+protected:
+ Create_func_intersection() {}
+ virtual ~Create_func_intersection() {}
+};
+
+
+class Create_func_difference : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_difference);
+ }
+
+ static Create_func_difference s_singleton;
+
+protected:
+ Create_func_difference() {}
+ virtual ~Create_func_difference() {}
+};
+
+
+class Create_func_union : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_union);
+ }
+
+ static Create_func_union s_singleton;
+
+protected:
+ Create_func_union() {}
+ virtual ~Create_func_union() {}
+};
+
+
+class Create_func_symdifference : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_operation(thd, arg1, arg2,
+ Gcalc_function::op_symdifference);
+ }
+
+ static Create_func_symdifference s_singleton;
+
+protected:
+ Create_func_symdifference() {}
+ virtual ~Create_func_symdifference() {}
+};
+
+
+class Create_func_buffer : public Create_func_arg2
+{
+public:
+ Item* create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_buffer(thd, arg1, arg2);
+ }
+
+ static Create_func_buffer s_singleton;
+
+protected:
+ Create_func_buffer() {}
+ virtual ~Create_func_buffer() {}
+};
+
+
+class Create_func_isclosed : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isclosed(thd, arg1);
+ }
+
+ static Create_func_isclosed s_singleton;
+
+protected:
+ Create_func_isclosed() {}
+ virtual ~Create_func_isclosed() {}
+};
+
+
+class Create_func_isring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isring(thd, arg1);
+ }
+
+ static Create_func_isring s_singleton;
+
+protected:
+ Create_func_isring() {}
+ virtual ~Create_func_isring() {}
+};
+
+
+class Create_func_isempty : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_isempty(thd, arg1);
+ }
+
+ static Create_func_isempty s_singleton;
+
+protected:
+ Create_func_isempty() {}
+ virtual ~Create_func_isempty() {}
+};
+
+
+class Create_func_issimple : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_issimple(thd, arg1);
+ }
+
+ static Create_func_issimple s_singleton;
+
+protected:
+ Create_func_issimple() {}
+ virtual ~Create_func_issimple() {}
+};
+
+
+
+class Create_func_numgeometries : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numgeometries(thd, arg1);
+ }
+
+ static Create_func_numgeometries s_singleton;
+
+protected:
+ Create_func_numgeometries() {}
+ virtual ~Create_func_numgeometries() {}
+};
+
+
+class Create_func_numinteriorring : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numinteriorring(thd, arg1);
+ }
+
+ static Create_func_numinteriorring s_singleton;
+
+protected:
+ Create_func_numinteriorring() {}
+ virtual ~Create_func_numinteriorring() {}
+};
+
+
+class Create_func_numpoints : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_numpoints(thd, arg1);
+ }
+
+ static Create_func_numpoints s_singleton;
+
+protected:
+ Create_func_numpoints() {}
+ virtual ~Create_func_numpoints() {}
+};
+
+
+class Create_func_mbr_overlaps : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_OVERLAPS_FUNC);
+ }
+
+ static Create_func_mbr_overlaps s_singleton;
+
+protected:
+ Create_func_mbr_overlaps() {}
+ virtual ~Create_func_mbr_overlaps() {}
+};
+
+
+class Create_func_overlaps : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_OVERLAPS_FUNC);
+ }
+
+ static Create_func_overlaps s_singleton;
+
+protected:
+ Create_func_overlaps() {}
+ virtual ~Create_func_overlaps() {}
+};
+
+
+
+
+
+class Create_func_pointn : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp_n(thd, arg1, arg2,
+ Item_func::SP_POINTN);
+ }
+ static Create_func_pointn s_singleton;
+
+protected:
+ Create_func_pointn() {}
+ virtual ~Create_func_pointn() {}
+};
+
+
+
+
+class Create_func_srid : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_srid(thd, arg1);
+ }
+
+ static Create_func_srid s_singleton;
+
+protected:
+ Create_func_srid() {}
+ virtual ~Create_func_srid() {}
+};
+
+
+class Create_func_startpoint : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_spatial_decomp(thd, arg1,
+ Item_func::SP_STARTPOINT);
+ }
+
+ static Create_func_startpoint s_singleton;
+
+protected:
+ Create_func_startpoint() {}
+ virtual ~Create_func_startpoint() {}
+};
+
+
+
+class Create_func_touches : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_TOUCHES_FUNC);
+ }
+
+ static Create_func_touches s_singleton;
+
+protected:
+ Create_func_touches() {}
+ virtual ~Create_func_touches() {}
+};
+
+
+class Create_func_mbr_within : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_mbr_rel(thd, arg1, arg2,
+ Item_func::SP_WITHIN_FUNC);
+ }
+
+ static Create_func_mbr_within s_singleton;
+
+protected:
+ Create_func_mbr_within() {}
+ virtual ~Create_func_mbr_within() {}
+};
+
+
+class Create_func_within : public Create_func_arg2
+{
+public:
+ Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) override
+ {
+ return new (thd->mem_root) Item_func_spatial_precise_rel(thd, arg1, arg2,
+ Item_func::SP_WITHIN_FUNC);
+ }
+
+ static Create_func_within s_singleton;
+
+protected:
+ Create_func_within() {}
+ virtual ~Create_func_within() {}
+};
+
+
+class Create_func_x : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_x(thd, arg1);
+ }
+
+ static Create_func_x s_singleton;
+
+protected:
+ Create_func_x() {}
+ virtual ~Create_func_x() {}
+};
+
+
+class Create_func_y : public Create_func_arg1
+{
+public:
+ Item *create_1_arg(THD *thd, Item *arg1) override
+ {
+ return new (thd->mem_root) Item_func_y(thd, arg1);
+ }
+
+ static Create_func_y s_singleton;
+
+protected:
+ Create_func_y() {}
+ virtual ~Create_func_y() {}
+};
+
+
+/*****************************************************************/
+
+
+
+
+
+
+
+/*************************************************************************/
+
+#if !defined(DBUG_OFF)
+Create_func_gis_debug Create_func_gis_debug::s_singleton;
+#endif
+
+Create_func_area Create_func_area::s_singleton;
+Create_func_as_geojson Create_func_as_geojson::s_singleton;
+Create_func_as_wkb Create_func_as_wkb::s_singleton;
+Create_func_as_wkt Create_func_as_wkt::s_singleton;
+Create_func_boundary Create_func_boundary::s_singleton;
+Create_func_buffer Create_func_buffer::s_singleton;
+Create_func_centroid Create_func_centroid::s_singleton;
+Create_func_contains Create_func_contains::s_singleton;
+Create_func_convexhull Create_func_convexhull::s_singleton;
+Create_func_crosses Create_func_crosses::s_singleton;
+Create_func_difference Create_func_difference::s_singleton;
+Create_func_dimension Create_func_dimension::s_singleton;
+Create_func_disjoint Create_func_disjoint::s_singleton;
+Create_func_distance Create_func_distance::s_singleton;
+Create_func_endpoint Create_func_endpoint::s_singleton;
+Create_func_envelope Create_func_envelope::s_singleton;
+Create_func_equals Create_func_equals::s_singleton;
+Create_func_exteriorring Create_func_exteriorring::s_singleton;
+Create_func_geometry_from_json Create_func_geometry_from_json::s_singleton;
+Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton;
+Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton;
+Create_func_geometryn Create_func_geometryn::s_singleton;
+Create_func_geometry_type Create_func_geometry_type::s_singleton;
+Create_func_glength Create_func_glength::s_singleton;
+Create_func_interiorringn Create_func_interiorringn::s_singleton;
+Create_func_intersection Create_func_intersection::s_singleton;
+Create_func_intersects Create_func_intersects::s_singleton;
+Create_func_isclosed Create_func_isclosed::s_singleton;
+Create_func_isempty Create_func_isempty::s_singleton;
+Create_func_isring Create_func_isring::s_singleton;
+Create_func_issimple Create_func_issimple::s_singleton;
+Create_func_mbr_contains Create_func_mbr_contains::s_singleton;
+Create_func_mbr_disjoint Create_func_mbr_disjoint::s_singleton;
+Create_func_mbr_equals Create_func_mbr_equals::s_singleton;
+Create_func_mbr_intersects Create_func_mbr_intersects::s_singleton;
+Create_func_mbr_overlaps Create_func_mbr_overlaps::s_singleton;
+Create_func_mbr_within Create_func_mbr_within::s_singleton;
+Create_func_numgeometries Create_func_numgeometries::s_singleton;
+Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
+Create_func_numpoints Create_func_numpoints::s_singleton;
+Create_func_overlaps Create_func_overlaps::s_singleton;
+Create_func_pointn Create_func_pointn::s_singleton;
+Create_func_pointonsurface Create_func_pointonsurface::s_singleton;
+Create_func_relate Create_func_relate::s_singleton;
+Create_func_srid Create_func_srid::s_singleton;
+Create_func_startpoint Create_func_startpoint::s_singleton;
+Create_func_symdifference Create_func_symdifference::s_singleton;
+Create_func_touches Create_func_touches::s_singleton;
+Create_func_union Create_func_union::s_singleton;
+Create_func_within Create_func_within::s_singleton;
+Create_func_x Create_func_x::s_singleton;
+Create_func_y Create_func_y::s_singleton;
+
+/*************************************************************************/
+
+
+class FHash: public HASH
+{
+public:
+ FHash()
+ {
+ bzero((HASH *) this, sizeof(HASH));
+ }
+};
+
+
+#define GEOM_BUILDER(F) & F::s_singleton
+
+
+static Native_func_registry func_array_geom[] =
+{
+#ifndef DBUG_OFF
+ { { STRING_WITH_LEN("ST_GIS_DEBUG") }, GEOM_BUILDER(Create_func_gis_debug)},
+#endif
+ { { STRING_WITH_LEN("AREA") }, GEOM_BUILDER(Create_func_area)},
+ { { STRING_WITH_LEN("ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
+ { { STRING_WITH_LEN("BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
+ { { STRING_WITH_LEN("CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
+ { { STRING_WITH_LEN("CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
+ { { STRING_WITH_LEN("CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
+ { { STRING_WITH_LEN("CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
+ { { STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
+ { { STRING_WITH_LEN("DISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
+ { { STRING_WITH_LEN("ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
+ { { STRING_WITH_LEN("ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
+ { { STRING_WITH_LEN("EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
+ { { STRING_WITH_LEN("GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
+ { { STRING_WITH_LEN("GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
+ { { STRING_WITH_LEN("GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("GLENGTH") }, GEOM_BUILDER(Create_func_glength)},
+ { { STRING_WITH_LEN("INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
+ { { STRING_WITH_LEN("INTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
+ { { STRING_WITH_LEN("ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
+ { { STRING_WITH_LEN("ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
+ { { STRING_WITH_LEN("ISRING") }, GEOM_BUILDER(Create_func_isring)},
+ { { STRING_WITH_LEN("ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
+ { { STRING_WITH_LEN("LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MBRCONTAINS") }, GEOM_BUILDER(Create_func_mbr_contains)},
+ { { STRING_WITH_LEN("MBRDISJOINT") }, GEOM_BUILDER(Create_func_mbr_disjoint)},
+ { { STRING_WITH_LEN("MBREQUAL") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { STRING_WITH_LEN("MBREQUALS") }, GEOM_BUILDER(Create_func_mbr_equals)},
+ { { STRING_WITH_LEN("MBRINTERSECTS") }, GEOM_BUILDER(Create_func_mbr_intersects)},
+ { { STRING_WITH_LEN("MBROVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
+ { { STRING_WITH_LEN("MBRTOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("MBRWITHIN") }, GEOM_BUILDER(Create_func_mbr_within)},
+ { { STRING_WITH_LEN("MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
+ { { STRING_WITH_LEN("NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
+ { { STRING_WITH_LEN("NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
+ { { STRING_WITH_LEN("OVERLAPS") }, GEOM_BUILDER(Create_func_mbr_overlaps)},
+ { { STRING_WITH_LEN("POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("POINTN") }, GEOM_BUILDER(Create_func_pointn)},
+ { { STRING_WITH_LEN("POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
+ { { STRING_WITH_LEN("POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("SRID") }, GEOM_BUILDER(Create_func_srid)},
+ { { STRING_WITH_LEN("ST_AREA") }, GEOM_BUILDER(Create_func_area)},
+ { { STRING_WITH_LEN("STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
+ { { STRING_WITH_LEN("ST_ASBINARY") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ST_ASGEOJSON") }, GEOM_BUILDER(Create_func_as_geojson)},
+ { { STRING_WITH_LEN("ST_ASTEXT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ST_ASWKB") }, GEOM_BUILDER(Create_func_as_wkb)},
+ { { STRING_WITH_LEN("ST_ASWKT") }, GEOM_BUILDER(Create_func_as_wkt)},
+ { { STRING_WITH_LEN("ST_BOUNDARY") }, GEOM_BUILDER(Create_func_boundary)},
+ { { STRING_WITH_LEN("ST_BUFFER") }, GEOM_BUILDER(Create_func_buffer)},
+ { { STRING_WITH_LEN("ST_CENTROID") }, GEOM_BUILDER(Create_func_centroid)},
+ { { STRING_WITH_LEN("ST_CONTAINS") }, GEOM_BUILDER(Create_func_contains)},
+ { { STRING_WITH_LEN("ST_CONVEXHULL") }, GEOM_BUILDER(Create_func_convexhull)},
+ { { STRING_WITH_LEN("ST_CROSSES") }, GEOM_BUILDER(Create_func_crosses)},
+ { { STRING_WITH_LEN("ST_DIFFERENCE") }, GEOM_BUILDER(Create_func_difference)},
+ { { STRING_WITH_LEN("ST_DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},
+ { { STRING_WITH_LEN("ST_DISJOINT") }, GEOM_BUILDER(Create_func_disjoint)},
+ { { STRING_WITH_LEN("ST_DISTANCE") }, GEOM_BUILDER(Create_func_distance)},
+ { { STRING_WITH_LEN("ST_ENDPOINT") }, GEOM_BUILDER(Create_func_endpoint)},
+ { { STRING_WITH_LEN("ST_ENVELOPE") }, GEOM_BUILDER(Create_func_envelope)},
+ { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("ST_EQUALS") }, GEOM_BUILDER(Create_func_equals)},
+ { { STRING_WITH_LEN("ST_EXTERIORRING") }, GEOM_BUILDER(Create_func_exteriorring)},
+ { { STRING_WITH_LEN("ST_GEOMCOLLFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMCOLLFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMETRYCOLLECTIONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMETRYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_GEOMETRYN") }, GEOM_BUILDER(Create_func_geometryn)},
+ { { STRING_WITH_LEN("ST_GEOMETRYTYPE") }, GEOM_BUILDER(Create_func_geometry_type)},
+ { { STRING_WITH_LEN("ST_GEOMFROMGEOJSON") }, GEOM_BUILDER(Create_func_geometry_from_json)},
+ { { STRING_WITH_LEN("ST_GEOMFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_GEOMFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_INTERIORRINGN") }, GEOM_BUILDER(Create_func_interiorringn)},
+ { { STRING_WITH_LEN("ST_INTERSECTION") }, GEOM_BUILDER(Create_func_intersection)},
+ { { STRING_WITH_LEN("ST_INTERSECTS") }, GEOM_BUILDER(Create_func_intersects)},
+ { { STRING_WITH_LEN("ST_ISCLOSED") }, GEOM_BUILDER(Create_func_isclosed)},
+ { { STRING_WITH_LEN("ST_ISEMPTY") }, GEOM_BUILDER(Create_func_isempty)},
+ { { STRING_WITH_LEN("ST_ISRING") }, GEOM_BUILDER(Create_func_isring)},
+ { { STRING_WITH_LEN("ST_ISSIMPLE") }, GEOM_BUILDER(Create_func_issimple)},
+ { { STRING_WITH_LEN("ST_LENGTH") }, GEOM_BUILDER(Create_func_glength)},
+ { { STRING_WITH_LEN("ST_LINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_LINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_LINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_LINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MLINEFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MLINEFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MPOLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MPOLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTILINESTRINGFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTIPOINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTIPOINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_MULTIPOLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_NUMGEOMETRIES") }, GEOM_BUILDER(Create_func_numgeometries)},
+ { { STRING_WITH_LEN("ST_NUMINTERIORRINGS") }, GEOM_BUILDER(Create_func_numinteriorring)},
+ { { STRING_WITH_LEN("ST_NUMPOINTS") }, GEOM_BUILDER(Create_func_numpoints)},
+ { { STRING_WITH_LEN("ST_OVERLAPS") }, GEOM_BUILDER(Create_func_overlaps)},
+ { { STRING_WITH_LEN("ST_POINTFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POINTFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_POINTN") }, GEOM_BUILDER(Create_func_pointn)},
+ { { STRING_WITH_LEN("ST_POINTONSURFACE") }, GEOM_BUILDER(Create_func_pointonsurface)},
+ { { STRING_WITH_LEN("ST_POLYFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POLYFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_POLYGONFROMTEXT") }, GEOM_BUILDER(Create_func_geometry_from_text)},
+ { { STRING_WITH_LEN("ST_POLYGONFROMWKB") }, GEOM_BUILDER(Create_func_geometry_from_wkb)},
+ { { STRING_WITH_LEN("ST_RELATE") }, GEOM_BUILDER(Create_func_relate)},
+ { { STRING_WITH_LEN("ST_SRID") }, GEOM_BUILDER(Create_func_srid)},
+ { { STRING_WITH_LEN("ST_STARTPOINT") }, GEOM_BUILDER(Create_func_startpoint)},
+ { { STRING_WITH_LEN("ST_SYMDIFFERENCE") }, GEOM_BUILDER(Create_func_symdifference)},
+ { { STRING_WITH_LEN("ST_TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("ST_UNION") }, GEOM_BUILDER(Create_func_union)},
+ { { STRING_WITH_LEN("ST_WITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { STRING_WITH_LEN("ST_X") }, GEOM_BUILDER(Create_func_x)},
+ { { STRING_WITH_LEN("ST_Y") }, GEOM_BUILDER(Create_func_y)},
+ { { STRING_WITH_LEN("TOUCHES") }, GEOM_BUILDER(Create_func_touches)},
+ { { STRING_WITH_LEN("WITHIN") }, GEOM_BUILDER(Create_func_within)},
+ { { STRING_WITH_LEN("X") }, GEOM_BUILDER(Create_func_x)},
+ { { STRING_WITH_LEN("Y") }, GEOM_BUILDER(Create_func_y)},
+};
+
+
+extern "C" uchar*
+get_native_fct_hash_key_geom(const uchar *buff, size_t *length,
+ my_bool /* unused */)
+{
+ Native_func_registry *func= (Native_func_registry*) buff;
+ *length= func->name.length;
+ return (uchar*) func->name.str;
+}
+
+
+Function_collection_geometry function_collection_geometry;
+
+static FHash hash_funcn;
+
+
+Create_func *
+Function_collection_geometry::find_native_function_builder(THD *thd,
+ const LEX_CSTRING &f)
+ const
+{
+ Native_func_registry *func;
+ func= (Native_func_registry*) my_hash_search(&hash_funcn,
+ (uchar*) f.str, f.length);
+ return func ? func->builder : NULL;
+}
+
+
+bool Function_collection_geometry::init()
+{
+ DBUG_ENTER("Type_collection_geometry::init_functions");
+ if (my_hash_init(&hash_funcn,
+ system_charset_info,
+ array_elements(func_array_geom),
+ 0,
+ 0,
+ (my_hash_get_key) get_native_fct_hash_key_geom,
+ NULL, /* Nothing to free */
+ MYF(0)))
+ DBUG_RETURN(true);
+
+ for (uint i= 0; i < array_elements(func_array_geom); i++)
+ {
+ Native_func_registry *func= &func_array_geom[i];
+ DBUG_ASSERT(func->builder != NULL);
+ if (my_hash_insert(&hash_funcn, (uchar*) func))
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(false);
+}
+
+
+void Function_collection_geometry::cleanup()
+{
+ my_hash_free(&hash_funcn);
+}
+
+
#endif /*HAVE_SPATIAL*/
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 4e7cda137c2..c38d0b986f1 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -26,6 +26,10 @@
#pragma interface /* gcc class implementation */
#endif
+#include "sql_type_geom.h"
+#include "item.h"
+#include "gstream.h"
+#include "spatial.h"
#include "gcalc_slicescan.h"
#include "gcalc_tools.h"
@@ -53,7 +57,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_real_func_args_geometry(THD *thd, Item *a)
@@ -69,7 +74,8 @@ class Item_long_func_args_geometry: public Item_long_func
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
protected:
String value;
@@ -89,7 +95,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count == 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_bool_func_args_geometry(THD *thd, Item *a)
@@ -106,7 +113,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_str_ascii_func_args_geometry(THD *thd, Item *a)
@@ -127,7 +135,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_binary_func_args_geometry(THD *thd, Item *a)
@@ -144,7 +153,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 1);
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry);
+ return Type_handler_geometry::check_type_geom_or_binary(func_name(),
+ args[0]);
}
public:
Item_geometry_func_args_geometry(THD *thd, Item *a)
@@ -163,7 +173,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_real_func_args_geometry_geometry(THD *thd, Item *a, Item *b)
@@ -181,7 +192,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_bool_func_args_geometry_geometry(THD *thd, Item *a, Item *b, Item *c)
@@ -210,8 +222,9 @@ class Item_func_geometry_from_wkb: public Item_geometry_func
{
bool check_arguments() const
{
- return args[0]->check_type_or_binary(func_name(), &type_handler_geometry) ||
- check_argument_types_can_return_int(1, MY_MIN(2, arg_count));
+ return
+ Type_handler_geometry::check_type_geom_or_binary(func_name(), args[0]) ||
+ check_argument_types_can_return_int(1, MY_MIN(2, arg_count));
}
public:
Item_func_geometry_from_wkb(THD *thd, Item *a): Item_geometry_func(thd, a) {}
@@ -363,7 +376,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_centroid"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_centroid>(thd, this); }
};
@@ -375,7 +391,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_envelope"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_polygon;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_envelope>(thd, this); }
};
@@ -425,7 +444,10 @@ public:
Item_geometry_func(thd, a, b, srid) {}
const char *func_name() const { return "point"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_point>(thd, this); }
};
@@ -493,7 +515,8 @@ class Item_func_spatial_collection: public Item_geometry_func
{
bool check_arguments() const
{
- return check_argument_types_or_binary(&type_handler_geometry, 0, arg_count);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(), args,
+ 0, arg_count);
}
enum Geometry::wkbType coll_type;
enum Geometry::wkbType item_type;
@@ -524,13 +547,112 @@ public:
}
return FALSE;
}
-
+};
+
+
+class Item_func_geometrycollection: public Item_func_spatial_collection
+{
+public:
+ Item_func_geometrycollection(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_geometrycollection,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_geometrycollection;
+ }
const char *func_name() const { return "geometrycollection"; }
Item *get_copy(THD *thd)
- { return get_item_copy<Item_func_spatial_collection>(thd, this); }
+ { return get_item_copy<Item_func_geometrycollection>(thd, this); }
};
+class Item_func_linestring: public Item_func_spatial_collection
+{
+public:
+ Item_func_linestring(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_linestring,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const { return &type_handler_linestring; }
+ const char *func_name() const { return "linestring"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_linestring>(thd, this); }
+};
+
+
+class Item_func_polygon: public Item_func_spatial_collection
+{
+public:
+ Item_func_polygon(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_polygon,
+ Geometry::wkb_linestring)
+ { }
+ const Type_handler *type_handler() const { return &type_handler_polygon; }
+ const char *func_name() const { return "polygon"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_polygon>(thd, this); }
+};
+
+
+class Item_func_multilinestring: public Item_func_spatial_collection
+{
+public:
+ Item_func_multilinestring(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multilinestring,
+ Geometry::wkb_linestring)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multilinestring;
+ }
+ const char *func_name() const { return "multilinestring"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multilinestring>(thd, this); }
+};
+
+
+class Item_func_multipoint: public Item_func_spatial_collection
+{
+public:
+ Item_func_multipoint(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multipoint,
+ Geometry::wkb_point)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multipoint;
+ }
+ const char *func_name() const { return "multipoint"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multipoint>(thd, this); }
+};
+
+
+class Item_func_multipolygon: public Item_func_spatial_collection
+{
+public:
+ Item_func_multipolygon(THD *thd, List<Item> &list)
+ :Item_func_spatial_collection(thd, list,
+ Geometry::wkb_multipolygon,
+ Geometry::wkb_polygon)
+ { }
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_multipolygon;
+ }
+ const char *func_name() const { return "multipolygon"; }
+ Item *get_copy(THD *thd)
+ { return get_item_copy<Item_func_multipolygon>(thd, this); }
+};
+
+
+
/*
Spatial relations
*/
@@ -546,7 +668,8 @@ protected:
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Item_func_spatial_rel(THD *thd, Item *a, Item *b, enum Functype sp_rel):
@@ -641,7 +764,8 @@ class Item_func_spatial_operation: public Item_geometry_func
bool check_arguments() const
{
DBUG_ASSERT(arg_count >= 2);
- return check_argument_types_or_binary(&type_handler_geometry, 0, 2);
+ return Type_handler_geometry::check_types_geom_or_binary(func_name(),
+ args, 0, 2);
}
public:
Gcalc_function::op_type spatial_op;
@@ -945,7 +1069,10 @@ public:
:Item_geometry_func_args_geometry(thd, a) {}
const char *func_name() const { return "st_pointonsurface"; }
String *val_str(String *);
- Field::geometry_type get_geometry_type() const;
+ const Type_handler *type_handler() const
+ {
+ return &type_handler_point;
+ }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_pointonsurface>(thd, this); }
};
@@ -971,10 +1098,12 @@ class Item_func_gis_debug: public Item_long_func
#define GEOM_NEW(thd, obj_constructor) new (thd->mem_root) obj_constructor
+#define GEOM_TYPE(x) (x)
#else /*HAVE_SPATIAL*/
#define GEOM_NEW(thd, obj_constructor) NULL
+#define GEOM_TYPE(x) NULL
#endif /*HAVE_SPATIAL*/
#endif /* ITEM_GEOFUNC_INCLUDED */
diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc
index a90e7fb3a1a..816f1e8d723 100644
--- a/sql/item_jsonfunc.cc
+++ b/sql/item_jsonfunc.cc
@@ -439,7 +439,17 @@ bool Item_func_json_value::fix_length_and_dec()
{
collation.set(args[0]->collation);
max_length= args[0]->max_length;
- path.set_constant_flag(args[1]->const_item());
+ set_constant_flag(args[1]->const_item());
+ maybe_null= 1;
+ return FALSE;
+}
+
+
+bool Item_func_json_query::fix_length_and_dec()
+{
+ collation.set(args[0]->collation);
+ max_length= args[0]->max_length;
+ set_constant_flag(args[1]->const_item());
maybe_null= 1;
return FALSE;
}
@@ -449,115 +459,100 @@ bool Item_func_json_value::fix_length_and_dec()
Returns NULL, not an error if the found value
is not a scalar.
*/
-String *Item_func_json_value::val_str(String *str)
+bool Json_path_extractor::extract(String *str, Item *item_js, Item *item_jp,
+ CHARSET_INFO *cs)
{
- json_engine_t je;
- String *js= args[0]->val_json(&tmp_js);
+ String *js= item_js->val_json(&tmp_js);
int error= 0;
uint array_counters[JSON_DEPTH_LIMIT];
- if (!path.parsed)
+ if (!parsed)
{
- String *s_p= args[1]->val_str(&tmp_path);
+ String *s_p= item_jp->val_str(&tmp_path);
if (s_p &&
- json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(),
+ json_path_setup(&p, s_p->charset(), (const uchar *) s_p->ptr(),
(const uchar *) s_p->ptr() + s_p->length()))
- goto err_return;
- path.parsed= path.constant;
+ return true;
+ parsed= constant;
}
- if ((null_value= args[0]->null_value || args[1]->null_value))
- return NULL;
-
- json_scan_start(&je, js->charset(),(const uchar *) js->ptr(),
- (const uchar *) js->ptr() + js->length());
+ if (item_js->null_value || item_jp->null_value)
+ return true;
+ Json_engine_scan je(*js);
str->length(0);
- str->set_charset(collation.collation);
+ str->set_charset(cs);
- path.cur_step= path.p.steps;
+ cur_step= p.steps;
continue_search:
- if (json_find_path(&je, &path.p, &path.cur_step, array_counters))
- {
- if (je.s.error)
- goto err_return;
-
- null_value= 1;
- return 0;
- }
+ if (json_find_path(&je, &p, &cur_step, array_counters))
+ return true;
if (json_read_value(&je))
- goto err_return;
+ return true;
if (unlikely(check_and_get_value(&je, str, &error)))
{
if (error)
- goto err_return;
+ return true;
goto continue_search;
}
- return str;
-
-err_return:
- null_value= 1;
- return 0;
+ return false;
}
-bool Item_func_json_value::check_and_get_value(json_engine_t *je, String *res,
- int *error)
+bool Json_engine_scan::check_and_get_value_scalar(String *res, int *error)
{
CHARSET_INFO *json_cs;
const uchar *js;
uint js_len;
- if (!json_value_scalar(je))
+ if (!json_value_scalar(this))
{
/* We only look for scalar values! */
- if (json_skip_level(je) || json_scan_next(je))
+ if (json_skip_level(this) || json_scan_next(this))
*error= 1;
return true;
}
- if (je->value_type == JSON_VALUE_TRUE ||
- je->value_type == JSON_VALUE_FALSE)
+ if (value_type == JSON_VALUE_TRUE ||
+ value_type == JSON_VALUE_FALSE)
{
json_cs= &my_charset_utf8mb4_bin;
- js= (const uchar *) ((je->value_type == JSON_VALUE_TRUE) ? "1" : "0");
+ js= (const uchar *) ((value_type == JSON_VALUE_TRUE) ? "1" : "0");
js_len= 1;
}
else
{
- json_cs= je->s.cs;
- js= je->value;
- js_len= je->value_len;
+ json_cs= s.cs;
+ js= value;
+ js_len= value_len;
}
- return st_append_json(res, json_cs, js, js_len);
+ return st_append_json(res, json_cs, js, js_len);
}
-bool Item_func_json_query::check_and_get_value(json_engine_t *je, String *res,
- int *error)
+bool Json_engine_scan::check_and_get_value_complex(String *res, int *error)
{
- const uchar *value;
- if (json_value_scalar(je))
+ if (json_value_scalar(this))
{
/* We skip scalar values. */
- if (json_scan_next(je))
+ if (json_scan_next(this))
*error= 1;
return true;
}
- value= je->value;
- if (json_skip_level(je))
+ const uchar *tmp_value= value;
+ if (json_skip_level(this))
{
*error= 1;
return true;
}
- res->set((const char *) je->value, (uint32)(je->s.c_str - value), je->s.cs);
+ res->set((const char *) value, (uint32)(s.c_str - tmp_value), s.cs);
return false;
}
@@ -600,7 +595,7 @@ String *Item_func_json_quote::val_str(String *str)
bool Item_func_json_unquote::fix_length_and_dec()
{
- collation.set(&my_charset_utf8_general_ci,
+ collation.set(&my_charset_utf8mb3_general_ci,
DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
max_length= args[0]->max_length;
maybe_null= 1;
@@ -645,12 +640,12 @@ String *Item_func_json_unquote::val_str(String *str)
return js;
str->length(0);
- str->set_charset(&my_charset_utf8_general_ci);
+ str->set_charset(&my_charset_utf8mb3_general_ci);
if (str->realloc_with_extra_if_needed(je.value_len) ||
(c_len= json_unescape(js->charset(),
je.value, je.value + je.value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) str->ptr(), (uchar *) (str->ptr() + je.value_len))) < 0)
goto error;
@@ -680,7 +675,7 @@ static int alloc_tmp_paths(THD *thd, uint n_paths,
return 1;
for (uint c_path=0; c_path < n_paths; c_path++)
- (*tmp_paths)[c_path].set_charset(&my_charset_utf8_general_ci);
+ (*tmp_paths)[c_path].set_charset(&my_charset_utf8mb3_general_ci);
}
return 0;
@@ -2619,7 +2614,7 @@ longlong Item_func_json_depth::val_int()
bool Item_func_json_type::fix_length_and_dec()
{
- collation.set(&my_charset_utf8_general_ci);
+ collation.set(&my_charset_utf8mb3_general_ci);
max_length= 12;
maybe_null= 1;
return FALSE;
@@ -2665,7 +2660,7 @@ String *Item_func_json_type::val_str(String *str)
break;
}
- str->set(type, strlen(type), &my_charset_utf8_general_ci);
+ str->set(type, strlen(type), &my_charset_utf8mb3_general_ci);
return str;
error:
@@ -3567,7 +3562,7 @@ int Arg_comparator::compare_json_str_basic(Item *j, Item *s)
if (value2.realloc_with_extra_if_needed(je.value_len) ||
(c_len= json_unescape(js->charset(), je.value,
je.value + je.value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) value2.ptr(),
(uchar *) (value2.ptr() + je.value_len))) < 0)
goto error;
@@ -3616,7 +3611,7 @@ int Arg_comparator::compare_e_json_str_basic(Item *j, Item *s)
if (value1.realloc_with_extra_if_needed(value_len) ||
(c_len= json_unescape(value1.charset(), (uchar *) value,
(uchar *) value+value_len,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
(uchar *) value1.ptr(),
(uchar *) (value1.ptr() + value_len))) < 0)
return 1;
diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h
index e9b77502e80..c4dfe9adfb4 100644
--- a/sql/item_jsonfunc.h
+++ b/sql/item_jsonfunc.h
@@ -40,6 +40,33 @@ public:
};
+class Json_engine_scan: public json_engine_t
+{
+public:
+ Json_engine_scan(CHARSET_INFO *i_cs, const uchar *str, const uchar *end)
+ {
+ json_scan_start(this, i_cs, str, end);
+ }
+ Json_engine_scan(const String &str)
+ :Json_engine_scan(str.charset(), (const uchar *) str.ptr(),
+ (const uchar *) str.end())
+ { }
+ bool check_and_get_value_scalar(String *res, int *error);
+ bool check_and_get_value_complex(String *res, int *error);
+};
+
+
+class Json_path_extractor: public json_path_with_flags
+{
+protected:
+ String tmp_js, tmp_path;
+ virtual ~Json_path_extractor() { }
+ virtual bool check_and_get_value(Json_engine_scan *je,
+ String *to, int *error)=0;
+ bool extract(String *to, Item *js, Item *jp, CHARSET_INFO *cs);
+};
+
+
class Item_func_json_valid: public Item_bool_func
{
protected:
@@ -78,33 +105,66 @@ public:
};
-class Item_func_json_value: public Item_str_func
+class Item_json_func: public Item_str_func
+{
+public:
+ Item_json_func(THD *thd)
+ :Item_str_func(thd) { }
+ Item_json_func(THD *thd, Item *a)
+ :Item_str_func(thd, a) { }
+ Item_json_func(THD *thd, Item *a, Item *b)
+ :Item_str_func(thd, a, b) { }
+ Item_json_func(THD *thd, List<Item> &list)
+ :Item_str_func(thd, list) { }
+ bool is_json_type() { return true; }
+};
+
+
+class Item_func_json_value: public Item_str_func,
+ public Json_path_extractor
{
-protected:
- json_path_with_flags path;
- String tmp_js, tmp_path;
public:
Item_func_json_value(THD *thd, Item *js, Item *i_path):
Item_str_func(thd, js, i_path) {}
- const char *func_name() const { return "json_value"; }
- bool fix_length_and_dec();
- String *val_str(String *);
- virtual bool check_and_get_value(json_engine_t *je, String *res, int *error);
- Item *get_copy(THD *thd)
+ const char *func_name() const override { return "json_value"; }
+ bool fix_length_and_dec() override ;
+ String *val_str(String *to) override
+ {
+ null_value= Json_path_extractor::extract(to, args[0], args[1],
+ collation.collation);
+ return null_value ? NULL : to;
+ }
+ bool check_and_get_value(Json_engine_scan *je,
+ String *res, int *error) override
+ {
+ return je->check_and_get_value_scalar(res, error);
+ }
+ Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_json_value>(thd, this); }
};
-class Item_func_json_query: public Item_func_json_value
+class Item_func_json_query: public Item_json_func,
+ public Json_path_extractor
{
public:
Item_func_json_query(THD *thd, Item *js, Item *i_path):
- Item_func_json_value(thd, js, i_path) {}
- bool is_json_type() { return true; }
- const char *func_name() const { return "json_query"; }
- bool check_and_get_value(json_engine_t *je, String *res, int *error);
- Item *get_copy(THD *thd)
+ Item_json_func(thd, js, i_path) {}
+ const char *func_name() const override { return "json_query"; }
+ bool fix_length_and_dec() override;
+ String *val_str(String *to) override
+ {
+ null_value= Json_path_extractor::extract(to, args[0], args[1],
+ collation.collation);
+ return null_value ? NULL : to;
+ }
+ bool check_and_get_value(Json_engine_scan *je,
+ String *res, int *error) override
+ {
+ return je->check_and_get_value_complex(res, error);
+ }
+ Item *get_copy(THD *thd) override
{ return get_item_copy<Item_func_json_query>(thd, this); }
};
@@ -139,18 +199,17 @@ public:
};
-class Item_json_str_multipath: public Item_str_func
+class Item_json_str_multipath: public Item_json_func
{
protected:
json_path_with_flags *paths;
String *tmp_paths;
public:
Item_json_str_multipath(THD *thd, List<Item> &list):
- Item_str_func(thd, list), tmp_paths(0) {}
+ Item_json_func(thd, list), tmp_paths(0) {}
bool fix_fields(THD *thd, Item **ref);
void cleanup();
virtual uint get_n_paths() const = 0;
- bool is_json_type() { return true; }
};
@@ -217,18 +276,17 @@ public:
};
-class Item_func_json_array: public Item_str_func
+class Item_func_json_array: public Item_json_func
{
protected:
String tmp_val;
ulong result_limit;
public:
Item_func_json_array(THD *thd):
- Item_str_func(thd) {}
+ Item_json_func(thd) {}
Item_func_json_array(THD *thd, List<Item> &list):
- Item_str_func(thd, list) {}
+ Item_json_func(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
bool fix_length_and_dec();
const char *func_name() const { return "json_array"; }
Item *get_copy(THD *thd)
@@ -273,7 +331,6 @@ public:
Item_func_json_object(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
const char *func_name() const { return "json_object"; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_object>(thd, this); }
@@ -288,7 +345,6 @@ public:
Item_func_json_merge(THD *thd, List<Item> &list):
Item_func_json_array(thd, list) {}
String *val_str(String *);
- bool is_json_type() { return true; }
const char *func_name() const { return "json_merge_preserve"; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_merge>(thd, this); }
@@ -439,7 +495,7 @@ public:
};
-class Item_func_json_format: public Item_str_func
+class Item_func_json_format: public Item_json_func
{
public:
enum formats
@@ -454,15 +510,14 @@ protected:
String tmp_js;
public:
Item_func_json_format(THD *thd, Item *js, formats format):
- Item_str_func(thd, js), fmt(format) {}
+ Item_json_func(thd, js), fmt(format) {}
Item_func_json_format(THD *thd, List<Item> &list):
- Item_str_func(thd, list), fmt(DETAILED) {}
+ Item_json_func(thd, list), fmt(DETAILED) {}
const char *func_name() const;
bool fix_length_and_dec();
String *val_str(String *str);
String *val_json(String *str);
- bool is_json_type() { return true; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_func_json_format>(thd, this); }
};
diff --git a/sql/item_row.h b/sql/item_row.h
index ea5a0f21d8b..28e6c09a873 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -60,7 +60,7 @@ public:
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return NULL; // Check with Vicentiu why it's called for Item_row
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 98da93ae699..234d36b36fe 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -4340,24 +4340,7 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
uint valpos= i * 2 + 1;
DYNAMIC_COLUMN_TYPE type= defs[i].type;
if (type == DYN_COL_NULL)
- switch (args[valpos]->field_type())
- {
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_GEOMETRY:
- type= DYN_COL_STRING;
- break;
- default:
- break;
- }
-
+ type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
if (type == DYN_COL_STRING &&
args[valpos]->type() == Item::FUNC_ITEM &&
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
@@ -4374,63 +4357,7 @@ bool Item_func_dyncol_create::prepare_arguments(THD *thd, bool force_names_arg)
uint valpos= i * 2 + 1;
DYNAMIC_COLUMN_TYPE type= defs[i].type;
if (type == DYN_COL_NULL) // auto detect
- {
- /*
- We don't have a default here to ensure we get a warning if
- one adds a new not handled MYSQL_TYPE_...
- */
- switch (args[valpos]->field_type()) {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- type= DYN_COL_DECIMAL;
- break;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_BIT:
- type= args[valpos]->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- type= DYN_COL_DOUBLE;
- break;
- case MYSQL_TYPE_NULL:
- type= DYN_COL_NULL;
- break;
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- type= DYN_COL_DATETIME;
- break;
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- type= DYN_COL_DATE;
- break;
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_TIME2:
- type= DYN_COL_TIME;
- break;
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_GEOMETRY:
- type= DYN_COL_STRING;
- break;
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- DBUG_ASSERT(0);
- }
- }
+ type= args[valpos]->type_handler()->dyncol_type(args[valpos]);
if (type == DYN_COL_STRING &&
args[valpos]->type() == Item::FUNC_ITEM &&
((Item_func *)args[valpos])->functype() == DYNCOL_FUNC)
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 3ed5a7036c3..676a815eb4e 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1796,8 +1796,8 @@ public:
TABLE *table;
Item_temptable_rowid(TABLE *table_arg);
const Type_handler *type_handler() const { return &type_handler_string; }
- Field *create_tmp_field(bool group, TABLE *table)
- { return create_table_field_from_handler(table); }
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
+ { return create_table_field_from_handler(root, table); }
String *val_str(String *str);
enum Functype functype() const { return TEMPTABLE_ROWID; }
const char *func_name() const { return "<rowid>"; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index dd1ffd20b47..de49a54b54a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -47,6 +47,8 @@ double get_post_group_estimate(JOIN* join, double join_op_rows);
LEX_CSTRING exists_outer_expr_name= { STRING_WITH_LEN("<exists outer expr>") };
+LEX_CSTRING no_matter_name= {STRING_WITH_LEN("<no matter>") };
+
int check_and_do_in_subquery_rewrites(JOIN *join);
Item_subselect::Item_subselect(THD *thd_arg):
@@ -1937,8 +1939,8 @@ Item_in_subselect::single_value_transformer(JOIN *join)
*/
expr= new (thd->mem_root) Item_direct_ref(thd, &select_lex->context,
(Item**)optimizer->get_cache(),
- "<no matter>",
- &in_left_expr_name);
+ no_matter_name,
+ in_left_expr_name);
}
DBUG_RETURN(false);
@@ -2169,8 +2171,8 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
this,
&select_lex->
ref_pointer_array[0],
- (char *)"<ref>",
- &field_name));
+ {STRING_WITH_LEN("<ref>")},
+ field_name));
if (!abort_on_null && left_expr->maybe_null)
{
/*
@@ -2251,8 +2253,8 @@ Item_in_subselect::create_single_in_to_exists_cond(JOIN *join,
&select_lex->context,
this,
&select_lex->ref_pointer_array[0],
- (char *)"<no matter>",
- &field_name));
+ no_matter_name,
+ field_name));
if (!abort_on_null && left_expr->maybe_null)
{
disable_cond_guard_for_const_null_left_expr(0);
@@ -2437,21 +2439,21 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
(*optimizer->get_cache())->
addr(i),
- (char *)"<no matter>",
- &in_left_expr_name),
+ no_matter_name,
+ in_left_expr_name),
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
Item *item_isnull=
new (thd->mem_root)
Item_func_isnull(thd,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
Item *col_item= new (thd->mem_root)
Item_cond_or(thd, item_eq, item_isnull);
if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
@@ -2471,8 +2473,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
if (!abort_on_null && left_expr->element_index(i)->maybe_null &&
get_cond_guard(i) )
{
@@ -2506,14 +2508,14 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
(*optimizer->get_cache())->
addr(i),
- (char *)"<no matter>",
- &in_left_expr_name),
+ no_matter_name,
+ in_left_expr_name),
new (thd->mem_root)
Item_direct_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
if (!abort_on_null && select_lex->ref_pointer_array[i]->maybe_null)
{
Item *having_col_item=
@@ -2522,8 +2524,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
new (thd->mem_root)
Item_ref(thd, &select_lex->context,
&select_lex->ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
item_isnull= new (thd->mem_root)
Item_func_isnull(thd,
@@ -2531,8 +2533,8 @@ Item_in_subselect::create_row_in_to_exists_cond(JOIN * join,
Item_direct_ref(thd, &select_lex->context,
&select_lex->
ref_pointer_array[i],
- (char *)"<no matter>",
- &list_ref));
+ no_matter_name,
+ list_ref));
item= new (thd->mem_root) Item_cond_or(thd, item, item_isnull);
if (left_expr->element_index(i)->maybe_null && get_cond_guard(i))
{
@@ -3082,8 +3084,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
in_subs->expr= new (thd->mem_root)
Item_direct_ref(thd, &first_select->context,
(Item**)optimizer->get_cache(),
- (char *)"<no matter>",
- &in_left_expr_name);
+ no_matter_name,
+ in_left_expr_name);
if (in_subs->fix_fields(thd, optimizer->arguments() + 1))
{
res= TRUE;
@@ -3153,8 +3155,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
Item_direct_ref(thd,
&unit->outer_select()->context,
optimizer->arguments(),
- (char *)"<no matter>",
- &exists_outer_expr_name)),
+ no_matter_name,
+ exists_outer_expr_name)),
optimizer) :
(Item *)optimizer);
}
@@ -3177,8 +3179,8 @@ bool Item_exists_subselect::exists2in_processor(void *opt_arg)
Item_direct_ref(thd,
&unit->outer_select()->context,
optimizer->arguments()[0]->addr((int)i),
- (char *)"<no matter>",
- &exists_outer_expr_name)),
+ no_matter_name,
+ exists_outer_expr_name)),
thd->mem_root);
}
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 287a17aad3a..87f3e1d3345 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1293,21 +1293,22 @@ void Item_sum_min_max::setup_hybrid(THD *thd, Item *item, Item *value_arg)
}
-Field *Item_sum_min_max::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_min_max::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
DBUG_ENTER("Item_sum_min_max::create_tmp_field");
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*) args[0])->field;
- if ((field= field->create_tmp_field(table->in_use->mem_root, table, true)))
+ if ((field= field->create_tmp_field(root, table, true)))
{
DBUG_ASSERT((field->flags & NOT_NULL_FLAG) == 0);
field->field_name= name;
}
DBUG_RETURN(field);
}
- DBUG_RETURN(tmp_table_field_from_field_type(table));
+ DBUG_RETURN(tmp_table_field_from_field_type(root, table));
}
/***********************************************************************
@@ -1997,7 +1998,7 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
-Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_avg::create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
{
if (group)
@@ -2007,7 +2008,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
The easiest way is to do this is to store both value in a string
and unpack on access.
*/
- Field *field= new (table->in_use->mem_root)
+ Field *field= new (root)
Field_string(((result_type() == DECIMAL_RESULT) ?
dec_bin_size : sizeof(double)) + sizeof(longlong),
0, &name, &my_charset_bin);
@@ -2015,7 +2016,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table)
field->init(table);
return field;
}
- return tmp_table_field_from_field_type(table);
+ return tmp_table_field_from_field_type(root, table);
}
@@ -2239,7 +2240,8 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
If we're grouping, then we need some space to serialize variables into, to
pass around.
*/
-Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_variance::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
Field *field;
if (group)
@@ -2249,11 +2251,12 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table)
The easiest way is to do this is to store both value in a string
and unpack on access.
*/
- field= new Field_string(Stddev::binary_size(), 0, &name, &my_charset_bin);
+ field= new (root) Field_string(Stddev::binary_size(), 0,
+ &name, &my_charset_bin);
}
else
- field= new Field_double(max_length, maybe_null, &name, decimals,
- TRUE);
+ field= new (root) Field_double(max_length, maybe_null, &name, decimals,
+ TRUE);
if (field != NULL)
field->init(table);
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 99cdf885c7c..16cc8d131b8 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -513,11 +513,11 @@ public:
}
virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
- virtual Field *create_tmp_field(bool group, TABLE *table);
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ virtual Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field(param->group(), table);
+ return create_tmp_field(root, param->group(), table);
}
virtual bool collect_outer_ref_processor(void *param);
bool init_sum_func_check(THD *thd);
@@ -753,7 +753,6 @@ public:
double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
- const Type_handler *type_handler() const { return &type_handler_longlong; }
bool fix_length_and_dec()
{ decimals=0; max_length=21; maybe_null=null_value=0; return FALSE; }
};
@@ -869,6 +868,7 @@ public:
count=count_arg;
Item_sum::make_const();
}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
longlong val_int();
void reset_field();
void update_field();
@@ -928,7 +928,7 @@ public:
return has_with_distinct() ? "avg(distinct " : "avg(";
}
Item *copy_or_same(THD* thd);
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void cleanup()
{
count= 0;
@@ -1013,7 +1013,7 @@ public:
const char *func_name() const
{ return sample ? "var_samp(" : "variance("; }
Item *copy_or_same(THD* thd);
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
const Type_handler *type_handler() const { return &type_handler_double; }
void cleanup()
{
@@ -1052,11 +1052,11 @@ class Item_sum_hybrid: public Item_sum,
public:
Item_sum_hybrid(THD *thd, Item *item_par):
Item_sum(thd, item_par),
- Type_handler_hybrid_field_type(&type_handler_longlong)
+ Type_handler_hybrid_field_type(&type_handler_slonglong)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item *a, Item *b):
Item_sum(thd, a, b),
- Type_handler_hybrid_field_type(&type_handler_longlong)
+ Type_handler_hybrid_field_type(&type_handler_slonglong)
{ collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
:Item_sum(thd, item),
@@ -1111,7 +1111,7 @@ public:
{
return get_arg(0)->real_type_handler();
}
- TYPELIB *get_typelib() const { return args[0]->get_typelib(); }
+ const TYPELIB *get_typelib() const { return args[0]->get_typelib(); }
void update_field();
void min_max_update_str_field();
void min_max_update_real_field();
@@ -1121,7 +1121,7 @@ public:
bool any_value() { return was_values; }
void no_rows_in_result();
void restore_to_before_no_rows_in_result();
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void setup_caches(THD *thd) { setup_hybrid(thd, arguments()[0], NULL); }
};
@@ -1175,6 +1175,7 @@ public:
longlong val_int();
void reset_field();
void update_field();
+ const Type_handler *type_handler() const { return &type_handler_ulonglong; }
bool fix_length_and_dec()
{
decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0;
@@ -1344,9 +1345,9 @@ public:
{
return SP_AGGREGATE_FUNC;
}
- Field *create_field_for_create_select(TABLE *table)
+ Field *create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
- return create_table_field_from_handler(table);
+ return create_table_field_from_handler(root, table);
}
bool fix_length_and_dec();
bool fix_fields(THD *thd, Item **ref);
@@ -1428,10 +1429,10 @@ public:
unsigned_flag= item->unsigned_flag;
}
table_map used_tables() const { return (table_map) 1L; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
bool check_vcol_func_processor(void *arg)
@@ -1644,7 +1645,11 @@ public:
{ DBUG_ASSERT(fixed == 1); return (double) Item_sum_udf_int::val_int(); }
String *val_str(String*str);
my_decimal *val_decimal(my_decimal *);
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ return unsigned_flag ? &type_handler_ulonglong :
+ &type_handler_slonglong;
+ }
bool fix_length_and_dec() { decimals=0; max_length=21; return FALSE; }
Item *copy_or_same(THD* thd);
Item *get_copy(THD *thd)
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index d3433963c25..0057ed45c7d 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -986,7 +986,7 @@ String* Item_func_monthname::val_str(String* str)
return (String *) 0;
month_name= locale->month_names->type_names[d.get_mysql_time()->month - 1];
- str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8_bin,
+ str->copy(month_name, (uint) strlen(month_name), &my_charset_utf8mb3_bin,
collation.collation, &err);
return str;
}
@@ -1130,7 +1130,7 @@ String* Item_func_dayname::val_str(String* str)
return (String*) 0;
day_name= locale->day_names->type_names[weekday];
- str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8_bin,
+ str->copy(day_name, (uint) strlen(day_name), &my_charset_utf8mb3_bin,
collation.collation, &err);
return str;
}
@@ -1920,7 +1920,10 @@ bool Item_func_from_unixtime::fix_length_and_dec()
THD *thd= current_thd;
thd->time_zone_used= 1;
tz= thd->variables.time_zone;
- fix_attributes_datetime_not_fixed_dec(args[0]->decimals);
+ Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH,
+ args[0]->decimals, false),
+ DTCollation_numeric());
maybe_null= true;
return FALSE;
}
@@ -2001,7 +2004,7 @@ bool Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- if (!args[0]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
@@ -2505,8 +2508,8 @@ bool Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- if (!args[0]->type_handler()->is_traditional_type() ||
- !args[1]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type() ||
+ !args[1]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
@@ -2916,8 +2919,8 @@ get_date_time_result_type(const char *format, uint length)
bool Item_func_str_to_date::fix_length_and_dec()
{
- if (!args[0]->type_handler()->is_traditional_type() ||
- !args[1]->type_handler()->is_traditional_type())
+ if (!args[0]->type_handler()->is_traditional_scalar_type() ||
+ !args[1]->type_handler()->is_traditional_scalar_type())
{
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION, MYF(0),
args[0]->type_handler()->name().ptr(),
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 987bd1c8595..9896499e172 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -170,7 +170,7 @@ class Item_func_month :public Item_func
{
public:
Item_func_month(THD *thd, Item *a): Item_func(thd, a)
- { collation.set_numeric(); }
+ { collation= DTCollation_numeric(); }
longlong val_int();
double val_real()
{ DBUG_ASSERT(fixed == 1); return (double) Item_func_month::val_int(); }
@@ -182,12 +182,16 @@ public:
str->set(nr, collation.collation);
return str;
}
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate)
{
return get_date_from_int(thd, ltime, fuzzydate);
}
const char *func_name() const { return "month"; }
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const { return &type_handler_slong; }
bool fix_length_and_dec()
{
decimals= 0;
@@ -442,7 +446,7 @@ class Item_func_weekday :public Item_func
bool odbc_type;
public:
Item_func_weekday(THD *thd, Item *a, bool type_arg):
- Item_func(thd, a), odbc_type(type_arg) { collation.set_numeric(); }
+ Item_func(thd, a), odbc_type(type_arg) { collation= DTCollation_numeric(); }
longlong val_int();
double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String *str)
@@ -451,6 +455,10 @@ public:
str->set(val_int(), &my_charset_bin);
return null_value ? 0 : str;
}
+ my_decimal *val_decimal(my_decimal *decimal_value)
+ {
+ return val_decimal_from_int(decimal_value);
+ }
const char *func_name() const
{
return (odbc_type ? "dayofweek" : "weekday");
@@ -459,7 +467,7 @@ public:
{
return type_handler()->Item_get_date_with_warn(thd, this, ltime, fuzzydate);
}
- const Type_handler *type_handler() const { return &type_handler_long; }
+ const Type_handler *type_handler() const { return &type_handler_slong; }
bool fix_length_and_dec()
{
decimals= 0;
@@ -972,8 +980,8 @@ class Item_extract :public Item_int_func,
uint32 threashold)
{
if (length >= threashold)
- return &type_handler_longlong;
- return &type_handler_long;
+ return &type_handler_slonglong;
+ return &type_handler_slong;
}
void set_date_length(uint32 length)
{
@@ -1004,7 +1012,7 @@ class Item_extract :public Item_int_func,
const interval_type int_type; // keep it public
Item_extract(THD *thd, interval_type type_arg, Item *a):
Item_int_func(thd, a),
- Type_handler_hybrid_field_type(&type_handler_longlong),
+ Type_handler_hybrid_field_type(&type_handler_slonglong),
m_date_mode(date_mode_t(0)),
int_type(type_arg)
{ }
@@ -1548,9 +1556,11 @@ public:
{
uint dec= MY_MAX(item->arguments()[0]->datetime_precision(current_thd),
interval_dec(item->arguments()[1], int_type(item)));
- item->collation.set(item->default_charset(),
- DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
- item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ item->Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false),
+ DTCollation(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII));
+ item->fix_char_length(item->max_length);
return false;
}
bool get_date(THD *thd, Item_handled_func *item,
@@ -1655,9 +1665,11 @@ public:
uint dec0= item->arguments()[0]->decimals;
uint dec1= Interval_DDhhmmssff::fsp(current_thd, item->arguments()[1]);
uint dec= MY_MAX(dec0, dec1);
- item->collation.set(item->default_charset(),
- DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII);
- item->fix_char_length_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
+ item->Type_std_attributes::set(
+ Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, dec, false),
+ DTCollation(item->default_charset(),
+ DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII));
+ item->fix_char_length(item->max_length);
return false;
}
bool get_date(THD *thd, Item_handled_func *item,
diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc
index 5ecb9510940..f20d20c81d6 100644
--- a/sql/item_windowfunc.cc
+++ b/sql/item_windowfunc.cc
@@ -463,7 +463,8 @@ bool Item_sum_hybrid_simple::get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t f
return retval;
}
-Field *Item_sum_hybrid_simple::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum_hybrid_simple::create_tmp_field(MEM_ROOT *root,
+ bool group, TABLE *table)
{
DBUG_ASSERT(0);
return NULL;
diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h
index 5b3aa4f0e41..8b53b2012e7 100644
--- a/sql/item_windowfunc.h
+++ b/sql/item_windowfunc.h
@@ -118,6 +118,8 @@ public:
Item_sum_row_number(THD *thd)
: Item_sum_int(thd), count(0) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
+
void clear()
{
count= 0;
@@ -179,6 +181,8 @@ public:
Item_sum_rank(THD *thd) : Item_sum_int(thd), peer_tracker(NULL) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
+
void clear()
{
/* This is called on partition start */
@@ -266,6 +270,7 @@ class Item_sum_dense_rank: public Item_sum_int
Item_sum_dense_rank(THD *thd)
: Item_sum_int(thd), dense_rank(0), first_add(true), peer_tracker(NULL) {}
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
enum Sumfunctype sum_func () const
{
return DENSE_RANK_FUNC;
@@ -318,7 +323,7 @@ class Item_sum_hybrid_simple : public Item_sum_hybrid
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
void update_field();
- Field *create_tmp_field(bool group, TABLE *table);
+ Field *create_tmp_field(MEM_ROOT *root, bool group, TABLE *table);
void clear()
{
value->clear();
@@ -690,7 +695,7 @@ class Item_sum_ntile : public Item_sum_window_with_row_count
void update_field() {}
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const { return &type_handler_slonglong; }
Item *get_copy(THD *thd)
{ return get_item_copy<Item_sum_ntile>(thd, this); }
@@ -705,7 +710,7 @@ class Item_sum_percentile_disc : public Item_sum_cume_dist,
{
public:
Item_sum_percentile_disc(THD *thd, Item* arg) : Item_sum_cume_dist(thd, arg),
- Type_handler_hybrid_field_type(&type_handler_longlong),
+ Type_handler_hybrid_field_type(&type_handler_slonglong),
value(NULL), val_calculated(FALSE), first_call(TRUE),
prev_value(0), order_item(NULL){}
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 60218c8ee74..d320b51879a 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -195,7 +195,7 @@ public:
{
return &type_handler_xpath_nodeset;
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
@@ -606,7 +606,7 @@ public:
{
return mark_unsupported_function(func_name(), arg, VCOL_IMPOSSIBLE);
}
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
diff --git a/sql/lex.h b/sql/lex.h
index ec657ff48df..c52e981f8b8 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -261,8 +261,6 @@ static SYMBOL symbols[] = {
{ "FUNCTION", SYM(FUNCTION_SYM)},
{ "GENERAL", SYM(GENERAL)},
{ "GENERATED", SYM(GENERATED_SYM)},
- { "GEOMETRY", SYM(GEOMETRY_SYM)},
- { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION)},
{ "GET_FORMAT", SYM(GET_FORMAT)},
{ "GET", SYM(GET_SYM)},
{ "GLOBAL", SYM(GLOBAL_SYM)},
@@ -343,7 +341,6 @@ static SYMBOL symbols[] = {
{ "LIMIT", SYM(LIMIT)},
{ "LINEAR", SYM(LINEAR_SYM)},
{ "LINES", SYM(LINES)},
- { "LINESTRING", SYM(LINESTRING)},
{ "LIST", SYM(LIST_SYM)},
{ "LOAD", SYM(LOAD)},
{ "LOCAL", SYM(LOCAL_SYM)},
@@ -409,9 +406,6 @@ static SYMBOL symbols[] = {
{ "MODIFIES", SYM(MODIFIES_SYM)},
{ "MODIFY", SYM(MODIFY_SYM)},
{ "MONTH", SYM(MONTH_SYM)},
- { "MULTILINESTRING", SYM(MULTILINESTRING)},
- { "MULTIPOINT", SYM(MULTIPOINT)},
- { "MULTIPOLYGON", SYM(MULTIPOLYGON)},
{ "MUTEX", SYM(MUTEX_SYM)},
{ "MYSQL", SYM(MYSQL_SYM)},
{ "MYSQL_ERRNO", SYM(MYSQL_ERRNO_SYM)},
@@ -476,8 +470,6 @@ static SYMBOL symbols[] = {
{ "PHASE", SYM(PHASE_SYM)},
{ "PLUGIN", SYM(PLUGIN_SYM)},
{ "PLUGINS", SYM(PLUGINS_SYM)},
- { "POINT", SYM(POINT_SYM)},
- { "POLYGON", SYM(POLYGON)},
{ "PORT", SYM(PORT_SYM)},
{ "PORTION", SYM(PORTION_SYM)},
{ "PRECEDES", SYM(PRECEDES_SYM)},
diff --git a/sql/lex_string.h b/sql/lex_string.h
index 88a7154b064..a62609c6b60 100644
--- a/sql/lex_string.h
+++ b/sql/lex_string.h
@@ -18,8 +18,46 @@
#ifndef LEX_STRING_INCLUDED
#define LEX_STRING_INCLUDED
+
typedef struct st_mysql_const_lex_string LEX_CSTRING;
+
+class Lex_cstring : public LEX_CSTRING
+{
+ public:
+ Lex_cstring()
+ {
+ str= NULL;
+ length= 0;
+ }
+ Lex_cstring(const char *_str, size_t _len)
+ {
+ str= _str;
+ length= _len;
+ }
+ Lex_cstring(const char *start, const char *end)
+ {
+ DBUG_ASSERT(start <= end);
+ str= start;
+ length= end - start;
+ }
+ void set(const char *_str, size_t _len)
+ {
+ str= _str;
+ length= _len;
+ }
+};
+
+
+class Lex_cstring_strlen: public Lex_cstring
+{
+public:
+ Lex_cstring_strlen(const char *from)
+ :Lex_cstring(from, from ? strlen(from) : 0)
+ { }
+};
+
+
/* Functions to compare if two lex strings are equal */
static inline bool lex_string_cmp(CHARSET_INFO *charset, const LEX_CSTRING *a,
diff --git a/sql/log.cc b/sql/log.cc
index 7f632b43cb6..78c1debcb4d 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1680,9 +1680,6 @@ binlog_trans_log_truncate(THD *thd, my_off_t pos)
int binlog_init(void *p)
{
binlog_hton= (handlerton *)p;
- binlog_hton->state= (WSREP_ON || opt_bin_log) ? SHOW_OPTION_YES
- : SHOW_OPTION_NO;
- binlog_hton->db_type=DB_TYPE_BINLOG;
binlog_hton->savepoint_offset= sizeof(my_off_t);
binlog_hton->close_connection= binlog_close_connection;
binlog_hton->savepoint_set= binlog_savepoint_set;
@@ -1691,8 +1688,11 @@ int binlog_init(void *p)
binlog_savepoint_rollback_can_release_mdl;
binlog_hton->commit= binlog_commit;
binlog_hton->rollback= binlog_rollback;
- binlog_hton->prepare= binlog_prepare;
- binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
+ if (WSREP_ON || opt_bin_log)
+ {
+ binlog_hton->prepare= binlog_prepare;
+ binlog_hton->start_consistent_snapshot= binlog_start_consistent_snapshot;
+ }
binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
return 0;
}
@@ -1723,7 +1723,6 @@ static int binlog_close_connection(handlerton *hton, THD *thd)
}
#endif /* WITH_WSREP */
DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty());
- thd_set_ha_data(thd, binlog_hton, NULL);
cache_mngr->~binlog_cache_mngr();
my_free(cache_mngr);
DBUG_RETURN(0);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 060c4592a74..351caa96446 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2000, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2000, 2018, Oracle and/or its affiliates.
Copyright (c) 2009, 2019, MariaDB
This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,6 @@
#include "transaction.h"
#include <my_dir.h>
#include "sql_show.h" // append_identifier
-#include "debug_sync.h" // debug_sync
#include <mysql/psi/mysql_statement.h>
#include <strfunc.h>
#include "compat56.h"
@@ -80,9 +79,6 @@ TYPELIB binlog_checksum_typelib=
};
-
-#define log_cs &my_charset_latin1
-
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
/*
@@ -107,179 +103,6 @@ const Version checksum_version_split_mariadb(5, 3, 0);
// First MySQL version with fraction seconds
const Version fsp_version_split_mysql(5, 6, 0);
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD* thd);
-
-static const char *HA_ERR(int i)
-{
- /*
- This function should only be called in case of an error
- was detected
- */
- DBUG_ASSERT(i != 0);
- switch (i) {
- case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND";
- case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY";
- case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED";
- case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX";
- case HA_ERR_CRASHED: return "HA_ERR_CRASHED";
- case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD";
- case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM";
- case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE";
- case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND";
- case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE";
- case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD";
- case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED";
- case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL";
- case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL";
- case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE";
- case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED";
- case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW";
- case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION";
- case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE";
- case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET";
- case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF";
- case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR";
- case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE";
- case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT";
- case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL";
- case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION";
- case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK";
- case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN";
- case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW";
- case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED";
- case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT";
- case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE";
- case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE";
- case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST";
- case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION";
- case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL";
- case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED";
- case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND";
- case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED";
- case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK";
- case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY";
- case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE";
- case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY";
- case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED";
- case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE";
- case HA_ERR_GENERIC: return "HA_ERR_GENERIC";
- case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
- case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
- case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
- case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
- }
- return "No Error!";
-}
-
-
-/*
- Return true if an error caught during event execution is a temporary error
- that will cause automatic retry of the event group during parallel
- replication, false otherwise.
-
- In parallel replication, conflicting transactions can occasionally cause
- deadlocks; such errors are handled automatically by rolling back re-trying
- the transactions, so should not pollute the error log.
-*/
-static bool
-is_parallel_retry_error(rpl_group_info *rgi, int err)
-{
- if (!rgi->is_parallel_exec)
- return false;
- if (rgi->speculation == rpl_group_info::SPECULATE_OPTIMISTIC)
- return true;
- if (rgi->killed_for_retry &&
- (err == ER_QUERY_INTERRUPTED || err == ER_CONNECTION_KILLED))
- return true;
- return has_temporary_error(rgi->thd);
-}
-
-
-/**
- Error reporting facility for Rows_log_event::do_apply_event
-
- @param level error, warning or info
- @param ha_error HA_ERR_ code
- @param rli pointer to the active Relay_log_info instance
- @param thd pointer to the slave thread's thd
- @param table pointer to the event's table object
- @param type the type of the event
- @param log_name the master binlog file name
- @param pos the master binlog file pos (the next after the event)
-
-*/
-static void inline slave_rows_error_report(enum loglevel level, int ha_error,
- rpl_group_info *rgi, THD *thd,
- TABLE *table, const char * type,
- const char *log_name, my_off_t pos)
-{
- const char *handler_error= (ha_error ? HA_ERR(ha_error) : NULL);
- char buff[MAX_SLAVE_ERRMSG], *slider;
- const char *buff_end= buff + sizeof(buff);
- size_t len;
- Diagnostics_area::Sql_condition_iterator it=
- thd->get_stmt_da()->sql_conditions();
- Relay_log_info const *rli= rgi->rli;
- const Sql_condition *err;
- buff[0]= 0;
- int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
-
- /*
- In parallel replication, deadlocks or other temporary errors can happen
- occasionally in normal operation, they will be handled correctly and
- automatically by re-trying the transactions. So do not pollute the error
- log with messages about them.
- */
- if (is_parallel_retry_error(rgi, errcode))
- return;
-
- for (err= it++, slider= buff; err && slider < buff_end - 1;
- slider += len, err= it++)
- {
- len= my_snprintf(slider, buff_end - slider,
- " %s, Error_code: %d;", err->get_message_text(),
- err->get_sql_errno());
- }
-
- if (ha_error != 0)
- rli->report(level, errcode, rgi->gtid_info(),
- "Could not execute %s event on table %s.%s;"
- "%s handler error %s; "
- "the event's master log %s, end_log_pos %llu",
- type, table->s->db.str, table->s->table_name.str,
- buff, handler_error == NULL ? "<unknown>" : handler_error,
- log_name, pos);
- else
- rli->report(level, errcode, rgi->gtid_info(),
- "Could not execute %s event on table %s.%s;"
- "%s the event's master log %s, end_log_pos %llu",
- type, table->s->db.str, table->s->table_name.str,
- buff, log_name, pos);
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static void set_thd_db(THD *thd, Rpl_filter *rpl_filter,
- const char *db, uint32 db_len)
-{
- char lcase_db_buf[NAME_LEN +1];
- LEX_CSTRING new_db;
- new_db.length= db_len;
- if (lower_case_table_names == 1)
- {
- strmov(lcase_db_buf, db);
- my_casedn_str(system_charset_info, lcase_db_buf);
- new_db.str= lcase_db_buf;
- }
- else
- new_db.str= db;
- /* TODO WARNING this makes rewrite_db respect lower_case_table_names values
- * for more info look MDEV-17446 */
- new_db.str= rpl_filter->get_rewrite_db(new_db.str, &new_db.length);
- thd->set_db(&new_db);
-}
-#endif
/*
Cache that will automatically be written to a dedicated file on
destruction.
@@ -292,7 +115,7 @@ class Write_on_release_cache
public:
enum flag
{
- FLUSH_F= 1
+ FLUSH_F
};
typedef unsigned short flag_set;
@@ -383,187 +206,6 @@ private:
Log_event *m_ev; // Used for Flashback
};
-/*
- pretty_print_str()
-*/
-
-#ifdef MYSQL_CLIENT
-static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
-{
- const char* end = str + len;
- if (my_b_write_byte(cache, '\''))
- goto err;
-
- while (str < end)
- {
- char c;
- int error;
-
- switch ((c=*str++)) {
- case '\n': error= my_b_write(cache, (uchar*)"\\n", 2); break;
- case '\r': error= my_b_write(cache, (uchar*)"\\r", 2); break;
- case '\\': error= my_b_write(cache, (uchar*)"\\\\", 2); break;
- case '\b': error= my_b_write(cache, (uchar*)"\\b", 2); break;
- case '\t': error= my_b_write(cache, (uchar*)"\\t", 2); break;
- case '\'': error= my_b_write(cache, (uchar*)"\\'", 2); break;
- case 0 : error= my_b_write(cache, (uchar*)"\\0", 2); break;
- default:
- error= my_b_write_byte(cache, c);
- break;
- }
- if (unlikely(error))
- goto err;
- }
- return my_b_write_byte(cache, '\'');
-
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-inline int idempotent_error_code(int err_code)
-{
- int ret= 0;
-
- switch (err_code)
- {
- case 0:
- ret= 1;
- break;
- /*
- The following list of "idempotent" errors
- means that an error from the list might happen
- because of idempotent (more than once)
- applying of a binlog file.
- Notice, that binlog has a ddl operation its
- second applying may cause
-
- case HA_ERR_TABLE_DEF_CHANGED:
- case HA_ERR_CANNOT_ADD_FOREIGN:
-
- which are not included into to the list.
-
- Note that HA_ERR_RECORD_DELETED is not in the list since
- do_exec_row() should not return that error code.
- */
- case HA_ERR_RECORD_CHANGED:
- case HA_ERR_KEY_NOT_FOUND:
- case HA_ERR_END_OF_FILE:
- case HA_ERR_FOUND_DUPP_KEY:
- case HA_ERR_FOUND_DUPP_UNIQUE:
- case HA_ERR_FOREIGN_DUPLICATE_KEY:
- case HA_ERR_NO_REFERENCED_ROW:
- case HA_ERR_ROW_IS_REFERENCED:
- ret= 1;
- break;
- default:
- ret= 0;
- break;
- }
- return (ret);
-}
-
-/**
- Ignore error code specified on command line.
-*/
-
-inline int ignored_error_code(int err_code)
-{
- if (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code))
- {
- statistic_increment(slave_skipped_errors, LOCK_status);
- return 1;
- }
- return err_code == ER_SLAVE_IGNORED_TABLE;
-}
-
-/*
- This function converts an engine's error to a server error.
-
- If the thread does not have an error already reported, it tries to
- define it by calling the engine's method print_error. However, if a
- mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
- warning message.
-*/
-int convert_handler_error(int error, THD* thd, TABLE *table)
-{
- uint actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
- 0);
-
- if (actual_error == 0)
- {
- table->file->print_error(error, MYF(0));
- actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
- ER_UNKNOWN_ERROR);
- if (actual_error == ER_UNKNOWN_ERROR)
- if (global_system_variables.log_warnings)
- sql_print_warning("Unknown error detected %d in handler", error);
- }
-
- return (actual_error);
-}
-
-inline bool concurrency_error_code(int error)
-{
- switch (error)
- {
- case ER_LOCK_WAIT_TIMEOUT:
- case ER_LOCK_DEADLOCK:
- case ER_XA_RBDEADLOCK:
- return TRUE;
- default:
- return (FALSE);
- }
-}
-
-inline bool unexpected_error_code(int unexpected_error)
-{
- switch (unexpected_error)
- {
- case ER_NET_READ_ERROR:
- case ER_NET_ERROR_ON_WRITE:
- case ER_QUERY_INTERRUPTED:
- case ER_STATEMENT_TIMEOUT:
- case ER_CONNECTION_KILLED:
- case ER_SERVER_SHUTDOWN:
- case ER_NEW_ABORTING_CONNECTION:
- return(TRUE);
- default:
- return(FALSE);
- }
-}
-
-/*
- pretty_print_str()
-*/
-
-static void
-pretty_print_str(String *packet, const char *str, int len)
-{
- const char *end= str + len;
- packet->append(STRING_WITH_LEN("'"));
- while (str < end)
- {
- char c;
- switch ((c=*str++)) {
- case '\n': packet->append(STRING_WITH_LEN("\\n")); break;
- case '\r': packet->append(STRING_WITH_LEN("\\r")); break;
- case '\\': packet->append(STRING_WITH_LEN("\\\\")); break;
- case '\b': packet->append(STRING_WITH_LEN("\\b")); break;
- case '\t': packet->append(STRING_WITH_LEN("\\t")); break;
- case '\'': packet->append(STRING_WITH_LEN("\\'")); break;
- case 0 : packet->append(STRING_WITH_LEN("\\0")); break;
- default:
- packet->append(&c, 1);
- break;
- }
- }
- packet->append(STRING_WITH_LEN("'"));
-}
-#endif /* !MYSQL_CLIENT */
-
#ifndef DBUG_OFF
#define DBUG_DUMP_EVENT_BUF(B,L) \
do { \
@@ -587,131 +229,6 @@ pretty_print_str(String *packet, const char *str, int len)
#define DBUG_DUMP_EVENT_BUF(B,L) do { } while(0)
#endif
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Create a prefix for the temporary files that is to be used for
- load data file name for this master
-
- @param name Store prefix of name here
- @param connection_name Connection name
-
- @return pointer to end of name
-
- @description
- We assume that FN_REFLEN is big enough to hold
- MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH characters + 2 numbers +
- a short extension.
-
- The resulting file name has the following parts, each separated with a '-'
- - PREFIX_SQL_LOAD (SQL_LOAD-)
- - If a connection name is given (multi-master setup):
- - Add an extra '-' to mark that this is a multi-master file
- - connection name in lower case, converted to safe file characters.
- (see create_logfile_name_with_suffix()).
- - server_id
- - A last '-' (after server_id).
-*/
-
-static char *load_data_tmp_prefix(char *name,
- LEX_CSTRING *connection_name)
-{
- name= strmov(name, PREFIX_SQL_LOAD);
- if (connection_name->length)
- {
- uint buf_length;
- uint errors;
- /* Add marker that this is a multi-master-file */
- *name++='-';
- /* Convert connection_name to a safe filename */
- buf_length= strconvert(system_charset_info, connection_name->str, FN_REFLEN,
- &my_charset_filename, name, FN_REFLEN, &errors);
- name+= buf_length;
- *name++= '-';
- }
- name= int10_to_str(global_system_variables.server_id, name, 10);
- *name++ = '-';
- *name= '\0'; // For testing prefixes
- return name;
-}
-
-
-/**
- Creates a temporary name for LOAD DATA INFILE
-
- @param buf Store new filename here
- @param file_id File_id (part of file name)
- @param event_server_id Event_id (part of file name)
- @param ext Extension for file name
-
- @return
- Pointer to start of extension
-*/
-
-static char *slave_load_file_stem(char *buf, uint file_id,
- int event_server_id, const char *ext,
- LEX_CSTRING *connection_name)
-{
- char *res;
- res= buf+ unpack_dirname(buf, slave_load_tmpdir);
- to_unix_path(buf);
- buf= load_data_tmp_prefix(res, connection_name);
- buf= int10_to_str(event_server_id, buf, 10);
- *buf++ = '-';
- res= int10_to_str(file_id, buf, 10);
- strmov(res, ext); // Add extension last
- return res; // Pointer to extension
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Delete all temporary files used for SQL_LOAD.
-*/
-
-static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
-{
- MY_DIR *dirp;
- FILEINFO *file;
- uint i;
- char dir[FN_REFLEN], fname[FN_REFLEN];
- char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1];
- DBUG_ENTER("cleanup_load_tmpdir");
-
- unpack_dirname(dir, slave_load_tmpdir);
- if (!(dirp=my_dir(dir, MYF(MY_WME))))
- return;
-
- /*
- When we are deleting temporary files, we should only remove
- the files associated with the server id of our server.
- We don't use event_server_id here because since we've disabled
- direct binlogging of Create_file/Append_file/Exec_load events
- we cannot meet Start_log event in the middle of events from one
- LOAD DATA.
- */
-
- load_data_tmp_prefix(prefbuf, connection_name);
- DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf));
-
- for (i=0 ; i < (uint)dirp->number_of_files; i++)
- {
- file=dirp->dir_entry+i;
- if (is_prefix(file->name, prefbuf))
- {
- fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
- mysql_file_delete(key_file_misc, fname, MYF(0));
- }
- }
-
- my_dirend(dirp);
- DBUG_VOID_RETURN;
-}
-#endif
-
-
/*
read_str()
*/
@@ -1121,80 +638,6 @@ int binlog_buf_uncompress(const char *src, char *dst, uint32 len,
return 0;
}
-#ifndef MYSQL_CLIENT
-
-/**
- Append a version of the 'str' string suitable for use in a query to
- the 'to' string. To generate a correct escaping, the character set
- information in 'csinfo' is used.
-*/
-
-int append_query_string(CHARSET_INFO *csinfo, String *to,
- const char *str, size_t len, bool no_backslash)
-{
- char *beg, *ptr;
- uint32 const orig_len= to->length();
- if (to->reserve(orig_len + len * 2 + 4))
- return 1;
-
- beg= (char*) to->ptr() + to->length();
- ptr= beg;
- if (csinfo->escape_with_backslash_is_dangerous)
- ptr= str_to_hex(ptr, str, len);
- else
- {
- *ptr++= '\'';
- if (!no_backslash)
- {
- ptr+= escape_string_for_mysql(csinfo, ptr, 0, str, len);
- }
- else
- {
- const char *frm_str= str;
-
- for (; frm_str < (str + len); frm_str++)
- {
- /* Using '' way to represent "'" */
- if (*frm_str == '\'')
- *ptr++= *frm_str;
-
- *ptr++= *frm_str;
- }
- }
-
- *ptr++= '\'';
- }
- to->length((uint32)(orig_len + ptr - beg));
- return 0;
-}
-#endif
-
-
-/**
- Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
- commands just before it prints a query.
-*/
-
-#ifdef MYSQL_CLIENT
-
-static bool print_set_option(IO_CACHE* file, uint32 bits_changed,
- uint32 option, uint32 flags, const char* name,
- bool* need_comma)
-{
- if (bits_changed & option)
- {
- if (*need_comma)
- if (my_b_write(file, (uchar*)", ", 2))
- goto err;
- if (my_b_printf(file, "%s=%d", name, MY_TEST(flags & option)))
- goto err;
- *need_comma= 1;
- }
- return 0;
-err:
- return 1;
-}
-#endif
/**************************************************************************
Log_event methods (= the parent class of all events)
@@ -1275,51 +718,6 @@ const char* Log_event::get_type_str()
Log_event::Log_event()
*/
-#ifndef MYSQL_CLIENT
-Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
- :log_pos(0), temp_buf(0), exec_time(0), thd(thd_arg),
- checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
-{
- server_id= thd->variables.server_id;
- when= thd->start_time;
- when_sec_part=thd->start_time_sec_part;
-
- if (using_trans)
- cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
- else
- cache_type= Log_event::EVENT_STMT_CACHE;
- flags= flags_arg |
- (thd->variables.option_bits & OPTION_SKIP_REPLICATION ?
- LOG_EVENT_SKIP_REPLICATION_F : 0);
-}
-
-/**
- This minimal constructor is for when you are not even sure that there
- is a valid THD. For example in the server when we are shutting down or
- flushing logs after receiving a SIGHUP (then we must write a Rotate to
- the binlog but we have no THD, so we need this minimal constructor).
-*/
-
-Log_event::Log_event()
- :temp_buf(0), exec_time(0), flags(0), cache_type(EVENT_INVALID_CACHE),
- thd(0), checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
-{
- server_id= global_system_variables.server_id;
- /*
- We can't call my_time() here as this would cause a call before
- my_init() is called
- */
- when= 0;
- when_sec_part=0;
- log_pos= 0;
-}
-#endif /* !MYSQL_CLIENT */
-
-
-/*
- Log_event::Log_event()
-*/
-
Log_event::Log_event(const char* buf,
const Format_description_log_event* description_event)
:temp_buf(0), exec_time(0), cache_type(Log_event::EVENT_INVALID_CACHE),
@@ -1390,395 +788,6 @@ Log_event::Log_event(const char* buf,
/* otherwise, go on with reading the header from buf (nothing now) */
}
-#ifndef MYSQL_CLIENT
-#ifdef HAVE_REPLICATION
-
-int Log_event::do_update_pos(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Log_event::do_update_pos");
-
- DBUG_ASSERT(!rli->belongs_to_client());
- /*
- rli is null when (as far as I (Guilhem) know) the caller is
- Load_log_event::do_apply_event *and* that one is called from
- Execute_load_log_event::do_apply_event. In this case, we don't
- do anything here ; Execute_load_log_event::do_apply_event will
- call Log_event::do_apply_event again later with the proper rli.
- Strictly speaking, if we were sure that rli is null only in the
- case discussed above, 'if (rli)' is useless here. But as we are
- not 100% sure, keep it for now.
-
- Matz: I don't think we will need this check with this refactoring.
- */
- if (rli)
- {
- /*
- In parallel execution, delay position update for the events that are
- not part of event groups (format description, rotate, and such) until
- the actual event execution reaches that point.
- */
- if (!rgi->is_parallel_exec || is_group_event(get_type_code()))
- rli->stmt_done(log_pos, thd, rgi);
- }
- DBUG_RETURN(0); // Cannot fail currently
-}
-
-
-Log_event::enum_skip_reason
-Log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_PRINT("info", ("ev->server_id: %lu, ::server_id: %lu,"
- " rli->replicate_same_server_id: %d,"
- " rli->slave_skip_counter: %llu",
- (ulong) server_id,
- (ulong) global_system_variables.server_id,
- rli->replicate_same_server_id,
- rli->slave_skip_counter));
- if ((server_id == global_system_variables.server_id &&
- !rli->replicate_same_server_id) ||
- (rli->slave_skip_counter == 1 && rli->is_in_group()) ||
- (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
- return EVENT_SKIP_IGNORE;
- if (rli->slave_skip_counter > 0)
- return EVENT_SKIP_COUNT;
- return EVENT_SKIP_NOT;
-}
-
-
-/*
- Log_event::pack_info()
-*/
-
-void Log_event::pack_info(Protocol *protocol)
-{
- protocol->store("", &my_charset_bin);
-}
-
-
-/**
- Only called by SHOW BINLOG EVENTS
-*/
-int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
-{
- const char *p= strrchr(log_name, FN_LIBCHAR);
- const char *event_type;
- if (p)
- log_name = p + 1;
-
- protocol->prepare_for_resend();
- protocol->store(log_name, &my_charset_bin);
- protocol->store((ulonglong) pos);
- event_type = get_type_str();
- protocol->store(event_type, strlen(event_type), &my_charset_bin);
- protocol->store((uint32) server_id);
- protocol->store((ulonglong) log_pos);
- pack_info(protocol);
- return protocol->write();
-}
-#endif /* HAVE_REPLICATION */
-
-
-/**
- init_show_field_list() prepares the column names and types for the
- output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
- EVENTS.
-*/
-
-void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
-{
- MEM_ROOT *mem_root= thd->mem_root;
- field_list->push_back(new (mem_root)
- Item_empty_string(thd, "Log_name", 20),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "Pos",
- MY_INT64_NUM_DECIMAL_DIGITS,
- MYSQL_TYPE_LONGLONG),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_empty_string(thd, "Event_type", 20),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "Server_id", 10,
- MYSQL_TYPE_LONG),
- mem_root);
- field_list->push_back(new (mem_root)
- Item_return_int(thd, "End_log_pos",
- MY_INT64_NUM_DECIMAL_DIGITS,
- MYSQL_TYPE_LONGLONG),
- mem_root);
- field_list->push_back(new (mem_root) Item_empty_string(thd, "Info", 20),
- mem_root);
-}
-
-/**
- A decider of whether to trigger checksum computation or not.
- To be invoked in Log_event::write() stack.
- The decision is positive
-
- S,M) if it's been marked for checksumming with @c checksum_alg
-
- M) otherwise, if @@global.binlog_checksum is not NONE and the event is
- directly written to the binlog file.
- The to-be-cached event decides at @c write_cache() time.
-
- Otherwise the decision is negative.
-
- @note A side effect of the method is altering Log_event::checksum_alg
- it the latter was undefined at calling.
-
- @return true (positive) or false (negative)
-*/
-my_bool Log_event::need_checksum()
-{
- DBUG_ENTER("Log_event::need_checksum");
- my_bool ret;
- /*
- few callers of Log_event::write
- (incl FD::write, FD constructing code on the slave side, Rotate relay log
- and Stop event)
- provides their checksum alg preference through Log_event::checksum_alg.
- */
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
- ret= checksum_alg != BINLOG_CHECKSUM_ALG_OFF;
- else
- {
- ret= binlog_checksum_options && cache_type == Log_event::EVENT_NO_CACHE;
- checksum_alg= ret ? (enum_binlog_checksum_alg)binlog_checksum_options
- : BINLOG_CHECKSUM_ALG_OFF;
- }
- /*
- FD calls the methods before data_written has been calculated.
- The following invariant claims if the current is not the first
- call (and therefore data_written is not zero) then `ret' must be
- TRUE. It may not be null because FD is always checksummed.
- */
-
- DBUG_ASSERT(get_type_code() != FORMAT_DESCRIPTION_EVENT || ret ||
- data_written == 0);
-
- DBUG_ASSERT(!ret ||
- ((checksum_alg == binlog_checksum_options ||
- /*
- Stop event closes the relay-log and its checksum alg
- preference is set by the caller can be different
- from the server's binlog_checksum_options.
- */
- get_type_code() == STOP_EVENT ||
- /*
- Rotate:s can be checksummed regardless of the server's
- binlog_checksum_options. That applies to both
- the local RL's Rotate and the master's Rotate
- which IO thread instantiates via queue_binlog_ver_3_event.
- */
- get_type_code() == ROTATE_EVENT ||
- get_type_code() == START_ENCRYPTION_EVENT ||
- /* FD is always checksummed */
- get_type_code() == FORMAT_DESCRIPTION_EVENT) &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF));
-
- DBUG_ASSERT(checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
-
- DBUG_ASSERT(((get_type_code() != ROTATE_EVENT &&
- get_type_code() != STOP_EVENT) ||
- get_type_code() != FORMAT_DESCRIPTION_EVENT) ||
- cache_type == Log_event::EVENT_NO_CACHE);
-
- DBUG_RETURN(ret);
-}
-
-int Log_event_writer::write_internal(const uchar *pos, size_t len)
-{
- if (my_b_safe_write(file, pos, len))
- return 1;
- bytes_written+= len;
- return 0;
-}
-
-/*
- as soon as encryption produces the first output block, write event_len
- where it should be in a valid event header
-*/
-int Log_event_writer::maybe_write_event_len(uchar *pos, size_t len)
-{
- if (len && event_len)
- {
- DBUG_ASSERT(len >= EVENT_LEN_OFFSET);
- if (write_internal(pos + EVENT_LEN_OFFSET - 4, 4))
- return 1;
- int4store(pos + EVENT_LEN_OFFSET - 4, event_len);
- event_len= 0;
- }
- return 0;
-}
-
-int Log_event_writer::encrypt_and_write(const uchar *pos, size_t len)
-{
- uchar *dst= 0;
- size_t dstsize= 0;
-
- if (ctx)
- {
- dstsize= encryption_encrypted_length((uint)len, ENCRYPTION_KEY_SYSTEM_DATA,
- crypto->key_version);
- if (!(dst= (uchar*)my_safe_alloca(dstsize)))
- return 1;
-
- uint dstlen;
- if (len == 0)
- dstlen= 0;
- else if (encryption_ctx_update(ctx, pos, (uint)len, dst, &dstlen))
- goto err;
-
- if (maybe_write_event_len(dst, dstlen))
- return 1;
- pos= dst;
- len= dstlen;
- }
- if (write_internal(pos, len))
- goto err;
-
- my_safe_afree(dst, dstsize);
- return 0;
-err:
- my_safe_afree(dst, dstsize);
- return 1;
-}
-
-int Log_event_writer::write_header(uchar *pos, size_t len)
-{
- DBUG_ENTER("Log_event_writer::write_header");
- /*
- recording checksum of FD event computed with dropped
- possibly active LOG_EVENT_BINLOG_IN_USE_F flag.
- Similar step at verication: the active flag is dropped before
- checksum computing.
- */
- if (checksum_len)
- {
- uchar save=pos[FLAGS_OFFSET];
- pos[FLAGS_OFFSET]&= ~LOG_EVENT_BINLOG_IN_USE_F;
- crc= my_checksum(0, pos, len);
- pos[FLAGS_OFFSET]= save;
- }
-
- if (ctx)
- {
- uchar iv[BINLOG_IV_LENGTH];
- crypto->set_iv(iv, (uint32)my_b_safe_tell(file));
- if (encryption_ctx_init(ctx, crypto->key, crypto->key_length,
- iv, sizeof(iv), ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
- ENCRYPTION_KEY_SYSTEM_DATA, crypto->key_version))
- DBUG_RETURN(1);
-
- DBUG_ASSERT(len >= LOG_EVENT_HEADER_LEN);
- event_len= uint4korr(pos + EVENT_LEN_OFFSET);
- DBUG_ASSERT(event_len >= len);
- memcpy(pos + EVENT_LEN_OFFSET, pos, 4);
- pos+= 4;
- len-= 4;
- }
- DBUG_RETURN(encrypt_and_write(pos, len));
-}
-
-int Log_event_writer::write_data(const uchar *pos, size_t len)
-{
- DBUG_ENTER("Log_event_writer::write_data");
- if (checksum_len)
- crc= my_checksum(crc, pos, len);
-
- DBUG_RETURN(encrypt_and_write(pos, len));
-}
-
-int Log_event_writer::write_footer()
-{
- DBUG_ENTER("Log_event_writer::write_footer");
- if (checksum_len)
- {
- uchar checksum_buf[BINLOG_CHECKSUM_LEN];
- int4store(checksum_buf, crc);
- if (encrypt_and_write(checksum_buf, BINLOG_CHECKSUM_LEN))
- DBUG_RETURN(ER_ERROR_ON_WRITE);
- }
- if (ctx)
- {
- uint dstlen;
- uchar dst[MY_AES_BLOCK_SIZE*2];
- if (encryption_ctx_finish(ctx, dst, &dstlen))
- DBUG_RETURN(1);
- if (maybe_write_event_len(dst, dstlen) || write_internal(dst, dstlen))
- DBUG_RETURN(ER_ERROR_ON_WRITE);
- }
- DBUG_RETURN(0);
-}
-
-/*
- Log_event::write_header()
-*/
-
-bool Log_event::write_header(size_t event_data_length)
-{
- uchar header[LOG_EVENT_HEADER_LEN];
- ulong now;
- DBUG_ENTER("Log_event::write_header");
- DBUG_PRINT("enter", ("filepos: %lld length: %zu type: %d",
- (longlong) writer->pos(), event_data_length,
- (int) get_type_code()));
-
- writer->checksum_len= need_checksum() ? BINLOG_CHECKSUM_LEN : 0;
-
- /* Store number of bytes that will be written by this event */
- data_written= event_data_length + sizeof(header) + writer->checksum_len;
-
- /*
- log_pos != 0 if this is relay-log event. In this case we should not
- change the position
- */
-
- if (is_artificial_event())
- {
- /*
- Artificial events are automatically generated and do not exist
- in master's binary log, so log_pos should be set to 0.
- */
- log_pos= 0;
- }
- else if (!log_pos)
- {
- /*
- Calculate the position of where the next event will start
- (end of this event, that is).
- */
-
- log_pos= writer->pos() + data_written;
-
- DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31););
- }
-
- now= get_time(); // Query start time
-
- /*
- Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
- FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT, where it will be
- LOG_EVENT_MINIMAL_HEADER_LEN (remember these 2 have a frozen header,
- because we read them before knowing the format).
- */
-
- int4store(header, now); // timestamp
- header[EVENT_TYPE_OFFSET]= get_type_code();
- int4store(header+ SERVER_ID_OFFSET, server_id);
- int4store(header+ EVENT_LEN_OFFSET, data_written);
- int4store(header+ LOG_POS_OFFSET, log_pos);
- int2store(header + FLAGS_OFFSET, flags);
-
- bool ret= writer->write_header(header, sizeof(header));
- DBUG_RETURN(ret);
-}
-
-#endif /* !MYSQL_CLIENT */
/**
This needn't be format-tolerant, because we only parse the first
@@ -2291,2197 +1300,6 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
DBUG_RETURN(ev);
}
-#ifdef MYSQL_CLIENT
-
-static bool hexdump_minimal_header_to_io_cache(IO_CACHE *file,
- my_off_t offset,
- uchar *ptr)
-{
- DBUG_ASSERT(LOG_EVENT_MINIMAL_HEADER_LEN == 19);
-
- /*
- Pretty-print the first LOG_EVENT_MINIMAL_HEADER_LEN (19) bytes of the
- common header, which contains the basic information about the log event.
- Every event will have at least this much header, but events could contain
- more headers (which must be printed by other methods, if desired).
- */
- char emit_buf[120]; // Enough for storing one line
- size_t emit_buf_written;
-
- if (my_b_printf(file,
- "# "
- "|Timestamp "
- "|Type "
- "|Master ID "
- "|Size "
- "|Master Pos "
- "|Flags\n"))
- goto err;
- emit_buf_written=
- my_snprintf(emit_buf, sizeof(emit_buf),
- "# %8llx " /* Position */
- "|%02x %02x %02x %02x " /* Timestamp */
- "|%02x " /* Type */
- "|%02x %02x %02x %02x " /* Master ID */
- "|%02x %02x %02x %02x " /* Size */
- "|%02x %02x %02x %02x " /* Master Pos */
- "|%02x %02x\n", /* Flags */
- (ulonglong) offset, /* Position */
- ptr[0], ptr[1], ptr[2], ptr[3], /* Timestamp */
- ptr[4], /* Type */
- ptr[5], ptr[6], ptr[7], ptr[8], /* Master ID */
- ptr[9], ptr[10], ptr[11], ptr[12], /* Size */
- ptr[13], ptr[14], ptr[15], ptr[16], /* Master Pos */
- ptr[17], ptr[18]); /* Flags */
-
- DBUG_ASSERT(static_cast<size_t>(emit_buf_written) < sizeof(emit_buf));
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written) ||
- my_b_write(file, (uchar*)"#\n", 2))
- goto err;
-
- return 0;
-err:
- return 1;
-}
-
-
-/*
- The number of bytes to print per line. Should be an even number,
- and "hexdump -C" uses 16, so we'll duplicate that here.
-*/
-#define HEXDUMP_BYTES_PER_LINE 16
-
-static void format_hex_line(char *emit_buff)
-{
- memset(emit_buff + 1, ' ',
- 1 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE);
- emit_buff[0]= '#';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 1]= '|';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE]= '|';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 1]= '\n';
- emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 2]= '\0';
-}
-
-static bool hexdump_data_to_io_cache(IO_CACHE *file,
- my_off_t offset,
- uchar *ptr,
- my_off_t size)
-{
- /*
- 2 = '# '
- 8 = address
- 2 = ' '
- (HEXDUMP_BYTES_PER_LINE * 3 + 1) = Each byte prints as two hex digits,
- plus a space
- 2 = ' |'
- HEXDUMP_BYTES_PER_LINE = text representation
- 2 = '|\n'
- 1 = '\0'
- */
- char emit_buffer[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
- HEXDUMP_BYTES_PER_LINE + 2 + 1 ];
- char *h,*c;
- my_off_t i;
-
- if (size == 0)
- return 0; // ok, nothing to do
-
- format_hex_line(emit_buffer);
- /*
- Print the rest of the event (without common header)
- */
- my_off_t starting_offset = offset;
- for (i= 0,
- c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2,
- h= emit_buffer + 2 + 8 + 2;
- i < size;
- i++, ptr++)
- {
- my_snprintf(h, 4, "%02x ", *ptr);
- h+= 3;
-
- *c++= my_isprint(&my_charset_bin, *ptr) ? *ptr : '.';
-
- /* Print in groups of HEXDUMP_BYTES_PER_LINE characters. */
- if ((i % HEXDUMP_BYTES_PER_LINE) == (HEXDUMP_BYTES_PER_LINE - 1))
- {
- /* remove \0 left after printing hex byte representation */
- *h= ' ';
- /* prepare space to print address */
- memset(emit_buffer + 2, ' ', 8);
- /* print address */
- size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
- (ulonglong) starting_offset);
- /* remove \0 left after printing address */
- emit_buffer[2 + emit_buf_written]= ' ';
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- sizeof(emit_buffer) - 1))
- goto err;
- c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2;
- h= emit_buffer + 2 + 8 + 2;
- format_hex_line(emit_buffer);
- starting_offset+= HEXDUMP_BYTES_PER_LINE;
- }
- else if ((i % (HEXDUMP_BYTES_PER_LINE / 2))
- == ((HEXDUMP_BYTES_PER_LINE / 2) - 1))
- {
- /*
- In the middle of the group of HEXDUMP_BYTES_PER_LINE, emit an extra
- space in the hex string, to make two groups.
- */
- *h++= ' ';
- }
-
- }
-
- /*
- There is still data left in our buffer, which means that the previous
- line was not perfectly HEXDUMP_BYTES_PER_LINE characters, so write an
- incomplete line, with spaces to pad out to the same length as a full
- line would be, to make things more readable.
- */
- if (h != emit_buffer + 2 + 8 + 2)
- {
- *h= ' ';
- *c++= '|'; *c++= '\n';
- memset(emit_buffer + 2, ' ', 8);
- size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
- (ulonglong) starting_offset);
- emit_buffer[2 + emit_buf_written]= ' ';
- /* pad unprinted area */
- memset(h, ' ',
- (HEXDUMP_BYTES_PER_LINE * 3 + 1) - (h - (emit_buffer + 2 + 8 + 2)));
- if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
- c - emit_buffer))
- goto err;
- }
- if (my_b_write(file, (uchar*)"#\n", 2))
- goto err;
-
- return 0;
-err:
- return 1;
-}
-
-/*
- Log_event::print_header()
-*/
-
-bool Log_event::print_header(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool is_more __attribute__((unused)))
-{
- char llbuff[22];
- my_off_t hexdump_from= print_event_info->hexdump_from;
- DBUG_ENTER("Log_event::print_header");
-
- if (my_b_write_byte(file, '#') ||
- print_timestamp(file) ||
- my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
- llstr(log_pos,llbuff)))
- goto err;
-
- /* print the checksum */
-
- if (checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
- {
- char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "%p "
- size_t const bytes_written=
- my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08x ", crc);
- if (my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib,
- checksum_alg)) ||
- my_b_printf(file, checksum_buf, bytes_written))
- goto err;
- }
-
- /* mysqlbinlog --hexdump */
- if (print_event_info->hexdump_from)
- {
- my_b_write_byte(file, '\n');
- uchar *ptr= (uchar*)temp_buf;
- my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET);
- my_off_t hdr_len= get_header_len(print_event_info->common_header_len);
-
- size-= hdr_len;
-
- if (my_b_printf(file, "# Position\n"))
- goto err;
-
- /* Write the header, nicely formatted by field. */
- if (hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr))
- goto err;
-
- ptr+= hdr_len;
- hexdump_from+= hdr_len;
-
- /* Print the rest of the data, mimicking "hexdump -C" output. */
- if (hexdump_data_to_io_cache(file, hexdump_from, ptr, size))
- goto err;
-
- /*
- Prefix the next line so that the output from print_helper()
- will appear as a comment.
- */
- if (my_b_write(file, (uchar*)"# Event: ", 9))
- goto err;
- }
-
- DBUG_RETURN(0);
-
-err:
- DBUG_RETURN(1);
-}
-
-
-/**
- Prints a quoted string to io cache.
- Control characters are displayed as hex sequence, e.g. \x00
- Single-quote and backslash characters are escaped with a \
-
- @param[in] file IO cache
- @param[in] prt Pointer to string
- @param[in] length String length
-*/
-
-static void
-my_b_write_quoted(IO_CACHE *file, const uchar *ptr, uint length)
-{
- const uchar *s;
- my_b_write_byte(file, '\'');
- for (s= ptr; length > 0 ; s++, length--)
- {
- if (*s > 0x1F)
- my_b_write_byte(file, *s);
- else if (*s == '\'')
- my_b_write(file, (uchar*)"\\'", 2);
- else if (*s == '\\')
- my_b_write(file, (uchar*)"\\\\", 2);
- else
- {
- uchar hex[10];
- size_t len= my_snprintf((char*) hex, sizeof(hex), "%s%02x", "\\x", *s);
- my_b_write(file, hex, len);
- }
- }
- my_b_write_byte(file, '\'');
-}
-
-
-/**
- Prints a bit string to io cache in format b'1010'.
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] nbits Number of bits
-*/
-static void
-my_b_write_bit(IO_CACHE *file, const uchar *ptr, uint nbits)
-{
- uint bitnum, nbits8= ((nbits + 7) / 8) * 8, skip_bits= nbits8 - nbits;
- my_b_write(file, (uchar*)"b'", 2);
- for (bitnum= skip_bits ; bitnum < nbits8; bitnum++)
- {
- int is_set= (ptr[(bitnum) / 8] >> (7 - bitnum % 8)) & 0x01;
- my_b_write_byte(file, (is_set ? '1' : '0'));
- }
- my_b_write_byte(file, '\'');
-}
-
-
-/**
- Prints a packed string to io cache.
- The string consists of length packed to 1 or 2 bytes,
- followed by string data itself.
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] length String size
-
- @retval - number of bytes scanned.
-*/
-static size_t
-my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length)
-{
- if (length < 256)
- {
- length= *ptr;
- my_b_write_quoted(file, ptr + 1, length);
- return length + 1;
- }
- else
- {
- length= uint2korr(ptr);
- my_b_write_quoted(file, ptr + 2, length);
- return length + 2;
- }
-}
-
-
-/**
- Prints a 32-bit number in both signed and unsigned representation
-
- @param[in] file IO cache
- @param[in] sl Signed number
- @param[in] ul Unsigned number
-*/
-static bool
-my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
-{
- bool res= my_b_printf(file, "%d", si);
- if (si < 0)
- if (my_b_printf(file, " (%u)", ui))
- res= 1;
- return res;
-}
-
-
-/**
- Print a packed value of the given SQL type into IO cache
-
- @param[in] file IO cache
- @param[in] ptr Pointer to string
- @param[in] type Column type
- @param[in] meta Column meta information
- @param[out] typestr SQL type string buffer (for verbose output)
- @param[out] typestr_length Size of typestr
-
- @retval - number of bytes scanned from ptr.
- Except in case of NULL, in which case we return 1 to indicate ok
-*/
-
-static size_t
-log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
- const uchar *ptr, uint type, uint meta,
- char *typestr, size_t typestr_length)
-{
- uint32 length= 0;
-
- if (type == MYSQL_TYPE_STRING)
- {
- if (meta >= 256)
- {
- uint byte0= meta >> 8;
- uint byte1= meta & 0xFF;
-
- if ((byte0 & 0x30) != 0x30)
- {
- /* a long CHAR() field: see #37426 */
- length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
- type= byte0 | 0x30;
- }
- else
- length = meta & 0xFF;
- }
- else
- length= meta;
- }
-
- switch (type) {
- case MYSQL_TYPE_LONG:
- {
- strmake(typestr, "INT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= sint4korr(ptr);
- uint32 ui= uint4korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 4;
- }
-
- case MYSQL_TYPE_TINY:
- {
- strmake(typestr, "TINYINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- my_b_write_sint32_and_uint32(file, (int) (signed char) *ptr,
- (uint) (unsigned char) *ptr);
- return 1;
- }
-
- case MYSQL_TYPE_SHORT:
- {
- strmake(typestr, "SHORTINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= (int32) sint2korr(ptr);
- uint32 ui= (uint32) uint2korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 2;
- }
-
- case MYSQL_TYPE_INT24:
- {
- strmake(typestr, "MEDIUMINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 si= sint3korr(ptr);
- uint32 ui= uint3korr(ptr);
- my_b_write_sint32_and_uint32(file, si, ui);
- return 3;
- }
-
- case MYSQL_TYPE_LONGLONG:
- {
- strmake(typestr, "LONGINT", typestr_length);
- if (!ptr)
- goto return_null;
-
- char tmp[64];
- size_t length;
- longlong si= sint8korr(ptr);
- length= (longlong10_to_str(si, tmp, -10) - tmp);
- my_b_write(file, (uchar*)tmp, length);
- if (si < 0)
- {
- ulonglong ui= uint8korr(ptr);
- longlong10_to_str((longlong) ui, tmp, 10);
- my_b_printf(file, " (%s)", tmp);
- }
- return 8;
- }
-
- case MYSQL_TYPE_NEWDECIMAL:
- {
- uint precision= meta >> 8;
- uint decimals= meta & 0xFF;
- my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
- precision, decimals);
- if (!ptr)
- goto return_null;
-
- uint bin_size= my_decimal_get_binary_size(precision, decimals);
- my_decimal dec((const uchar *) ptr, precision, decimals);
- int length= DECIMAL_MAX_STR_LENGTH;
- char buff[DECIMAL_MAX_STR_LENGTH + 1];
- decimal2string(&dec, buff, &length, 0, 0, 0);
- my_b_write(file, (uchar*)buff, length);
- return bin_size;
- }
-
- case MYSQL_TYPE_FLOAT:
- {
- strmake(typestr, "FLOAT", typestr_length);
- if (!ptr)
- goto return_null;
-
- float fl;
- float4get(fl, ptr);
- char tmp[320];
- sprintf(tmp, "%-20g", (double) fl);
- my_b_printf(file, "%s", tmp); /* my_snprintf doesn't support %-20g */
- return 4;
- }
-
- case MYSQL_TYPE_DOUBLE:
- {
- double dbl;
- strmake(typestr, "DOUBLE", typestr_length);
- if (!ptr)
- goto return_null;
-
- float8get(dbl, ptr);
- char tmp[320];
- sprintf(tmp, "%-.20g", dbl); /* strmake doesn't support %-20g */
- my_b_printf(file, tmp, "%s");
- return 8;
- }
-
- case MYSQL_TYPE_BIT:
- {
- /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
- uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
- my_snprintf(typestr, typestr_length, "BIT(%d)", nbits);
- if (!ptr)
- goto return_null;
-
- length= (nbits + 7) / 8;
- my_b_write_bit(file, ptr, nbits);
- return length;
- }
-
- case MYSQL_TYPE_TIMESTAMP:
- {
- strmake(typestr, "TIMESTAMP", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 i32= uint4korr(ptr);
- my_b_printf(file, "%d", i32);
- return 4;
- }
-
- case MYSQL_TYPE_TIMESTAMP2:
- {
- my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- struct timeval tm;
- my_timestamp_from_binary(&tm, ptr, meta);
- int buflen= my_timeval_to_str(&tm, buf, meta);
- my_b_write(file, (uchar*)buf, buflen);
- return my_timestamp_binary_length(meta);
- }
-
- case MYSQL_TYPE_DATETIME:
- {
- strmake(typestr, "DATETIME", typestr_length);
- if (!ptr)
- goto return_null;
-
- ulong d, t;
- uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */
- d= (ulong) (i64 / 1000000);
- t= (ulong) (i64 % 1000000);
-
- my_b_printf(file, "'%04d-%02d-%02d %02d:%02d:%02d'",
- (int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100),
- (int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100);
- return 8;
- }
-
- case MYSQL_TYPE_DATETIME2:
- {
- my_snprintf(typestr, typestr_length, "DATETIME(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- MYSQL_TIME ltime;
- longlong packed= my_datetime_packed_from_binary(ptr, meta);
- TIME_from_longlong_datetime_packed(&ltime, packed);
- int buflen= my_datetime_to_str(&ltime, buf, meta);
- my_b_write_quoted(file, (uchar *) buf, buflen);
- return my_datetime_binary_length(meta);
- }
-
- case MYSQL_TYPE_TIME:
- {
- strmake(typestr, "TIME", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 tmp= sint3korr(ptr);
- int32 i32= tmp >= 0 ? tmp : - tmp;
- const char *sign= tmp < 0 ? "-" : "";
- my_b_printf(file, "'%s%02d:%02d:%02d'",
- sign, i32 / 10000, (i32 % 10000) / 100, i32 % 100, i32);
- return 3;
- }
-
- case MYSQL_TYPE_TIME2:
- {
- my_snprintf(typestr, typestr_length, "TIME(%d)", meta);
- if (!ptr)
- goto return_null;
-
- char buf[MAX_DATE_STRING_REP_LENGTH];
- MYSQL_TIME ltime;
- longlong packed= my_time_packed_from_binary(ptr, meta);
- TIME_from_longlong_time_packed(&ltime, packed);
- int buflen= my_time_to_str(&ltime, buf, meta);
- my_b_write_quoted(file, (uchar *) buf, buflen);
- return my_time_binary_length(meta);
- }
-
- case MYSQL_TYPE_NEWDATE:
- {
- strmake(typestr, "DATE", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 tmp= uint3korr(ptr);
- int part;
- char buf[11];
- char *pos= &buf[10]; // start from '\0' to the beginning
-
- /* Copied from field.cc */
- *pos--=0; // End NULL
- part=(int) (tmp & 31);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= ':';
- part=(int) (tmp >> 5 & 15);
- *pos--= (char) ('0'+part%10);
- *pos--= (char) ('0'+part/10);
- *pos--= ':';
- part=(int) (tmp >> 9);
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos--= (char) ('0'+part%10); part/=10;
- *pos= (char) ('0'+part);
- my_b_printf(file , "'%s'", buf);
- return 3;
- }
-
- case MYSQL_TYPE_DATE:
- {
- strmake(typestr, "DATE", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint i32= uint3korr(ptr);
- my_b_printf(file , "'%04d:%02d:%02d'",
- (int)(i32 / (16L * 32L)), (int)(i32 / 32L % 16L),
- (int)(i32 % 32L));
- return 3;
- }
-
- case MYSQL_TYPE_YEAR:
- {
- strmake(typestr, "YEAR", typestr_length);
- if (!ptr)
- goto return_null;
-
- uint32 i32= *ptr;
- my_b_printf(file, "%04d", i32+ 1900);
- return 1;
- }
-
- case MYSQL_TYPE_ENUM:
- switch (meta & 0xFF) {
- case 1:
- strmake(typestr, "ENUM(1 byte)", typestr_length);
- if (!ptr)
- goto return_null;
-
- my_b_printf(file, "%d", (int) *ptr);
- return 1;
- case 2:
- {
- strmake(typestr, "ENUM(2 bytes)", typestr_length);
- if (!ptr)
- goto return_null;
-
- int32 i32= uint2korr(ptr);
- my_b_printf(file, "%d", i32);
- return 2;
- }
- default:
- my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF);
- return 0;
- }
- break;
-
- case MYSQL_TYPE_SET:
- my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF);
- if (!ptr)
- goto return_null;
-
- my_b_write_bit(file, ptr , (meta & 0xFF) * 8);
- return meta & 0xFF;
-
- case MYSQL_TYPE_BLOB:
- switch (meta) {
- case 1:
- strmake(typestr, "TINYBLOB/TINYTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= *ptr;
- my_b_write_quoted(file, ptr + 1, length);
- return length + 1;
- case 2:
- strmake(typestr, "BLOB/TEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint2korr(ptr);
- my_b_write_quoted(file, ptr + 2, length);
- return length + 2;
- case 3:
- strmake(typestr, "MEDIUMBLOB/MEDIUMTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint3korr(ptr);
- my_b_write_quoted(file, ptr + 3, length);
- return length + 3;
- case 4:
- strmake(typestr, "LONGBLOB/LONGTEXT", typestr_length);
- if (!ptr)
- goto return_null;
-
- length= uint4korr(ptr);
- my_b_write_quoted(file, ptr + 4, length);
- return length + 4;
- default:
- my_b_printf(file, "!! Unknown BLOB packlen=%d", length);
- return 0;
- }
-
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- length= meta;
- my_snprintf(typestr, typestr_length, "VARSTRING(%d)", length);
- if (!ptr)
- goto return_null;
-
- return my_b_write_quoted_with_length(file, ptr, length);
-
- case MYSQL_TYPE_STRING:
- my_snprintf(typestr, typestr_length, "STRING(%d)", length);
- if (!ptr)
- goto return_null;
-
- return my_b_write_quoted_with_length(file, ptr, length);
-
- case MYSQL_TYPE_DECIMAL:
- print_event_info->flush_for_error();
- fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
- "Not enough metadata to display the value.\n");
- break;
- default:
- print_event_info->flush_for_error();
- fprintf(stderr,
- "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n",
- type, meta, meta);
- break;
- }
- *typestr= 0;
- return 0;
-
-return_null:
- return my_b_write(file, (uchar*) "NULL", 4) ? 0 : 1;
-}
-
-
-/**
- Print a packed row into IO cache
-
- @param[in] file IO cache
- @param[in] td Table definition
- @param[in] print_event_into Print parameters
- @param[in] cols_bitmap Column bitmaps.
- @param[in] value Pointer to packed row
- @param[in] prefix Row's SQL clause ("SET", "WHERE", etc)
-
- @retval 0 error
- # number of bytes scanned.
-*/
-
-
-size_t
-Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
- PRINT_EVENT_INFO *print_event_info,
- MY_BITMAP *cols_bitmap,
- const uchar *value, const uchar *prefix,
- const my_bool no_fill_output)
-{
- const uchar *value0= value;
- const uchar *null_bits= value;
- uint null_bit_index= 0;
- char typestr[64]= "";
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- /* Storing the review SQL */
- IO_CACHE *review_sql= &print_event_info->review_sql_cache;
- LEX_STRING review_str;
-#endif
-
- /*
- Skip metadata bytes which gives the information about nullabity of master
- columns. Master writes one bit for each affected column.
- */
-
- value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
-
- if (!no_fill_output)
- if (my_b_printf(file, "%s", prefix))
- goto err;
-
- for (uint i= 0; i < (uint)td->size(); i ++)
- {
- size_t size;
- int is_null= (null_bits[null_bit_index / 8]
- >> (null_bit_index % 8)) & 0x01;
-
- if (bitmap_is_set(cols_bitmap, i) == 0)
- continue;
-
- if (!no_fill_output)
- if (my_b_printf(file, "### @%d=", static_cast<int>(i + 1)))
- goto err;
-
- if (!is_null)
- {
- size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
- if (value + fsize > m_rows_end)
- {
- if (!no_fill_output)
- if (my_b_printf(file, "***Corrupted replication event was detected."
- " Not printing the value***\n"))
- goto err;
- value+= fsize;
- return 0;
- }
- }
-
- if (!no_fill_output)
- {
- size= log_event_print_value(file, print_event_info, is_null? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- {
- String tmp_str, hex_str;
- IO_CACHE tmp_cache;
-
- // Using a tmp IO_CACHE to get the value output
- open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache, print_event_info,
- is_null ? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
- error= copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str);
- close_cached_file(&tmp_cache);
- if (unlikely(error))
- return 0;
-
- switch (td->type(i)) // Converting a string to HEX format
- {
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_BLOB:
- // Avoid write_pos changed to a new area
- // tmp_str.free();
- tmp_str.append(review_str.str + 1, review_str.length - 2); // Removing quotation marks
- if (hex_str.alloc(tmp_str.length()*2+1)) // If out of memory
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not print correct binlog event.\n");
- exit(1);
- }
- octet2hex((char*) hex_str.ptr(), tmp_str.ptr(), tmp_str.length());
- if (my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr()))
- goto err;
- break;
- default:
- tmp_str.free();
- if (tmp_str.append(review_str.str, review_str.length) ||
- my_b_printf(review_sql, ", %s", tmp_str.ptr()))
- goto err;
- break;
- }
- my_free(revieww_str.str);
- }
-#endif
- }
- else
- {
- IO_CACHE tmp_cache;
- open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
- size= log_event_print_value(&tmp_cache, print_event_info,
- is_null ? NULL: value,
- td->type(i), td->field_metadata(i),
- typestr, sizeof(typestr));
- close_cached_file(&tmp_cache);
- }
-
- if (!size)
- goto err;
-
- if (!is_null)
- value+= size;
-
- if (print_event_info->verbose > 1 && !no_fill_output)
- {
- if (my_b_write(file, (uchar*)" /* ", 4) ||
- my_b_printf(file, "%s ", typestr) ||
- my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
- td->field_metadata(i),
- td->maybe_null(i), is_null) ||
- my_b_write(file, (uchar*)"*/", 2))
- goto err;
- }
-
- if (!no_fill_output)
- if (my_b_write_byte(file, '\n'))
- goto err;
-
- null_bit_index++;
- }
- return value - value0;
-
-err:
- return 0;
-}
-
-
-/**
- Exchange the SET part and WHERE part for the Update events.
- Revert the operations order for the Write and Delete events.
- And then revert the events order from the last one to the first one.
-
- @param[in] print_event_info PRINT_EVENT_INFO
- @param[in] rows_buff Packed event buff
-*/
-
-void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_info,
- uchar *rows_buff, Log_event_type ev_type)
-{
- Table_map_log_event *map;
- table_def *td;
- DYNAMIC_ARRAY rows_arr;
- uchar *swap_buff1, *swap_buff2;
- uchar *rows_pos= rows_buff + m_rows_before_size;
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- return;
-
- /* If the write rows event contained no values for the AI */
- if (((get_general_type_code() == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
- goto end;
-
- (void) my_init_dynamic_array(&rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0));
-
- for (uchar *value= m_rows_buf; value < m_rows_end; )
- {
- uchar *start_pos= value;
- size_t length1= 0;
- if (!(length1= print_verbose_one_row(NULL, td, print_event_info,
- &m_cols, value,
- (const uchar*) "", TRUE)))
- {
- fprintf(stderr, "\nError row length: %zu\n", length1);
- exit(1);
- }
- value+= length1;
-
- swap_buff1= (uchar *) my_malloc(length1, MYF(0));
- if (!swap_buff1)
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not exchange to flashback event.\n");
- exit(1);
- }
- memcpy(swap_buff1, start_pos, length1);
-
- // For Update_event, we have the second part
- size_t length2= 0;
- if (ev_type == UPDATE_ROWS_EVENT ||
- ev_type == UPDATE_ROWS_EVENT_V1)
- {
- if (!(length2= print_verbose_one_row(NULL, td, print_event_info,
- &m_cols, value,
- (const uchar*) "", TRUE)))
- {
- fprintf(stderr, "\nError row length: %zu\n", length2);
- exit(1);
- }
- value+= length2;
-
- swap_buff2= (uchar *) my_malloc(length2, MYF(0));
- if (!swap_buff2)
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not exchange to flashback event.\n");
- exit(1);
- }
- memcpy(swap_buff2, start_pos + length1, length2); // WHERE part
- }
-
- if (ev_type == UPDATE_ROWS_EVENT ||
- ev_type == UPDATE_ROWS_EVENT_V1)
- {
- /* Swap SET and WHERE part */
- memcpy(start_pos, swap_buff2, length2);
- memcpy(start_pos + length2, swap_buff1, length1);
- }
-
- /* Free tmp buffers */
- my_free(swap_buff1);
- if (ev_type == UPDATE_ROWS_EVENT ||
- ev_type == UPDATE_ROWS_EVENT_V1)
- my_free(swap_buff2);
-
- /* Copying one row into a buff, and pushing into the array */
- LEX_STRING one_row;
-
- one_row.length= length1 + length2;
- one_row.str= (char *) my_malloc(one_row.length, MYF(0));
- memcpy(one_row.str, start_pos, one_row.length);
- if (one_row.str == NULL || push_dynamic(&rows_arr, (uchar *) &one_row))
- {
- fprintf(stderr, "\nError: Out of memory. "
- "Could not push flashback event into array.\n");
- exit(1);
- }
- }
-
- /* Copying rows from the end to the begining into event */
- for (uint i= rows_arr.elements; i > 0; --i)
- {
- LEX_STRING *one_row= dynamic_element(&rows_arr, i - 1, LEX_STRING*);
-
- memcpy(rows_pos, (uchar *)one_row->str, one_row->length);
- rows_pos+= one_row->length;
- my_free(one_row->str);
- }
- delete_dynamic(&rows_arr);
-
-end:
- delete td;
-}
-
-/**
- Calc length of a packed value of the given SQL type
-
- @param[in] ptr Pointer to string
- @param[in] type Column type
- @param[in] meta Column meta information
-
- @retval - number of bytes scanned from ptr.
- Except in case of NULL, in which case we return 1 to indicate ok
-*/
-
-static size_t calc_field_event_length(const uchar *ptr, uint type, uint meta)
-{
- uint32 length= 0;
-
- if (type == MYSQL_TYPE_STRING)
- {
- if (meta >= 256)
- {
- uint byte0= meta >> 8;
- uint byte1= meta & 0xFF;
-
- if ((byte0 & 0x30) != 0x30)
- {
- /* a long CHAR() field: see #37426 */
- length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
- type= byte0 | 0x30;
- }
- else
- length = meta & 0xFF;
- }
- else
- length= meta;
- }
-
- switch (type) {
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_TIMESTAMP:
- return 4;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_YEAR:
- return 1;
- case MYSQL_TYPE_SHORT:
- return 2;
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- return 3;
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_DATETIME:
- return 8;
- case MYSQL_TYPE_NEWDECIMAL:
- {
- uint precision= meta >> 8;
- uint decimals= meta & 0xFF;
- uint bin_size= my_decimal_get_binary_size(precision, decimals);
- return bin_size;
- }
- case MYSQL_TYPE_FLOAT:
- return 4;
- case MYSQL_TYPE_DOUBLE:
- return 8;
- case MYSQL_TYPE_BIT:
- {
- /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
- uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
- length= (nbits + 7) / 8;
- return length;
- }
- case MYSQL_TYPE_TIMESTAMP2:
- return my_timestamp_binary_length(meta);
- case MYSQL_TYPE_DATETIME2:
- return my_datetime_binary_length(meta);
- case MYSQL_TYPE_TIME2:
- return my_time_binary_length(meta);
- case MYSQL_TYPE_ENUM:
- switch (meta & 0xFF) {
- case 1:
- case 2:
- return (meta & 0xFF);
- default:
- /* Unknown ENUM packlen=%d", meta & 0xFF */
- return 0;
- }
- break;
- case MYSQL_TYPE_SET:
- return meta & 0xFF;
- case MYSQL_TYPE_BLOB:
- return (meta <= 4 ? meta : 0);
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VAR_STRING:
- length= meta;
- /* fall through */
- case MYSQL_TYPE_STRING:
- if (length < 256)
- return (uint) *ptr + 1;
- return uint2korr(ptr) + 2;
- case MYSQL_TYPE_DECIMAL:
- break;
- default:
- break;
- }
- return 0;
-}
-
-
-size_t
-Rows_log_event::calc_row_event_length(table_def *td,
- PRINT_EVENT_INFO *print_event_info,
- MY_BITMAP *cols_bitmap,
- const uchar *value)
-{
- const uchar *value0= value;
- const uchar *null_bits= value;
- uint null_bit_index= 0;
-
- /*
- Skip metadata bytes which gives the information about nullabity of master
- columns. Master writes one bit for each affected column.
- */
-
- value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
-
- for (uint i= 0; i < (uint)td->size(); i ++)
- {
- int is_null;
- is_null= (null_bits[null_bit_index / 8] >> (null_bit_index % 8)) & 0x01;
-
- if (bitmap_is_set(cols_bitmap, i) == 0)
- continue;
-
- if (!is_null)
- {
- size_t size;
- size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
- if (value + fsize > m_rows_end)
- {
- /* Corrupted replication event was detected, skipping entry */
- return 0;
- }
- if (!(size= calc_field_event_length(value, td->type(i),
- td->field_metadata(i))))
- return 0;
- value+= size;
- }
- null_bit_index++;
- }
- return value - value0;
-}
-
-
-/**
- Calculate how many rows there are in the event
-
- @param[in] file IO cache
- @param[in] print_event_into Print parameters
-*/
-
-void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info)
-{
- Table_map_log_event *map;
- table_def *td;
- uint row_events;
- Log_event_type general_type_code= get_general_type_code();
-
- switch (general_type_code) {
- case WRITE_ROWS_EVENT:
- case DELETE_ROWS_EVENT:
- row_events= 1;
- break;
- case UPDATE_ROWS_EVENT:
- row_events= 2;
- break;
- default:
- DBUG_ASSERT(0); /* Not possible */
- return;
- }
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- {
- /* Row event for unknown table */
- return;
- }
-
- for (const uchar *value= m_rows_buf; value < m_rows_end; )
- {
- size_t length;
- print_event_info->row_events++;
-
- /* Print the first image */
- if (!(length= calc_row_event_length(td, print_event_info,
- &m_cols, value)))
- break;
- value+= length;
- DBUG_ASSERT(value <= m_rows_end);
-
- /* Print the second image (for UPDATE only) */
- if (row_events == 2)
- {
- if (!(length= calc_row_event_length(td, print_event_info,
- &m_cols_ai, value)))
- break;
- value+= length;
- DBUG_ASSERT(value <= m_rows_end);
- }
- }
- delete td;
-}
-
-
-/**
- Print a row event into IO cache in human readable form (in SQL format)
-
- @param[in] file IO cache
- @param[in] print_event_into Print parameters
-*/
-
-bool Rows_log_event::print_verbose(IO_CACHE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- Table_map_log_event *map;
- table_def *td= 0;
- const char *sql_command, *sql_clause1, *sql_clause2;
- const char *sql_command_short __attribute__((unused));
- Log_event_type general_type_code= get_general_type_code();
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- IO_CACHE *review_sql= &print_event_info->review_sql_cache;
-#endif
-
- if (m_extra_row_data)
- {
- uint8 extra_data_len= m_extra_row_data[EXTRA_ROW_INFO_LEN_OFFSET];
- uint8 extra_payload_len= extra_data_len - EXTRA_ROW_INFO_HDR_BYTES;
- assert(extra_data_len >= EXTRA_ROW_INFO_HDR_BYTES);
-
- if (my_b_printf(file, "### Extra row data format: %u, len: %u :",
- m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
- extra_payload_len))
- goto err;
- if (extra_payload_len)
- {
- /*
- Buffer for hex view of string, including '0x' prefix,
- 2 hex chars / byte and trailing 0
- */
- const int buff_len= 2 + (256 * 2) + 1;
- char buff[buff_len];
- str_to_hex(buff, (const char*) &m_extra_row_data[EXTRA_ROW_INFO_HDR_BYTES],
- extra_payload_len);
- if (my_b_printf(file, "%s", buff))
- goto err;
- }
- if (my_b_printf(file, "\n"))
- goto err;
- }
-
- switch (general_type_code) {
- case WRITE_ROWS_EVENT:
- sql_command= "INSERT INTO";
- sql_clause1= "### SET\n";
- sql_clause2= NULL;
- sql_command_short= "I";
- break;
- case DELETE_ROWS_EVENT:
- sql_command= "DELETE FROM";
- sql_clause1= "### WHERE\n";
- sql_clause2= NULL;
- sql_command_short= "D";
- break;
- case UPDATE_ROWS_EVENT:
- sql_command= "UPDATE";
- sql_clause1= "### WHERE\n";
- sql_clause2= "### SET\n";
- sql_command_short= "U";
- break;
- default:
- sql_command= sql_clause1= sql_clause2= NULL;
- sql_command_short= "";
- DBUG_ASSERT(0); /* Not possible */
- }
-
- if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
- !(td= map->create_table_def()))
- {
- return (my_b_printf(file, "### Row event for unknown table #%lu",
- (ulong) m_table_id));
- }
-
- /* If the write rows event contained no values for the AI */
- if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
- {
- if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
- map->get_db_name(), map->get_table_name()))
- goto err;
- goto end;
- }
-
- for (const uchar *value= m_rows_buf; value < m_rows_end; )
- {
- size_t length;
- print_event_info->row_events++;
-
- if (my_b_printf(file, "### %s %`s.%`s\n",
- sql_command,
- map->get_db_name(), map->get_table_name()))
- goto err;
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- if (my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
- map->get_review_dbname(), map->get_review_tablename(),
- sql_command_short))
- goto err;
-#endif
-
- /* Print the first image */
- if (!(length= print_verbose_one_row(file, td, print_event_info,
- &m_cols, value,
- (const uchar*) sql_clause1)))
- goto err;
- value+= length;
-
- /* Print the second image (for UPDATE only) */
- if (sql_clause2)
- {
- if (!(length= print_verbose_one_row(file, td, print_event_info,
- &m_cols_ai, value,
- (const uchar*) sql_clause2)))
- goto err;
- value+= length;
- }
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- else
- {
- if (need_flashback_review)
- for (size_t i= 0; i < td->size(); i ++)
- if (my_b_printf(review_sql, ", NULL"))
- goto err;
- }
-
- if (need_flashback_review)
- if (my_b_printf(review_sql, ")%s\n", print_event_info->delimiter))
- goto err;
-#endif
- }
-
-end:
- delete td;
- return 0;
-err:
- delete td;
- return 1;
-}
-
-void free_table_map_log_event(Table_map_log_event *event)
-{
- delete event;
-}
-
-/**
- Encode the event, optionally per 'do_print_encoded' arg store the
- result into the argument cache; optionally per event_info's
- 'verbose' print into the cache a verbose representation of the event.
- Note, no extra wrapping is done to the being io-cached data, like
- to producing a BINLOG query. It's left for a routine that extracts from
- the cache.
-
- @param file pointer to IO_CACHE
- @param print_event_info pointer to print_event_info specializing
- what out of and how to print the event
- @param do_print_encoded whether to store base64-encoded event
- into @file.
-*/
-bool Log_event::print_base64(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool do_print_encoded)
-{
- uchar *ptr= (uchar *)temp_buf;
- uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
- DBUG_ENTER("Log_event::print_base64");
-
- if (is_flashback)
- {
- uint tmp_size= size;
- Rows_log_event *ev= NULL;
- Log_event_type ev_type = (enum Log_event_type) ptr[EVENT_TYPE_OFFSET];
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
- tmp_size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
- switch (ev_type) {
- case WRITE_ROWS_EVENT:
- ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT;
- ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case WRITE_ROWS_EVENT_V1:
- ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT_V1;
- ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case DELETE_ROWS_EVENT:
- ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT;
- ev= new Write_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case DELETE_ROWS_EVENT_V1:
- ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT_V1;
- ev= new Write_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- case UPDATE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT_V1:
- ev= new Update_rows_log_event((const char*) ptr, tmp_size,
- glob_description_event);
- ev->change_to_flashback_event(print_event_info, ptr, ev_type);
- break;
- default:
- break;
- }
- delete ev;
- }
-
- if (do_print_encoded)
- {
- size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
- char *tmp_str;
- if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME))))
- goto err;
-
- if (my_base64_encode(ptr, (size_t) size, tmp_str))
- {
- DBUG_ASSERT(0);
- }
-
- my_b_printf(file, "%s\n", tmp_str);
- my_free(tmp_str);
- }
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (print_event_info->verbose || print_event_info->print_row_count ||
- need_flashback_review)
-#else
- // Flashback need the table_map to parse the event
- if (print_event_info->verbose || print_event_info->print_row_count ||
- is_flashback)
-#endif
- {
- Rows_log_event *ev= NULL;
- Log_event_type et= (Log_event_type) ptr[EVENT_TYPE_OFFSET];
-
- if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
- checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
- size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
-
- switch (et)
- {
- case TABLE_MAP_EVENT:
- {
- Table_map_log_event *map;
- map= new Table_map_log_event((const char*) ptr, size,
- glob_description_event);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (need_flashback_review)
- {
- map->set_review_dbname(m_review_dbname.ptr());
- map->set_review_tablename(m_review_tablename.ptr());
- }
-#endif
- print_event_info->m_table_map.set_table(map->get_table_id(), map);
- break;
- }
- case WRITE_ROWS_EVENT:
- case WRITE_ROWS_EVENT_V1:
- {
- ev= new Write_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case DELETE_ROWS_EVENT:
- case DELETE_ROWS_EVENT_V1:
- {
- ev= new Delete_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case UPDATE_ROWS_EVENT:
- case UPDATE_ROWS_EVENT_V1:
- {
- ev= new Update_rows_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case WRITE_ROWS_COMPRESSED_EVENT:
- case WRITE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Write_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case UPDATE_ROWS_COMPRESSED_EVENT:
- case UPDATE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Update_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- case DELETE_ROWS_COMPRESSED_EVENT:
- case DELETE_ROWS_COMPRESSED_EVENT_V1:
- {
- ev= new Delete_rows_compressed_log_event((const char*) ptr, size,
- glob_description_event);
- break;
- }
- default:
- break;
- }
-
- if (ev)
- {
- bool error= 0;
-
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- ev->need_flashback_review= need_flashback_review;
- if (print_event_info->verbose)
- {
- if (ev->print_verbose(file, print_event_info))
- goto err;
- }
- else
- {
- IO_CACHE tmp_cache;
-
- if (open_cached_file(&tmp_cache, NULL, NULL, 0,
- MYF(MY_WME | MY_NABP)))
- {
- delete ev;
- goto err;
- }
-
- error= ev->print_verbose(&tmp_cache, print_event_info);
- close_cached_file(&tmp_cache);
- if (unlikely(error))
- {
- delete ev;
- goto err;
- }
- }
-#else
- if (print_event_info->verbose)
- {
- /*
- Verbose event printout can't start before encoded data
- got enquoted. This is done at this point though multi-row
- statement remain vulnerable.
- TODO: fix MDEV-10362 to remove this workaround.
- */
- if (print_event_info->base64_output_mode !=
- BASE64_OUTPUT_DECODE_ROWS)
- my_b_printf(file, "'%s\n", print_event_info->delimiter);
- error= ev->print_verbose(file, print_event_info);
- }
- else
- {
- ev->count_row_events(print_event_info);
- }
-#endif
- delete ev;
- if (unlikely(error))
- goto err;
- }
- }
- DBUG_RETURN(0);
-
-err:
- DBUG_RETURN(1);
-}
-
-
-/*
- Log_event::print_timestamp()
-*/
-
-bool Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
-{
- struct tm *res;
- time_t my_when= when;
- DBUG_ENTER("Log_event::print_timestamp");
- if (!ts)
- ts = &my_when;
- res=localtime(ts);
-
- DBUG_RETURN(my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
- res->tm_year % 100,
- res->tm_mon+1,
- res->tm_mday,
- res->tm_hour,
- res->tm_min,
- res->tm_sec));
-}
-
-#endif /* MYSQL_CLIENT */
-
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-inline Log_event::enum_skip_reason
-Log_event::continue_group(rpl_group_info *rgi)
-{
- if (rgi->rli->slave_skip_counter == 1)
- return Log_event::EVENT_SKIP_IGNORE;
- return Log_event::do_shall_skip(rgi);
-}
-#endif
-
-/**************************************************************************
- Query_log_event methods
-**************************************************************************/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- This (which is used only for SHOW BINLOG EVENTS) could be updated to
- print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is
- only an information, it does not produce suitable queries to replay (for
- example it does not print LOAD DATA INFILE).
- @todo
- show the catalog ??
-*/
-
-void Query_log_event::pack_info(Protocol *protocol)
-{
- // TODO: show the catalog ??
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.real_alloc(9 + db_len + q_len);
- if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
- && db && db_len)
- {
- buf.append(STRING_WITH_LEN("use "));
- append_identifier(protocol->thd, &buf, db, db_len);
- buf.append(STRING_WITH_LEN("; "));
- }
- if (query && q_len)
- buf.append(query, q_len);
- protocol->store(&buf);
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-
-/**
- Utility function for the next method (Query_log_event::write()) .
-*/
-static void store_str_with_code_and_len(uchar **dst, const char *src,
- uint len, uint code)
-{
- /*
- only 1 byte to store the length of catalog, so it should not
- surpass 255
- */
- DBUG_ASSERT(len <= 255);
- DBUG_ASSERT(src);
- *((*dst)++)= (uchar) code;
- *((*dst)++)= (uchar) len;
- bmove(*dst, src, len);
- (*dst)+= len;
-}
-
-
-/**
- Query_log_event::write().
-
- @note
- In this event we have to modify the header to have the correct
- EVENT_LEN_OFFSET as we don't yet know how many status variables we
- will print!
-*/
-
-bool Query_log_event::write()
-{
- uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
- uchar *start, *start_of_status;
- ulong event_length;
-
- if (!query)
- return 1; // Something wrong with event
-
- /*
- We want to store the thread id:
- (- as an information for the user when he reads the binlog)
- - if the query uses temporary table: for the slave SQL thread to know to
- which master connection the temp table belongs.
- Now imagine we (write()) are called by the slave SQL thread (we are
- logging a query executed by this thread; the slave runs with
- --log-slave-updates). Then this query will be logged with
- thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of
- the same name were created simultaneously on the master (in the master
- binlog you have
- CREATE TEMPORARY TABLE t; (thread 1)
- CREATE TEMPORARY TABLE t; (thread 2)
- ...)
- then in the slave's binlog there will be
- CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
- CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
- which is bad (same thread id!).
-
- To avoid this, we log the thread's thread id EXCEPT for the SQL
- slave thread for which we log the original (master's) thread id.
- Now this moves the bug: what happens if the thread id on the
- master was 10 and when the slave replicates the query, a
- connection number 10 is opened by a normal client on the slave,
- and updates a temp table of the same name? We get a problem
- again. To avoid this, in the handling of temp tables (sql_base.cc)
- we use thread_id AND server_id. TODO when this is merged into
- 4.1: in 4.1, slave_proxy_id has been renamed to pseudo_thread_id
- and is a session variable: that's to make mysqlbinlog work with
- temp tables. We probably need to introduce
-
- SET PSEUDO_SERVER_ID
- for mysqlbinlog in 4.1. mysqlbinlog would print:
- SET PSEUDO_SERVER_ID=
- SET PSEUDO_THREAD_ID=
- for each query using temp tables.
- */
- int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id);
- int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
- buf[Q_DB_LEN_OFFSET] = (char) db_len;
- int2store(buf + Q_ERR_CODE_OFFSET, error_code);
-
- /*
- You MUST always write status vars in increasing order of code. This
- guarantees that a slightly older slave will be able to parse those he
- knows.
- */
- start_of_status= start= buf+QUERY_HEADER_LEN;
- if (flags2_inited)
- {
- *start++= Q_FLAGS2_CODE;
- int4store(start, flags2);
- start+= 4;
- }
- if (sql_mode_inited)
- {
- *start++= Q_SQL_MODE_CODE;
- int8store(start, (ulonglong)sql_mode);
- start+= 8;
- }
- if (catalog_len) // i.e. this var is inited (false for 4.0 events)
- {
- store_str_with_code_and_len(&start,
- catalog, catalog_len, Q_CATALOG_NZ_CODE);
- /*
- In 5.0.x where x<4 masters we used to store the end zero here. This was
- a waste of one byte so we don't do it in x>=4 masters. We change code to
- Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
- of this x>=4 master segfault (expecting a zero when there is
- none). Remaining compatibility problems are: the older slave will not
- find the catalog; but it is will not crash, and it's not an issue
- that it does not find the catalog as catalogs were not used in these
- older MySQL versions (we store it in binlog and read it from relay log
- but do nothing useful with it). What is an issue is that the older slave
- will stop processing the Q_* blocks (and jumps to the db/query) as soon
- as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
- Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
- various ways. Documented that you should not mix alpha/beta versions if
- they are not exactly the same version, with example of 5.0.3->5.0.2 and
- 5.0.4->5.0.3. If replication is from older to new, the new will
- recognize Q_CATALOG_CODE and have no problem.
- */
- }
- if (auto_increment_increment != 1 || auto_increment_offset != 1)
- {
- *start++= Q_AUTO_INCREMENT;
- int2store(start, auto_increment_increment);
- int2store(start+2, auto_increment_offset);
- start+= 4;
- }
- if (charset_inited)
- {
- *start++= Q_CHARSET_CODE;
- memcpy(start, charset, 6);
- start+= 6;
- }
- if (time_zone_len)
- {
- /* In the TZ sys table, column Name is of length 64 so this should be ok */
- DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
- store_str_with_code_and_len(&start,
- time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
- }
- if (lc_time_names_number)
- {
- DBUG_ASSERT(lc_time_names_number <= 0xFFFF);
- *start++= Q_LC_TIME_NAMES_CODE;
- int2store(start, lc_time_names_number);
- start+= 2;
- }
- if (charset_database_number)
- {
- DBUG_ASSERT(charset_database_number <= 0xFFFF);
- *start++= Q_CHARSET_DATABASE_CODE;
- int2store(start, charset_database_number);
- start+= 2;
- }
- if (table_map_for_update)
- {
- *start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
- int8store(start, table_map_for_update);
- start+= 8;
- }
- if (master_data_written != 0)
- {
- /*
- Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master
- has binlog_version<4 and the slave has binlog_version=4. See comment
- for master_data_written in log_event.h for details.
- */
- *start++= Q_MASTER_DATA_WRITTEN_CODE;
- int4store(start, master_data_written);
- start+= 4;
- }
-
- if (thd && thd->need_binlog_invoker())
- {
- LEX_CSTRING user;
- LEX_CSTRING host;
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-
- if (thd->slave_thread && thd->has_invoker())
- {
- /* user will be null, if master is older than this patch */
- user= thd->get_invoker_user();
- host= thd->get_invoker_host();
- }
- else
- {
- Security_context *ctx= thd->security_ctx;
-
- if (thd->need_binlog_invoker() == THD::INVOKER_USER)
- {
- user.str= ctx->priv_user;
- host.str= ctx->priv_host;
- host.length= strlen(host.str);
- }
- else
- {
- user.str= ctx->priv_role;
- host= empty_clex_str;
- }
- user.length= strlen(user.str);
- }
-
- if (user.length > 0)
- {
- *start++= Q_INVOKER;
-
- /*
- Store user length and user. The max length of use is 16, so 1 byte is
- enough to store the user's length.
- */
- *start++= (uchar)user.length;
- memcpy(start, user.str, user.length);
- start+= user.length;
-
- /*
- Store host length and host. The max length of host is 60, so 1 byte is
- enough to store the host's length.
- */
- *start++= (uchar)host.length;
- memcpy(start, host.str, host.length);
- start+= host.length;
- }
- }
-
- if (thd && thd->query_start_sec_part_used)
- {
- *start++= Q_HRNOW;
- get_time();
- int3store(start, when_sec_part);
- start+= 3;
- }
- /*
- NOTE: When adding new status vars, please don't forget to update
- the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
- code_name() in this file.
-
- Here there could be code like
- if (command-line-option-which-says-"log_this_variable" && inited)
- {
- *start++= Q_THIS_VARIABLE_CODE;
- int4store(start, this_variable);
- start+= 4;
- }
- */
-
- /* Store length of status variables */
- status_vars_len= (uint) (start-start_of_status);
- DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS);
- int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
-
- /*
- Calculate length of whole event
- The "1" below is the \0 in the db's length
- */
- event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
-
- return write_header(event_length) ||
- write_data(buf, QUERY_HEADER_LEN) ||
- write_post_header_for_derived() ||
- write_data(start_of_status, (uint) (start-start_of_status)) ||
- write_data(safe_str(db), db_len + 1) ||
- write_data(query, q_len) ||
- write_footer();
-}
-
-bool Query_compressed_log_event::write()
-{
- const char *query_tmp = query;
- uint32 q_len_tmp = q_len;
- uint32 alloc_size;
- bool ret = true;
- q_len = alloc_size = binlog_get_compress_len(q_len);
- query = (char *)my_safe_alloca(alloc_size);
- if(query && !binlog_buf_compress(query_tmp, (char *)query, q_len_tmp, &q_len))
- {
- ret = Query_log_event::write();
- }
- my_safe_afree((void *)query, alloc_size);
- query = query_tmp;
- q_len = q_len_tmp;
- return ret;
-}
-
-/**
- The simplest constructor that could possibly work. This is used for
- creating static objects that have a special meaning and are invisible
- to the log.
-*/
-Query_log_event::Query_log_event()
- :Log_event(), data_buf(0)
-{
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-}
-
-
-/*
- SYNOPSIS
- Query_log_event::Query_log_event()
- thd_arg - thread handle
- query_arg - array of char representing the query
- query_length - size of the `query_arg' array
- using_trans - there is a modified transactional table
- direct - Don't cache statement
- suppress_use - suppress the generation of 'USE' statements
- errcode - the error code of the query
-
- DESCRIPTION
- Creates an event for binlogging
- The value for `errcode' should be supplied by caller.
-*/
-Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length, bool using_trans,
- bool direct, bool suppress_use, int errcode)
-
- :Log_event(thd_arg,
- (thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
- 0) |
- (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0),
- using_trans),
- data_buf(0), query(query_arg), catalog(thd_arg->catalog),
- db(thd_arg->db.str), q_len((uint32) query_length),
- thread_id(thd_arg->thread_id),
- /* save the original thread id; we already know the server id */
- slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
- flags2_inited(1), sql_mode_inited(1), charset_inited(1),
- sql_mode(thd_arg->variables.sql_mode),
- auto_increment_increment(thd_arg->variables.auto_increment_increment),
- auto_increment_offset(thd_arg->variables.auto_increment_offset),
- lc_time_names_number(thd_arg->variables.lc_time_names->number),
- charset_database_number(0),
- table_map_for_update((ulonglong)thd_arg->table_map_for_update),
- master_data_written(0)
-{
- time_t end_time;
-
-#ifdef WITH_WSREP
- /*
- If Query_log_event will contain non trans keyword (not BEGIN, COMMIT,
- SAVEPOINT or ROLLBACK) we disable PA for this transaction.
- */
- if (WSREP_ON && !is_trans_keyword())
- thd->wsrep_PA_safe= false;
-#endif /* WITH_WSREP */
-
- memset(&user, 0, sizeof(user));
- memset(&host, 0, sizeof(host));
-
- error_code= errcode;
-
- end_time= my_time(0);
- exec_time = (ulong) (end_time - thd_arg->start_time);
- /**
- @todo this means that if we have no catalog, then it is replicated
- as an existing catalog of length zero. is that safe? /sven
- */
- catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
- /* status_vars_len is set just before writing the event */
- db_len = (db) ? (uint32) strlen(db) : 0;
- if (thd_arg->variables.collation_database != thd_arg->db_charset)
- charset_database_number= thd_arg->variables.collation_database->number;
-
- /*
- We only replicate over the bits of flags2 that we need: the rest
- are masked out by "& OPTIONS_WRITTEN_TO_BINLOG".
-
- We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After
- fixing BUG#26395, we always write BEGIN and COMMIT around all
- transactions (even single statements in autocommit mode). This is
- so that replication from non-transactional to transactional table
- and error recovery from XA to non-XA table should work as
- expected. The BEGIN/COMMIT are added in log.cc. However, there is
- one exception: MyISAM bypasses log.cc and writes directly to the
- binlog. So if autocommit is off, master has MyISAM, and slave has
- a transactional engine, then the slave will just see one long
- never-ending transaction. The only way to bypass explicit
- BEGIN/COMMIT in the binlog is by using a non-transactional table.
- So setting AUTOCOMMIT=1 will make this work as expected.
-
- Note: explicitly replicate AUTOCOMMIT=1 from master. We do not
- assume AUTOCOMMIT=1 on slave; the slave still reads the state of
- the autocommit flag as written by the master to the binlog. This
- behavior may change after WL#4162 has been implemented.
- */
- flags2= (uint32) (thd_arg->variables.option_bits &
- (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT));
- DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256);
- DBUG_ASSERT(thd_arg->variables.character_set_client->mbminlen == 1);
- int2store(charset, thd_arg->variables.character_set_client->number);
- int2store(charset+2, thd_arg->variables.collation_connection->number);
- int2store(charset+4, thd_arg->variables.collation_server->number);
- if (thd_arg->time_zone_used)
- {
- /*
- Note that our event becomes dependent on the Time_zone object
- representing the time zone. Fortunately such objects are never deleted
- or changed during mysqld's lifetime.
- */
- time_zone_len= thd_arg->variables.time_zone->get_name()->length();
- time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
- }
- else
- time_zone_len= 0;
-
- LEX *lex= thd->lex;
- /*
- Defines that the statement will be written directly to the binary log
- without being wrapped by a BEGIN...COMMIT. Otherwise, the statement
- will be written to either the trx-cache or stmt-cache.
-
- Note that a cache will not be used if the parameter direct is TRUE.
- */
- bool use_cache= FALSE;
- /*
- TRUE defines that the trx-cache must be used and by consequence the
- use_cache is TRUE.
-
- Note that a cache will not be used if the parameter direct is TRUE.
- */
- bool trx_cache= FALSE;
- cache_type= Log_event::EVENT_INVALID_CACHE;
-
- if (!direct)
- {
- switch (lex->sql_command)
- {
- case SQLCOM_DROP_TABLE:
- case SQLCOM_DROP_SEQUENCE:
- use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
- break;
-
- case SQLCOM_CREATE_TABLE:
- case SQLCOM_CREATE_SEQUENCE:
- /*
- If we are using CREATE ... SELECT or if we are a slave
- executing BEGIN...COMMIT (generated by CREATE...SELECT) we
- have to use the transactional cache to ensure we don't
- calculate any checksum for the CREATE part.
- */
- trx_cache= (lex->first_select_lex()->item_list.elements &&
- thd->is_current_stmt_binlog_format_row()) ||
- (thd->variables.option_bits & OPTION_GTID_BEGIN);
- use_cache= (lex->tmp_table() &&
- thd->in_multi_stmt_transaction_mode()) || trx_cache;
- break;
- case SQLCOM_SET_OPTION:
- if (lex->autocommit)
- use_cache= trx_cache= FALSE;
- else
- use_cache= TRUE;
- break;
- case SQLCOM_RELEASE_SAVEPOINT:
- case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- case SQLCOM_SAVEPOINT:
- use_cache= trx_cache= TRUE;
- break;
- default:
- use_cache= sqlcom_can_generate_row_events(thd);
- break;
- }
- }
-
- if (!use_cache || direct)
- {
- cache_type= Log_event::EVENT_NO_CACHE;
- }
- else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) ||
- thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(),
- thd->variables.binlog_direct_non_trans_update,
- trans_has_updated_trans_table(thd),
- thd->tx_isolation))
- cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
- else
- cache_type= Log_event::EVENT_STMT_CACHE;
- DBUG_ASSERT(cache_type != Log_event::EVENT_INVALID_CACHE);
- DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %llu cache_tye: %d",
- (ulong) flags2, sql_mode, cache_type));
-}
-
-Query_compressed_log_event::Query_compressed_log_event(THD* thd_arg, const char* query_arg,
- ulong query_length, bool using_trans,
- bool direct, bool suppress_use, int errcode)
- :Query_log_event(thd_arg, query_arg, query_length, using_trans, direct,
- suppress_use, errcode),
- query_buf(0)
-{
-
-}
-#endif /* MYSQL_CLIENT */
/* 2 utility functions for the next method */
@@ -5136,962 +1954,10 @@ Query_log_event::begin_event(String *packet, ulong ev_offset,
}
-#ifdef MYSQL_CLIENT
-/**
- Query_log_event::print().
-
- @todo
- print the catalog ??
-*/
-bool Query_log_event::print_query_header(IO_CACHE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- // TODO: print the catalog ??
- char buff[64], *end; // Enough for SET TIMESTAMP
- bool different_db= 1;
- uint32 tmp;
-
- if (!print_event_info->short_form)
- {
- if (print_header(file, print_event_info, FALSE) ||
- my_b_printf(file,
- "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
- get_type_str(), (ulong) thread_id, (ulong) exec_time,
- error_code))
- goto err;
- }
-
- if ((flags & LOG_EVENT_SUPPRESS_USE_F))
- {
- if (!is_trans_keyword())
- print_event_info->db[0]= '\0';
- }
- else if (db)
- {
- different_db= memcmp(print_event_info->db, db, db_len + 1);
- if (different_db)
- memcpy(print_event_info->db, db, db_len + 1);
- if (db[0] && different_db)
- if (my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter))
- goto err;
- }
-
- end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
- if (when_sec_part && when_sec_part <= TIME_MAX_SECOND_PART)
- {
- *end++= '.';
- end=int10_to_str(when_sec_part, end, 10);
- }
- end= strmov(end, print_event_info->delimiter);
- *end++='\n';
- if (my_b_write(file, (uchar*) buff, (uint) (end-buff)))
- goto err;
- if ((!print_event_info->thread_id_printed ||
- ((flags & LOG_EVENT_THREAD_SPECIFIC_F) &&
- thread_id != print_event_info->thread_id)))
- {
- // If --short-form, print deterministic value instead of pseudo_thread_id.
- if (my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
- short_form ? 999999999 : (ulong)thread_id,
- print_event_info->delimiter))
- goto err;
- print_event_info->thread_id= thread_id;
- print_event_info->thread_id_printed= 1;
- }
-
- /*
- If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
- print (remember we don't produce mixed relay logs so there cannot be
- 5.0 events before that one so there is nothing to reset).
- */
- if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
- {
- /* tmp is a bitmask of bits which have changed. */
- if (likely(print_event_info->flags2_inited))
- /* All bits which have changed */
- tmp= (print_event_info->flags2) ^ flags2;
- else /* that's the first Query event we read */
- {
- print_event_info->flags2_inited= 1;
- tmp= ~((uint32)0); /* all bits have changed */
- }
-
- if (unlikely(tmp)) /* some bits have changed */
- {
- bool need_comma= 0;
- if (my_b_write_string(file, "SET ") ||
- print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
- "@@session.foreign_key_checks", &need_comma)||
- print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
- "@@session.sql_auto_is_null", &need_comma) ||
- print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
- "@@session.unique_checks", &need_comma) ||
- print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
- "@@session.autocommit", &need_comma) ||
- print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
- ~flags2,
- "@@session.check_constraint_checks", &need_comma) ||
- my_b_printf(file,"%s\n", print_event_info->delimiter))
- goto err;
- print_event_info->flags2= flags2;
- }
- }
-
- /*
- Now the session variables;
- it's more efficient to pass SQL_MODE as a number instead of a
- comma-separated list.
- FOREIGN_KEY_CHECKS, SQL_AUTO_IS_NULL, UNIQUE_CHECKS are session-only
- variables (they have no global version; they're not listed in
- sql_class.h), The tests below work for pure binlogs or pure relay
- logs. Won't work for mixed relay logs but we don't create mixed
- relay logs (that is, there is no relay log with a format change
- except within the 3 first events, which mysqlbinlog handles
- gracefully). So this code should always be good.
- */
-
- if (likely(sql_mode_inited) &&
- (unlikely(print_event_info->sql_mode != sql_mode ||
- !print_event_info->sql_mode_inited)))
- {
- char llbuff[22];
- if (my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
- ullstr(sql_mode, llbuff), print_event_info->delimiter))
- goto err;
- print_event_info->sql_mode= sql_mode;
- print_event_info->sql_mode_inited= 1;
- }
- if (print_event_info->auto_increment_increment != auto_increment_increment ||
- print_event_info->auto_increment_offset != auto_increment_offset)
- {
- if (my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
- auto_increment_increment,auto_increment_offset,
- print_event_info->delimiter))
- goto err;
- print_event_info->auto_increment_increment= auto_increment_increment;
- print_event_info->auto_increment_offset= auto_increment_offset;
- }
-
- /* TODO: print the catalog when we feature SET CATALOG */
-
- if (likely(charset_inited) &&
- (unlikely(!print_event_info->charset_inited ||
- memcmp(print_event_info->charset, charset, 6))))
- {
- CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
- if (cs_info)
- {
- /* for mysql client */
- if (my_b_printf(file, "/*!\\C %s */%s\n",
- cs_info->csname, print_event_info->delimiter))
- goto err;
- }
- if (my_b_printf(file,"SET "
- "@@session.character_set_client=%d,"
- "@@session.collation_connection=%d,"
- "@@session.collation_server=%d"
- "%s\n",
- uint2korr(charset),
- uint2korr(charset+2),
- uint2korr(charset+4),
- print_event_info->delimiter))
- goto err;
- memcpy(print_event_info->charset, charset, 6);
- print_event_info->charset_inited= 1;
- }
- if (time_zone_len)
- {
- if (memcmp(print_event_info->time_zone_str,
- time_zone_str, time_zone_len+1))
- {
- if (my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
- time_zone_str, print_event_info->delimiter))
- goto err;
- memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
- }
- }
- if (lc_time_names_number != print_event_info->lc_time_names_number)
- {
- if (my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
- lc_time_names_number, print_event_info->delimiter))
- goto err;
- print_event_info->lc_time_names_number= lc_time_names_number;
- }
- if (charset_database_number != print_event_info->charset_database_number)
- {
- if (charset_database_number)
- {
- if (my_b_printf(file, "SET @@session.collation_database=%d%s\n",
- charset_database_number, print_event_info->delimiter))
- goto err;
- }
- else if (my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
- print_event_info->delimiter))
- goto err;
- print_event_info->charset_database_number= charset_database_number;
- }
- return 0;
-
-err:
- return 1;
-}
-
-
-bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this);
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_write().
- */
- DBUG_EXECUTE_IF ("simulate_file_write_error",
- {(&cache)->write_pos= (&cache)->write_end- 500;});
- if (print_query_header(&cache, print_event_info))
- goto err;
- if (!is_flashback)
- {
- if (my_b_write(&cache, (uchar*) query, q_len) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else // is_flashback == 1
- {
- if (strcmp("BEGIN", query) == 0)
- {
- if (my_b_write(&cache, (uchar*) "COMMIT", 6) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else if (strcmp("COMMIT", query) == 0)
- {
- if (my_b_write(&cache, (uchar*) "BEGIN", 5) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- }
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Query_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-int Query_log_event::do_apply_event(rpl_group_info *rgi)
-{
- return do_apply_event(rgi, query, q_len);
-}
-
-/**
- Compare if two errors should be regarded as equal.
- This is to handle the case when you can get slightly different errors
- on master and slave for the same thing.
- @param
- expected_error Error we got on master
- actual_error Error we got on slave
-
- @return
- 1 Errors are equal
- 0 Errors are different
-*/
-
-bool test_if_equal_repl_errors(int expected_error, int actual_error)
-{
- if (expected_error == actual_error)
- return 1;
- switch (expected_error) {
- case ER_DUP_ENTRY:
- case ER_DUP_ENTRY_WITH_KEY_NAME:
- case ER_DUP_KEY:
- case ER_AUTOINC_READ_FAILED:
- return (actual_error == ER_DUP_ENTRY ||
- actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
- actual_error == ER_DUP_KEY ||
- actual_error == ER_AUTOINC_READ_FAILED ||
- actual_error == HA_ERR_AUTOINC_ERANGE);
- case ER_UNKNOWN_TABLE:
- return actual_error == ER_IT_IS_A_VIEW;
- default:
- break;
- }
- return 0;
-}
-
-
-/**
- @todo
- Compare the values of "affected rows" around here. Something
- like:
- @code
- if ((uint32) affected_in_event != (uint32) affected_on_slave)
- {
- sql_print_error("Slave: did not get the expected number of affected \
- rows running query from master - expected %d, got %d (this numbers \
- should have matched modulo 4294967296).", 0, ...);
- thd->query_error = 1;
- }
- @endcode
- We may also want an option to tell the slave to ignore "affected"
- mismatch. This mismatch could be implemented with a new ER_ code, and
- to ignore it you would use --slave-skip-errors...
-*/
-int Query_log_event::do_apply_event(rpl_group_info *rgi,
- const char *query_arg, uint32 q_len_arg)
-{
- int expected_error,actual_error= 0;
- Schema_specification_st db_options;
- uint64 sub_id= 0;
- void *hton= NULL;
- rpl_gtid gtid;
- Relay_log_info const *rli= rgi->rli;
- Rpl_filter *rpl_filter= rli->mi->rpl_filter;
- bool current_stmt_is_commit;
- DBUG_ENTER("Query_log_event::do_apply_event");
-
- /*
- Colleagues: please never free(thd->catalog) in MySQL. This would
- lead to bugs as here thd->catalog is a part of an alloced block,
- not an entire alloced block (see
- Query_log_event::do_apply_event()). Same for thd->db. Thank
- you.
- */
- thd->catalog= catalog_len ? (char *) catalog : (char *)"";
-
- size_t valid_len= Well_formed_prefix(system_charset_info,
- db, db_len, NAME_LEN).length();
-
- if (valid_len != db_len)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid database name in Query event.");
- thd->is_slave_error= true;
- goto end;
- }
-
- set_thd_db(thd, rpl_filter, db, db_len);
-
- /*
- Setting the character set and collation of the current database thd->db.
- */
- load_db_opt_by_name(thd, thd->db.str, &db_options);
- if (db_options.default_table_charset)
- thd->db_charset= db_options.default_table_charset;
- thd->variables.auto_increment_increment= auto_increment_increment;
- thd->variables.auto_increment_offset= auto_increment_offset;
-
- DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
-
- thd->clear_error(1);
- current_stmt_is_commit= is_commit();
-
- DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
- rgi->slave_close_thread_tables(thd);
-
- /*
- Note: We do not need to execute reset_one_shot_variables() if this
- db_ok() test fails.
- Reason: The db stored in binlog events is the same for SET and for
- its companion query. If the SET is ignored because of
- db_ok(), the companion query will also be ignored, and if
- the companion query is ignored in the db_ok() test of
- ::do_apply_event(), then the companion SET also have so
- we don't need to reset_one_shot_variables().
- */
- if (is_trans_keyword() || rpl_filter->db_ok(thd->db.str))
- {
- thd->set_time(when, when_sec_part);
- thd->set_query_and_id((char*)query_arg, q_len_arg,
- thd->charset(), next_query_id());
- thd->variables.pseudo_thread_id= thread_id; // for temp tables
- DBUG_PRINT("query",("%s", thd->query()));
-
- if (unlikely(!(expected_error= error_code)) ||
- ignored_error_code(expected_error) ||
- !unexpected_error_code(expected_error))
- {
- thd->slave_expected_error= expected_error;
- if (flags2_inited)
- /*
- all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
- must take their value from flags2.
- */
- thd->variables.option_bits= flags2|(thd->variables.option_bits & ~OPTIONS_WRITTEN_TO_BIN_LOG);
- /*
- else, we are in a 3.23/4.0 binlog; we previously received a
- Rotate_log_event which reset thd->variables.option_bits and sql_mode etc, so
- nothing to do.
- */
- /*
- We do not replicate MODE_NO_DIR_IN_CREATE. That is, if the master is a
- slave which runs with SQL_MODE=MODE_NO_DIR_IN_CREATE, this should not
- force us to ignore the dir too. Imagine you are a ring of machines, and
- one has a disk problem so that you temporarily need
- MODE_NO_DIR_IN_CREATE on this machine; you don't want it to propagate
- elsewhere (you don't want all slaves to start ignoring the dirs).
- */
- if (sql_mode_inited)
- thd->variables.sql_mode=
- (sql_mode_t) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
- (sql_mode & ~(sql_mode_t) MODE_NO_DIR_IN_CREATE));
- if (charset_inited)
- {
- rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;
- if (sql_info->cached_charset_compare(charset))
- {
- /* Verify that we support the charsets found in the event. */
- if (!(thd->variables.character_set_client=
- get_charset(uint2korr(charset), MYF(MY_WME))) ||
- !(thd->variables.collation_connection=
- get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
- !(thd->variables.collation_server=
- get_charset(uint2korr(charset+4), MYF(MY_WME))))
- {
- /*
- We updated the thd->variables with nonsensical values (0). Let's
- set them to something safe (i.e. which avoids crash), and we'll
- stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
- ignore this error).
- */
- set_slave_thread_default_charset(thd, rgi);
- goto compare_errors;
- }
- thd->update_charset(); // for the charset change to take effect
- /*
- Reset thd->query_string.cs to the newly set value.
- Note, there is a small flaw here. For a very short time frame
- if the new charset is different from the old charset and
- if another thread executes "SHOW PROCESSLIST" after
- the above thd->set_query_and_id() and before this thd->set_query(),
- and if the current query has some non-ASCII characters,
- the another thread may see some '?' marks in the PROCESSLIST
- result. This should be acceptable now. This is a reminder
- to fix this if any refactoring happens here sometime.
- */
- thd->set_query((char*) query_arg, q_len_arg, thd->charset());
- }
- }
- if (time_zone_len)
- {
- String tmp(time_zone_str, time_zone_len, &my_charset_bin);
- if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
- {
- my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
- thd->variables.time_zone= global_system_variables.time_zone;
- goto compare_errors;
- }
- }
- if (lc_time_names_number)
- {
- if (!(thd->variables.lc_time_names=
- my_locale_by_number(lc_time_names_number)))
- {
- my_printf_error(ER_UNKNOWN_ERROR,
- "Unknown locale: '%d'", MYF(0), lc_time_names_number);
- thd->variables.lc_time_names= &my_locale_en_US;
- goto compare_errors;
- }
- }
- else
- thd->variables.lc_time_names= &my_locale_en_US;
- if (charset_database_number)
- {
- CHARSET_INFO *cs;
- if (!(cs= get_charset(charset_database_number, MYF(0))))
- {
- char buf[20];
- int10_to_str((int) charset_database_number, buf, -10);
- my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
- goto compare_errors;
- }
- thd->variables.collation_database= cs;
- }
- else
- thd->variables.collation_database= thd->db_charset;
-
- {
- const CHARSET_INFO *cs= thd->charset();
- /*
- We cannot ask for parsing a statement using a character set
- without state_maps (parser internal data).
- */
- if (!cs->state_map)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "character_set cannot be parsed");
- thd->is_slave_error= true;
- goto end;
- }
- }
-
- /*
- Record any GTID in the same transaction, so slave state is
- transactionally consistent.
- */
- if (current_stmt_is_commit)
- {
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- if (rgi->gtid_pending)
- {
- sub_id= rgi->gtid_sub_id;
- rgi->gtid_pending= false;
-
- gtid= rgi->current_gtid;
- if (unlikely(rpl_global_gtid_slave_state->record_gtid(thd, &gtid,
- sub_id,
- true, false,
- &hton)))
- {
- int errcode= thd->get_stmt_da()->sql_errno();
- if (!is_parallel_retry_error(rgi, errcode))
- rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
- rgi->gtid_info(),
- "Error during COMMIT: failed to update GTID state in "
- "%s.%s: %d: %s",
- "mysql", rpl_gtid_slave_state_table_name.str,
- errcode,
- thd->get_stmt_da()->message());
- sub_id= 0;
- thd->is_slave_error= 1;
- goto end;
- }
- }
- }
-
- thd->table_map_for_update= (table_map)table_map_for_update;
- thd->set_invoker(&user, &host);
- /*
- Flag if we need to rollback the statement transaction on
- slave if it by chance succeeds.
- If we expected a non-zero error code and get nothing and,
- it is a concurrency issue or ignorable issue, effects
- of the statement should be rolled back.
- */
- if (unlikely(expected_error) &&
- (ignored_error_code(expected_error) ||
- concurrency_error_code(expected_error)))
- {
- thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR;
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- }
- /* Execute the query (note that we bypass dispatch_command()) */
- Parser_state parser_state;
- if (!parser_state.init(thd, thd->query(), thd->query_length()))
- {
- DBUG_ASSERT(thd->m_digest == NULL);
- thd->m_digest= & thd->m_digest_state;
- DBUG_ASSERT(thd->m_statement_psi == NULL);
- thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
- stmt_info_rpl.m_key,
- thd->db.str, thd->db.length,
- thd->charset());
- THD_STAGE_INFO(thd, stage_init);
- MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length());
- if (thd->m_digest != NULL)
- thd->m_digest->reset(thd->m_token_array, max_digest_length);
-
- if (thd->slave_thread)
- {
- /*
- To be compatible with previous releases, the slave thread uses the global
- log_slow_disabled_statements value, wich can be changed dynamically, so we
- have to set the sql_log_slow respectively.
- */
- thd->variables.sql_log_slow= !MY_TEST(global_system_variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE);
- }
-
- mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
- FALSE, FALSE);
- /* Finalize server status flags after executing a statement. */
- thd->update_server_status();
- log_slow_statement(thd);
- thd->lex->restore_set_statement_var();
- }
-
- thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR;
- }
- else
- {
- /*
- The query got a really bad error on the master (thread killed etc),
- which could be inconsistent. Parse it to test the table names: if the
- replicate-*-do|ignore-table rules say "this query must be ignored" then
- we exit gracefully; otherwise we warn about the bad error and tell DBA
- to check/fix it.
- */
- if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
- thd->clear_error(1);
- else
- {
- rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
- "\
-Query partially completed on the master (error on master: %d) \
-and was aborted. There is a chance that your master is inconsistent at this \
-point. If you are sure that your master is ok, run this query manually on the \
-slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \
-START SLAVE; . Query: '%s'", expected_error, thd->query());
- thd->is_slave_error= 1;
- }
- goto end;
- }
-
- /* If the query was not ignored, it is printed to the general log */
- if (likely(!thd->is_error()) ||
- thd->get_stmt_da()->sql_errno() != ER_SLAVE_IGNORED_TABLE)
- general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
- else
- {
- /*
- Bug#54201: If we skip an INSERT query that uses auto_increment, then we
- should reset any @@INSERT_ID set by an Intvar_log_event associated with
- the query; otherwise the @@INSERT_ID will linger until the next INSERT
- that uses auto_increment and may affect extra triggers on the slave etc.
-
- We reset INSERT_ID unconditionally; it is probably cheaper than
- checking if it is necessary.
- */
- thd->auto_inc_intervals_forced.empty();
- }
-
-compare_errors:
- /*
- In the slave thread, we may sometimes execute some DROP / * 40005
- TEMPORARY * / TABLE that come from parts of binlogs (likely if we
- use RESET SLAVE or CHANGE MASTER TO), while the temporary table
- has already been dropped. To ignore such irrelevant "table does
- not exist errors", we silently clear the error if TEMPORARY was used.
- */
- if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
- thd->lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
- thd->lex->tmp_table() &&
- thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
- !expected_error)
- thd->get_stmt_da()->reset_diagnostics_area();
- /*
- If we expected a non-zero error code, and we don't get the same error
- code, and it should be ignored or is related to a concurrency issue.
- */
- actual_error= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
- DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
- expected_error, actual_error));
-
- if ((unlikely(expected_error) &&
- !test_if_equal_repl_errors(expected_error, actual_error) &&
- !concurrency_error_code(expected_error)) &&
- !ignored_error_code(actual_error) &&
- !ignored_error_code(expected_error))
- {
- rli->report(ERROR_LEVEL, 0, rgi->gtid_info(),
- "Query caused different errors on master and slave. "
- "Error on master: message (format)='%s' error code=%d ; "
- "Error on slave: actual message='%s', error code=%d. "
- "Default database: '%s'. Query: '%s'",
- ER_THD(thd, expected_error),
- expected_error,
- actual_error ? thd->get_stmt_da()->message() : "no error",
- actual_error,
- print_slave_db_safe(db), query_arg);
- thd->is_slave_error= 1;
- }
- /*
- If we get the same error code as expected and it is not a concurrency
- issue, or should be ignored.
- */
- else if ((test_if_equal_repl_errors(expected_error, actual_error) &&
- !concurrency_error_code(expected_error)) ||
- ignored_error_code(actual_error))
- {
- DBUG_PRINT("info",("error ignored"));
- thd->clear_error(1);
- if (actual_error == ER_QUERY_INTERRUPTED ||
- actual_error == ER_CONNECTION_KILLED)
- thd->reset_killed();
- }
- /*
- Other cases: mostly we expected no error and get one.
- */
- else if (unlikely(thd->is_slave_error || thd->is_fatal_error))
- {
- if (!is_parallel_retry_error(rgi, actual_error))
- rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(),
- "Error '%s' on query. Default database: '%s'. Query: '%s'",
- (actual_error ? thd->get_stmt_da()->message() :
- "unexpected success or fatal error"),
- thd->get_db(), query_arg);
- thd->is_slave_error= 1;
-#ifdef WITH_WSREP
- if (wsrep_thd_is_toi(thd) && wsrep_must_ignore_error(thd))
- {
- thd->clear_error(1);
- thd->killed= NOT_KILLED;
- thd->wsrep_has_ignored_error= true;
- }
-#endif /* WITH_WSREP */
- }
-
- /*
- TODO: compare the values of "affected rows" around here. Something
- like:
- if ((uint32) affected_in_event != (uint32) affected_on_slave)
- {
- sql_print_error("Slave: did not get the expected number of affected \
- rows running query from master - expected %d, got %d (this numbers \
- should have matched modulo 4294967296).", 0, ...);
- thd->is_slave_error = 1;
- }
- We may also want an option to tell the slave to ignore "affected"
- mismatch. This mismatch could be implemented with a new ER_ code, and
- to ignore it you would use --slave-skip-errors...
-
- To do the comparison we need to know the value of "affected" which the
- above mysql_parse() computed. And we need to know the value of
- "affected" in the master's binlog. Both will be implemented later. The
- important thing is that we now have the format ready to log the values
- of "affected" in the binlog. So we can release 5.0.0 before effectively
- logging "affected" and effectively comparing it.
- */
- } /* End of if (db_ok(... */
-
- {
- /**
- The following failure injecion works in cooperation with tests
- setting @@global.debug= 'd,stop_slave_middle_group'.
- The sql thread receives the killed status and will proceed
- to shutdown trying to finish incomplete events group.
- */
- DBUG_EXECUTE_IF("stop_slave_middle_group",
- if (!current_stmt_is_commit && is_begin() == 0)
- {
- if (thd->transaction.all.modified_non_trans_table)
- const_cast<Relay_log_info*>(rli)->abort_slave= 1;
- };);
- }
-
-end:
- if (unlikely(sub_id && !thd->is_slave_error))
- rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
-
- /*
- Probably we have set thd->query, thd->db, thd->catalog to point to places
- in the data_buf of this event. Now the event is going to be deleted
- probably, so data_buf will be freed, so the thd->... listed above will be
- pointers to freed memory.
- So we must set them to 0, so that those bad pointers values are not later
- used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
- don't suffer from these assignments to 0 as DROP TEMPORARY
- TABLE uses the db.table syntax.
- */
- thd->catalog= 0;
- thd->set_db(&null_clex_str); /* will free the current database */
- thd->reset_query();
- DBUG_PRINT("info", ("end: query= 0"));
-
- /* Mark the statement completed. */
- MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
- thd->m_statement_psi= NULL;
- thd->m_digest= NULL;
-
- /*
- As a disk space optimization, future masters will not log an event for
- LAST_INSERT_ID() if that function returned 0 (and thus they will be able
- to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt
- variable by (THD->first_successful_insert_id_in_prev_stmt > 0) ; with the
- resetting below we are ready to support that.
- */
- thd->first_successful_insert_id_in_prev_stmt_for_binlog= 0;
- thd->first_successful_insert_id_in_prev_stmt= 0;
- thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- DBUG_RETURN(thd->is_slave_error);
-}
-
-Log_event::enum_skip_reason
-Query_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Query_log_event::do_shall_skip");
- DBUG_PRINT("debug", ("query: '%s' q_len: %d", query, q_len));
- DBUG_ASSERT(query && q_len > 0);
- DBUG_ASSERT(thd == rgi->thd);
-
- /*
- An event skipped due to @@skip_replication must not be counted towards the
- number of events to be skipped due to @@sql_slave_skip_counter.
- */
- if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
-
- if (rli->slave_skip_counter > 0)
- {
- if (is_begin())
- {
- thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN;
- DBUG_RETURN(Log_event::continue_group(rgi));
- }
-
- if (is_commit() || is_rollback())
- {
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
- }
- }
-#ifdef WITH_WSREP
- else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 &&
- thd->wsrep_mysql_replicated > 0 &&
- (is_begin() || is_commit()))
- {
- if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
- {
- WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
- }
- else
- {
- thd->wsrep_mysql_replicated = 0;
- }
- }
-#endif
- DBUG_RETURN(Log_event::do_shall_skip(rgi));
-}
-
-
-bool
-Query_log_event::peek_is_commit_rollback(const char *event_start,
- size_t event_len,
- enum enum_binlog_checksum_alg checksum_alg)
-{
- if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
- {
- if (event_len > BINLOG_CHECKSUM_LEN)
- event_len-= BINLOG_CHECKSUM_LEN;
- else
- event_len= 0;
- }
- else
- DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
- checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
-
- if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
- return false;
- return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
- !memcmp(event_start + (event_len-9), "\0ROLLBACK", 9);
-}
-
-#endif
-
-
/**************************************************************************
Start_log_event_v3 methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Start_log_event_v3::Start_log_event_v3()
- :Log_event(), created(0), binlog_version(BINLOG_VERSION),
- dont_set_created(0)
-{
- memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
-}
-#endif
-
-/*
- Start_log_event_v3::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Start_log_event_v3::pack_info(Protocol *protocol)
-{
- char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
- pos= strmov(buf, "Server ver: ");
- pos= strmov(pos, server_version);
- pos= strmov(pos, ", Binlog ver: ");
- pos= int10_to_str(binlog_version, pos, 10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
-
-/*
- Start_log_event_v3::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- DBUG_ENTER("Start_log_event_v3::print");
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
- binlog_version, server_version) ||
- print_timestamp(&cache))
- goto err;
- if (created)
- if (my_b_printf(&cache," at startup"))
- goto err;
- if (my_b_printf(&cache, "\n"))
- goto err;
- if (flags & LOG_EVENT_BINLOG_IN_USE_F)
- if (my_b_printf(&cache,
- "# Warning: this binlog is either in use or was not "
- "closed properly.\n"))
- goto err;
- }
- if (!is_artificial_event() && created)
- {
-#ifdef WHEN_WE_HAVE_THE_RESET_CONNECTION_SQL_COMMAND
- /*
- This is for mysqlbinlog: like in replication, we want to delete the stale
- tmp files left by an unclean shutdown of mysqld (temporary tables)
- and rollback unfinished transaction.
- Probably this can be done with RESET CONNECTION (syntax to be defined).
- */
- if (my_b_printf(&cache,"RESET CONNECTION%s\n",
- print_event_info->delimiter))
- goto err;
-#else
- if (my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter))
- goto err;
-#endif
- }
- if (temp_buf &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- !print_event_info->short_form)
- {
- /* BINLOG is matched with the delimiter below on the same level */
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS;
- if (do_print_encoded)
- my_b_printf(&cache, "BINLOG '\n");
-
- if (print_base64(&cache, print_event_info, do_print_encoded))
- goto err;
-
- if (do_print_encoded)
- my_b_printf(&cache, "'%s\n", print_event_info->delimiter);
-
- print_event_info->printed_fd_event= TRUE;
- }
- DBUG_RETURN(cache.flush_data());
-err:
- DBUG_RETURN(1);
-}
-#endif /* MYSQL_CLIENT */
-
-/*
- Start_log_event_v3::Start_log_event_v3()
-*/
Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
const Format_description_log_event
@@ -6114,108 +1980,6 @@ Start_log_event_v3::Start_log_event_v3(const char* buf, uint event_len,
}
-/*
- Start_log_event_v3::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Start_log_event_v3::write()
-{
- char buff[START_V3_HEADER_LEN];
- int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
- memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
- if (!dont_set_created)
- created= get_time(); // this sets when and when_sec_part as a side effect
- int4store(buff + ST_CREATED_OFFSET,created);
- return write_header(sizeof(buff)) ||
- write_data(buff, sizeof(buff)) ||
- write_footer();
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/**
- Start_log_event_v3::do_apply_event() .
- The master started
-
- IMPLEMENTATION
- - To handle the case where the master died without having time to write
- DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is
- TODO), we clean up all temporary tables that we got, if we are sure we
- can (see below).
-
- @todo
- - Remove all active user locks.
- Guilhem 2003-06: this is true but not urgent: the worst it can cause is
- the use of a bit of memory for a user lock which will not be used
- anymore. If the user lock is later used, the old one will be released. In
- other words, no deadlock problem.
-*/
-
-int Start_log_event_v3::do_apply_event(rpl_group_info *rgi)
-{
- DBUG_ENTER("Start_log_event_v3::do_apply_event");
- int error= 0;
- Relay_log_info *rli= rgi->rli;
-
- switch (binlog_version)
- {
- case 3:
- case 4:
- /*
- This can either be 4.x (then a Start_log_event_v3 is only at master
- startup so we are sure the master has restarted and cleared his temp
- tables; the event always has 'created'>0) or 5.0 (then we have to test
- 'created').
- */
- if (created)
- {
- rli->close_temporary_tables();
-
- /*
- The following is only false if we get here with a BINLOG statement
- */
- if (rli->mi)
- cleanup_load_tmpdir(&rli->mi->cmp_connection_name);
- }
- break;
-
- /*
- Now the older formats; in that case load_tmpdir is cleaned up by the I/O
- thread.
- */
- case 1:
- if (strncmp(rli->relay_log.description_event_for_exec->server_version,
- "3.23.57",7) >= 0 && created)
- {
- /*
- Can distinguish, based on the value of 'created': this event was
- generated at master startup.
- */
- rli->close_temporary_tables();
- }
- /*
- Otherwise, can't distinguish a Start_log_event generated at
- master startup and one generated by master FLUSH LOGS, so cannot
- be sure temp tables have to be dropped. So do nothing.
- */
- break;
- default:
- /*
- This case is not expected. It can be either an event corruption or an
- unsupported binary log version.
- */
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Binlog version not supported");
- DBUG_RETURN(1);
- }
- DBUG_RETURN(error);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
/***************************************************************************
Format_description_log_event methods
****************************************************************************/
@@ -6465,159 +2229,6 @@ Format_description_log_event(const char* buf,
DBUG_VOID_RETURN;
}
-#ifndef MYSQL_CLIENT
-bool Format_description_log_event::write()
-{
- bool ret;
- bool no_checksum;
- /*
- We don't call Start_log_event_v3::write() because this would make 2
- my_b_safe_write().
- */
- uchar buff[START_V3_HEADER_LEN+1];
- size_t rec_size= sizeof(buff) + BINLOG_CHECKSUM_ALG_DESC_LEN +
- number_of_event_types;
- int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
- memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
- if (!dont_set_created)
- created= get_time();
- int4store(buff + ST_CREATED_OFFSET,created);
- buff[ST_COMMON_HEADER_LEN_OFFSET]= common_header_len;
- /*
- if checksum is requested
- record the checksum-algorithm descriptor next to
- post_header_len vector which will be followed by the checksum value.
- Master is supposed to trigger checksum computing by binlog_checksum_options,
- slave does it via marking the event according to
- FD_queue checksum_alg value.
- */
- compile_time_assert(BINLOG_CHECKSUM_ALG_DESC_LEN == 1);
-#ifdef DBUG_ASSERT_EXISTS
- data_written= 0; // to prepare for need_checksum assert
-#endif
- uint8 checksum_byte= (uint8)
- (need_checksum() ? checksum_alg : BINLOG_CHECKSUM_ALG_OFF);
- /*
- FD of checksum-aware server is always checksum-equipped, (V) is in,
- regardless of @@global.binlog_checksum policy.
- Thereby a combination of (A) == 0, (V) != 0 means
- it's the checksum-aware server's FD event that heads checksum-free binlog
- file.
- Here 0 stands for checksumming OFF to evaluate (V) as 0 is that case.
- A combination of (A) != 0, (V) != 0 denotes FD of the checksum-aware server
- heading the checksummed binlog.
- (A), (V) presence in FD of the checksum-aware server makes the event
- 1 + 4 bytes bigger comparing to the former FD.
- */
-
- if ((no_checksum= (checksum_alg == BINLOG_CHECKSUM_ALG_OFF)))
- {
- checksum_alg= BINLOG_CHECKSUM_ALG_CRC32; // Forcing (V) room to fill anyway
- }
- ret= write_header(rec_size) ||
- write_data(buff, sizeof(buff)) ||
- write_data(post_header_len, number_of_event_types) ||
- write_data(&checksum_byte, sizeof(checksum_byte)) ||
- write_footer();
- if (no_checksum)
- checksum_alg= BINLOG_CHECKSUM_ALG_OFF;
- return ret;
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Format_description_log_event::do_apply_event(rpl_group_info *rgi)
-{
- int ret= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Format_description_log_event::do_apply_event");
-
- /*
- As a transaction NEVER spans on 2 or more binlogs:
- if we have an active transaction at this point, the master died
- while writing the transaction to the binary log, i.e. while
- flushing the binlog cache to the binlog. XA guarantees that master has
- rolled back. So we roll back.
- Note: this event could be sent by the master to inform us of the
- format of its binlog; in other words maybe it is not at its
- original place when it comes to us; we'll know this by checking
- log_pos ("artificial" events have log_pos == 0).
- */
- if (!is_artificial_event() && created && thd->transaction.all.ha_list)
- {
- /* This is not an error (XA is safe), just an information */
- rli->report(INFORMATION_LEVEL, 0, NULL,
- "Rolling back unfinished transaction (no COMMIT "
- "or ROLLBACK in relay log). A probable cause is that "
- "the master died while writing the transaction to "
- "its binary log, thus rolled back too.");
- rgi->cleanup_context(thd, 1);
- }
-
- /*
- If this event comes from ourselves, there is no cleaning task to
- perform, we don't call Start_log_event_v3::do_apply_event()
- (this was just to update the log's description event).
- */
- if (server_id != (uint32) global_system_variables.server_id)
- {
- /*
- If the event was not requested by the slave i.e. the master sent
- it while the slave asked for a position >4, the event will make
- rli->group_master_log_pos advance. Say that the slave asked for
- position 1000, and the Format_desc event's end is 96. Then in
- the beginning of replication rli->group_master_log_pos will be
- 0, then 96, then jump to first really asked event (which is
- >96). So this is ok.
- */
- ret= Start_log_event_v3::do_apply_event(rgi);
- }
-
- if (!ret)
- {
- /* Save the information describing this binlog */
- copy_crypto_data(rli->relay_log.description_event_for_exec);
- delete rli->relay_log.description_event_for_exec;
- rli->relay_log.description_event_for_exec= this;
- }
-
- DBUG_RETURN(ret);
-}
-
-int Format_description_log_event::do_update_pos(rpl_group_info *rgi)
-{
- if (server_id == (uint32) global_system_variables.server_id)
- {
- /*
- We only increase the relay log position if we are skipping
- events and do not touch any group_* variables, nor flush the
- relay log info. If there is a crash, we will have to re-skip
- the events again, but that is a minor issue.
-
- If we do not skip stepping the group log position (and the
- server id was changed when restarting the server), it might well
- be that we start executing at a position that is invalid, e.g.,
- at a Rows_log_event or a Query_log_event preceeded by a
- Intvar_log_event instead of starting at a Table_map_log_event or
- the Intvar_log_event respectively.
- */
- rgi->inc_event_relay_log_pos();
- return 0;
- }
- else
- {
- return Log_event::do_update_pos(rgi);
- }
-}
-
-Log_event::enum_skip_reason
-Format_description_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- return Log_event::EVENT_SKIP_NOT;
-}
-
-#endif
-
bool Format_description_log_event::start_decryption(Start_encryption_log_event* sele)
{
DBUG_ASSERT(crypto_data.scheme == 0);
@@ -6753,42 +2364,7 @@ Start_encryption_log_event::Start_encryption_log_event(
crypto_scheme= ~0; // invalid
}
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Start_encryption_log_event::do_apply_event(rpl_group_info* rgi)
-{
- return rgi->rli->relay_log.description_event_for_exec->start_decryption(this);
-}
-
-int Start_encryption_log_event::do_update_pos(rpl_group_info *rgi)
-{
- /*
- master never sends Start_encryption_log_event, any SELE that a slave
- might see was created locally in MYSQL_BIN_LOG::open() on the slave
- */
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-#endif
-#ifndef MYSQL_SERVER
-bool Start_encryption_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file);
- StringBuffer<1024> buf;
- buf.append(STRING_WITH_LEN("# Encryption scheme: "));
- buf.append_ulonglong(crypto_scheme);
- buf.append(STRING_WITH_LEN(", key_version: "));
- buf.append_ulonglong(key_version);
- buf.append(STRING_WITH_LEN(", nonce: "));
- buf.append_hex(nonce, BINLOG_NONCE_LENGTH);
- buf.append(STRING_WITH_LEN("\n# The rest of the binlog is encrypted!\n"));
- if (my_b_write(&cache, (uchar*)buf.ptr(), buf.length()))
- return 1;
- return (cache.flush_data());
-}
-#endif
/**************************************************************************
Load_log_event methods
General note about Load_log_event: the binlogging of LOAD DATA INFILE is
@@ -6806,252 +2382,6 @@ bool Start_encryption_log_event::print(FILE* file,
positions displayed in SHOW SLAVE STATUS then are fine too).
**************************************************************************/
-/*
- Load_log_event::print_query()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-bool Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
- String *buf, my_off_t *fn_start,
- my_off_t *fn_end, const char *qualify_db)
-{
- if (need_db && db && db_len)
- {
- buf->append(STRING_WITH_LEN("use "));
- append_identifier(thd, buf, db, db_len);
- buf->append(STRING_WITH_LEN("; "));
- }
-
- buf->append(STRING_WITH_LEN("LOAD DATA "));
-
- if (is_concurrent)
- buf->append(STRING_WITH_LEN("CONCURRENT "));
-
- if (fn_start)
- *fn_start= buf->length();
-
- if (check_fname_outside_temp_buf())
- buf->append(STRING_WITH_LEN("LOCAL "));
- buf->append(STRING_WITH_LEN("INFILE '"));
- buf->append_for_single_quote(fname, fname_len);
- buf->append(STRING_WITH_LEN("' "));
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- buf->append(STRING_WITH_LEN("REPLACE "));
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- buf->append(STRING_WITH_LEN("IGNORE "));
-
- buf->append(STRING_WITH_LEN("INTO"));
-
- if (fn_end)
- *fn_end= buf->length();
-
- buf->append(STRING_WITH_LEN(" TABLE "));
- if (qualify_db)
- {
- append_identifier(thd, buf, qualify_db, strlen(qualify_db));
- buf->append(STRING_WITH_LEN("."));
- }
- append_identifier(thd, buf, table_name, table_name_len);
-
- if (cs != NULL)
- {
- buf->append(STRING_WITH_LEN(" CHARACTER SET "));
- buf->append(cs, strlen(cs));
- }
-
- /* We have to create all optional fields as the default is not empty */
- buf->append(STRING_WITH_LEN(" FIELDS TERMINATED BY "));
- pretty_print_str(buf, sql_ex.field_term, sql_ex.field_term_len);
- if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
- buf->append(STRING_WITH_LEN(" OPTIONALLY "));
- buf->append(STRING_WITH_LEN(" ENCLOSED BY "));
- pretty_print_str(buf, sql_ex.enclosed, sql_ex.enclosed_len);
-
- buf->append(STRING_WITH_LEN(" ESCAPED BY "));
- pretty_print_str(buf, sql_ex.escaped, sql_ex.escaped_len);
-
- buf->append(STRING_WITH_LEN(" LINES TERMINATED BY "));
- pretty_print_str(buf, sql_ex.line_term, sql_ex.line_term_len);
- if (sql_ex.line_start_len)
- {
- buf->append(STRING_WITH_LEN(" STARTING BY "));
- pretty_print_str(buf, sql_ex.line_start, sql_ex.line_start_len);
- }
-
- if ((long) skip_lines > 0)
- {
- buf->append(STRING_WITH_LEN(" IGNORE "));
- buf->append_ulonglong(skip_lines);
- buf->append(STRING_WITH_LEN(" LINES "));
- }
-
- if (num_fields)
- {
- uint i;
- const char *field= fields;
- buf->append(STRING_WITH_LEN(" ("));
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- {
- /*
- Yes, the space and comma is reversed here. But this is mostly dead
- code, at most used when reading really old binlogs from old servers,
- so better just leave it as is...
- */
- buf->append(STRING_WITH_LEN(" ,"));
- }
- append_identifier(thd, buf, field, field_lens[i]);
- field+= field_lens[i] + 1;
- }
- buf->append(STRING_WITH_LEN(")"));
- }
- return 0;
-}
-
-
-void Load_log_event::pack_info(Protocol *protocol)
-{
- char query_buffer[1024];
- String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
-
- query_str.length(0);
- print_query(protocol->thd, TRUE, NULL, &query_str, 0, 0, NULL);
- protocol->store(query_str.ptr(), query_str.length(), &my_charset_bin);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-#ifndef MYSQL_CLIENT
-
-/*
- Load_log_event::write_data_header()
-*/
-
-bool Load_log_event::write_data_header()
-{
- char buf[LOAD_HEADER_LEN];
- int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id);
- int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
- int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
- buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
- buf[L_DB_LEN_OFFSET] = (char)db_len;
- int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
- return write_data(buf, LOAD_HEADER_LEN) != 0;
-}
-
-
-/*
- Load_log_event::write_data_body()
-*/
-
-bool Load_log_event::write_data_body()
-{
- if (sql_ex.write_data(writer))
- return 1;
- if (num_fields && fields && field_lens)
- {
- if (write_data(field_lens, num_fields) ||
- write_data(fields, field_block_len))
- return 1;
- }
- return (write_data(table_name, table_name_len + 1) ||
- write_data(db, db_len + 1) ||
- write_data(fname, fname_len));
-}
-
-
-/*
- Load_log_event::Load_log_event()
-*/
-
-Load_log_event::Load_log_event(THD *thd_arg, const sql_exchange *ex,
- const char *db_arg, const char *table_name_arg,
- List<Item> &fields_arg,
- bool is_concurrent_arg,
- enum enum_duplicates handle_dup,
- bool ignore, bool using_trans)
- :Log_event(thd_arg,
- thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0,
- using_trans),
- thread_id(thd_arg->thread_id),
- slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
- num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(table_name_arg ? table_name_arg : ""),
- db(db_arg), fname(ex->file_name), local_fname(FALSE),
- is_concurrent(is_concurrent_arg)
-{
- time_t end_time;
- time(&end_time);
- exec_time = (ulong) (end_time - thd_arg->start_time);
- /* db can never be a zero pointer in 4.0 */
- db_len = (uint32) strlen(db);
- table_name_len = (uint32) strlen(table_name);
- fname_len = (fname) ? (uint) strlen(fname) : 0;
- sql_ex.field_term = ex->field_term->ptr();
- sql_ex.field_term_len = (uint8) ex->field_term->length();
- sql_ex.enclosed = ex->enclosed->ptr();
- sql_ex.enclosed_len = (uint8) ex->enclosed->length();
- sql_ex.line_term = ex->line_term->ptr();
- sql_ex.line_term_len = (uint8) ex->line_term->length();
- sql_ex.line_start = ex->line_start->ptr();
- sql_ex.line_start_len = (uint8) ex->line_start->length();
- sql_ex.escaped = ex->escaped->ptr();
- sql_ex.escaped_len = (uint8) ex->escaped->length();
- sql_ex.opt_flags = 0;
- sql_ex.cached_new_format = -1;
-
- if (ex->dumpfile)
- sql_ex.opt_flags|= DUMPFILE_FLAG;
- if (ex->opt_enclosed)
- sql_ex.opt_flags|= OPT_ENCLOSED_FLAG;
-
- sql_ex.empty_flags= 0;
-
- switch (handle_dup) {
- case DUP_REPLACE:
- sql_ex.opt_flags|= REPLACE_FLAG;
- break;
- case DUP_UPDATE: // Impossible here
- case DUP_ERROR:
- break;
- }
- if (ignore)
- sql_ex.opt_flags|= IGNORE_FLAG;
-
- if (!ex->field_term->length())
- sql_ex.empty_flags |= FIELD_TERM_EMPTY;
- if (!ex->enclosed->length())
- sql_ex.empty_flags |= ENCLOSED_EMPTY;
- if (!ex->line_term->length())
- sql_ex.empty_flags |= LINE_TERM_EMPTY;
- if (!ex->line_start->length())
- sql_ex.empty_flags |= LINE_START_EMPTY;
- if (!ex->escaped->length())
- sql_ex.empty_flags |= ESCAPED_EMPTY;
-
- skip_lines = ex->skip_lines;
-
- List_iterator<Item> li(fields_arg);
- field_lens_buf.length(0);
- fields_buf.length(0);
- Item* item;
- while ((item = li++))
- {
- num_fields++;
- uchar len= (uchar) item->name.length;
- field_block_len += len + 1;
- fields_buf.append(item->name.str, len + 1);
- field_lens_buf.append((char*)&len, 1);
- }
-
- field_lens = (const uchar*)field_lens_buf.ptr();
- fields = fields_buf.ptr();
-}
-#endif /* !MYSQL_CLIENT */
-
/**
@note
@@ -7149,531 +2479,10 @@ err:
}
-/*
- Load_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-
-
-bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
- bool commented)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
- bool different_db= 1;
- DBUG_ENTER("Load_log_event::print");
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
- thread_id, exec_time))
- goto err;
- }
-
- if (db)
- {
- /*
- If the database is different from the one of the previous statement, we
- need to print the "use" command, and we update the last_db.
- But if commented, the "use" is going to be commented so we should not
- update the last_db.
- */
- if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
- !commented)
- memcpy(print_event_info->db, db, db_len + 1);
- }
-
- if (db && db[0] && different_db)
- if (my_b_printf(&cache, "%suse %`s%s\n",
- commented ? "# " : "",
- db, print_event_info->delimiter))
- goto err;
-
- if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
- if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
- commented ? "# " : "", (ulong)thread_id,
- print_event_info->delimiter))
- goto err;
- if (my_b_printf(&cache, "%sLOAD DATA ",
- commented ? "# " : ""))
- goto err;
- if (check_fname_outside_temp_buf())
- if (my_b_write_string(&cache, "LOCAL "))
- goto err;
- if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
- goto err;
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- {
- if (my_b_write_string(&cache, "REPLACE "))
- goto err;
- }
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- if (my_b_write_string(&cache, "IGNORE "))
- goto err;
-
- if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
- my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
- pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
- goto err;
-
- if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
- if (my_b_write_string(&cache, " OPTIONALLY "))
- goto err;
- if (my_b_write_string(&cache, " ENCLOSED BY ") ||
- pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
- my_b_write_string(&cache, " ESCAPED BY ") ||
- pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
- my_b_write_string(&cache, " LINES TERMINATED BY ") ||
- pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
- goto err;
-
- if (sql_ex.line_start)
- {
- if (my_b_write_string(&cache," STARTING BY ") ||
- pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
- goto err;
- }
- if ((long) skip_lines > 0)
- if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
- goto err;
-
- if (num_fields)
- {
- uint i;
- const char* field = fields;
- if (my_b_write_string(&cache, " ("))
- goto err;
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- if (my_b_write_byte(&cache, ','))
- goto err;
- if (my_b_printf(&cache, "%`s", field))
- goto err;
- field += field_lens[i] + 1;
- }
- if (my_b_write_byte(&cache, ')'))
- goto err;
- }
-
- if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
- goto err;
- DBUG_RETURN(cache.flush_data());
-err:
- DBUG_RETURN(1);
-}
-#endif /* MYSQL_CLIENT */
-
-#ifndef MYSQL_CLIENT
-
-/**
- Load_log_event::set_fields()
-
- @note
- This function can not use the member variable
- for the database, since LOAD DATA INFILE on the slave
- can be for a different database than the current one.
- This is the reason for the affected_db argument to this method.
-*/
-
-void Load_log_event::set_fields(const char* affected_db,
- List<Item> &field_list,
- Name_resolution_context *context)
-{
- uint i;
- const char* field = fields;
- for (i= 0; i < num_fields; i++)
- {
- LEX_CSTRING field_name= {field, field_lens[i] };
- field_list.push_back(new (thd->mem_root)
- Item_field(thd, context, affected_db, table_name,
- &field_name),
- thd->mem_root);
- field+= field_lens[i] + 1;
- }
-}
-#endif /* !MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-/**
- Does the data loading job when executing a LOAD DATA on the slave.
-
- @param net
- @param rli
- @param use_rli_only_for_errors If set to 1, rli is provided to
- Load_log_event::exec_event only for this
- function to have RPL_LOG_NAME and
- rli->last_slave_error, both being used by
- error reports. rli's position advancing
- is skipped (done by the caller which is
- Execute_load_log_event::exec_event).
- If set to 0, rli is provided for full use,
- i.e. for error reports and position
- advancing.
-
- @todo
- fix this; this can be done by testing rules in
- Create_file_log_event::exec_event() and then discarding Append_block and
- al.
- @todo
- this is a bug - this needs to be moved to the I/O thread
-
- @retval
- 0 Success
- @retval
- 1 Failure
-*/
-
-int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
- bool use_rli_only_for_errors)
-{
- Relay_log_info const *rli= rgi->rli;
- Rpl_filter *rpl_filter= rli->mi->rpl_filter;
- DBUG_ENTER("Load_log_event::do_apply_event");
-
- DBUG_ASSERT(thd->query() == 0);
- set_thd_db(thd, rpl_filter, db, db_len);
- thd->clear_error(1);
-
- /* see Query_log_event::do_apply_event() and BUG#13360 */
- DBUG_ASSERT(!rgi->m_table_map.count());
- /*
- Usually lex_start() is called by mysql_parse(), but we need it here
- as the present method does not call mysql_parse().
- */
- lex_start(thd);
- thd->lex->local_file= local_fname;
- thd->reset_for_next_command(0); // Errors are cleared above
-
- /*
- We test replicate_*_db rules. Note that we have already prepared
- the file to load, even if we are going to ignore and delete it
- now. So it is possible that we did a lot of disk writes for
- nothing. In other words, a big LOAD DATA INFILE on the master will
- still consume a lot of space on the slave (space in the relay log
- + space of temp files: twice the space of the file to load...)
- even if it will finally be ignored. TODO: fix this; this can be
- done by testing rules in Create_file_log_event::do_apply_event()
- and then discarding Append_block and al. Another way is do the
- filtering in the I/O thread (more efficient: no disk writes at
- all).
-
-
- Note: We do not need to execute reset_one_shot_variables() if this
- db_ok() test fails.
- Reason: The db stored in binlog events is the same for SET and for
- its companion query. If the SET is ignored because of
- db_ok(), the companion query will also be ignored, and if
- the companion query is ignored in the db_ok() test of
- ::do_apply_event(), then the companion SET also have so
- we don't need to reset_one_shot_variables().
- */
- if (rpl_filter->db_ok(thd->db.str))
- {
- thd->set_time(when, when_sec_part);
- thd->set_query_id(next_query_id());
- thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
-
- TABLE_LIST tables;
- LEX_CSTRING db_name= { thd->strmake(thd->db.str, thd->db.length), thd->db.length };
- if (lower_case_table_names)
- my_casedn_str(system_charset_info, (char *)table_name);
- LEX_CSTRING tbl_name= { table_name, strlen(table_name) };
- tables.init_one_table(&db_name, &tbl_name, 0, TL_WRITE);
- tables.updating= 1;
-
- // the table will be opened in mysql_load
- if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db.str, &tables))
- {
- // TODO: this is a bug - this needs to be moved to the I/O thread
- if (net)
- skip_load_data_infile(net);
- }
- else
- {
- enum enum_duplicates handle_dup;
- bool ignore= 0;
- char query_buffer[1024];
- String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
- char *load_data_query;
-
- query_str.length(0);
- /*
- Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
- and written to slave's binlog if binlogging is on.
- */
- print_query(thd, FALSE, NULL, &query_str, NULL, NULL, NULL);
- if (!(load_data_query= (char *)thd->strmake(query_str.ptr(),
- query_str.length())))
- {
- /*
- This will set thd->fatal_error in case of OOM. So we surely will notice
- that something is wrong.
- */
- goto error;
- }
-
- thd->set_query(load_data_query, (uint) (query_str.length()));
-
- if (sql_ex.opt_flags & REPLACE_FLAG)
- handle_dup= DUP_REPLACE;
- else if (sql_ex.opt_flags & IGNORE_FLAG)
- {
- ignore= 1;
- handle_dup= DUP_ERROR;
- }
- else
- {
- /*
- When replication is running fine, if it was DUP_ERROR on the
- master then we could choose IGNORE here, because if DUP_ERROR
- suceeded on master, and data is identical on the master and slave,
- then there should be no uniqueness errors on slave, so IGNORE is
- the same as DUP_ERROR. But in the unlikely case of uniqueness errors
- (because the data on the master and slave happen to be different
- (user error or bug), we want LOAD DATA to print an error message on
- the slave to discover the problem.
-
- If reading from net (a 3.23 master), mysql_load() will change this
- to IGNORE.
- */
- handle_dup= DUP_ERROR;
- }
- /*
- We need to set thd->lex->sql_command and thd->lex->duplicates
- since InnoDB tests these variables to decide if this is a LOAD
- DATA ... REPLACE INTO ... statement even though mysql_parse()
- is not called. This is not needed in 5.0 since there the LOAD
- DATA ... statement is replicated using mysql_parse(), which
- sets the thd->lex fields correctly.
- */
- thd->lex->sql_command= SQLCOM_LOAD;
- thd->lex->duplicates= handle_dup;
-
- sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
- String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
- String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
- String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
- String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
- String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
- ex.field_term= &field_term;
- ex.enclosed= &enclosed;
- ex.line_term= &line_term;
- ex.line_start= &line_start;
- ex.escaped= &escaped;
-
- ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
- if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
-
- ex.skip_lines = skip_lines;
- List<Item> field_list;
- thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
- set_fields(tables.db.str,
- field_list, &thd->lex->first_select_lex()->context);
- thd->variables.pseudo_thread_id= thread_id;
- if (net)
- {
- // mysql_load will use thd->net to read the file
- thd->net.vio = net->vio;
- // Make sure the client does not get confused about the packet sequence
- thd->net.pkt_nr = net->pkt_nr;
- }
- /*
- It is safe to use tmp_list twice because we are not going to
- update it inside mysql_load().
- */
- List<Item> tmp_list;
- if (thd->open_temporary_tables(&tables) ||
- mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
- handle_dup, ignore, net != 0))
- thd->is_slave_error= 1;
- if (thd->cuted_fields)
- {
- /* log_pos is the position of the LOAD event in the master log */
- sql_print_warning("Slave: load data infile on table '%s' at "
- "log position %llu in log '%s' produced %ld "
- "warning(s). Default database: '%s'",
- (char*) table_name, log_pos, RPL_LOG_NAME,
- (ulong) thd->cuted_fields,
- thd->get_db());
- }
- if (net)
- net->pkt_nr= thd->net.pkt_nr;
- }
- }
- else
- {
- /*
- We will just ask the master to send us /dev/null if we do not
- want to load the data.
- TODO: this a bug - needs to be done in I/O thread
- */
- if (net)
- skip_load_data_infile(net);
- }
-
-error:
- thd->net.vio = 0;
- const char *remember_db= thd->get_db();
- thd->catalog= 0;
- thd->set_db(&null_clex_str); /* will free the current database */
- thd->reset_query();
- thd->get_stmt_da()->set_overwrite_status(true);
- thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- thd->get_stmt_da()->set_overwrite_status(false);
- close_thread_tables(thd);
- /*
- - If transaction rollback was requested due to deadlock
- perform it and release metadata locks.
- - If inside a multi-statement transaction,
- defer the release of metadata locks until the current
- transaction is either committed or rolled back. This prevents
- other statements from modifying the table for the entire
- duration of this transaction. This provides commit ordering
- and guarantees serializability across multiple transactions.
- - If in autocommit mode, or outside a transactional context,
- automatically release metadata locks of the current statement.
- */
- if (thd->transaction_rollback_request)
- {
- trans_rollback_implicit(thd);
- thd->mdl_context.release_transactional_locks();
- }
- else if (! thd->in_multi_stmt_transaction_mode())
- thd->mdl_context.release_transactional_locks();
- else
- thd->mdl_context.release_statement_locks();
-
- DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
- thd->is_slave_error= 0; thd->is_fatal_error= 1;);
-
- if (unlikely(thd->is_slave_error))
- {
- /* this err/sql_errno code is copy-paste from net_send_error() */
- const char *err;
- int sql_errno;
- if (thd->is_error())
- {
- err= thd->get_stmt_da()->message();
- sql_errno= thd->get_stmt_da()->sql_errno();
- }
- else
- {
- sql_errno=ER_UNKNOWN_ERROR;
- err= ER_THD(thd, sql_errno);
- }
- rli->report(ERROR_LEVEL, sql_errno, rgi->gtid_info(), "\
-Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
- err, (char*)table_name, remember_db);
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- DBUG_RETURN(1);
- }
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
-
- if (unlikely(thd->is_fatal_error))
- {
- char buf[256];
- my_snprintf(buf, sizeof(buf),
- "Running LOAD DATA INFILE on table '%-.64s'."
- " Default database: '%-.64s'",
- (char*)table_name,
- remember_db);
-
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
- DBUG_RETURN(1);
- }
-
- DBUG_RETURN( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rgi) );
-}
-#endif
-
-
/**************************************************************************
Rotate_log_event methods
**************************************************************************/
-/*
- Rotate_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rotate_log_event::pack_info(Protocol *protocol)
-{
- StringBuffer<256> tmp(log_cs);
- tmp.length(0);
- tmp.append(new_log_ident, ident_len);
- tmp.append(STRING_WITH_LEN(";pos="));
- tmp.append_ulonglong(pos);
- protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
-}
-#endif
-
-
-/*
- Rotate_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- char buf[22];
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tRotate to "))
- goto err;
- if (new_log_ident)
- if (my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len))
- goto err;
- if (my_b_printf(&cache, " pos: %s\n", llstr(pos, buf)))
- goto err;
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-
-/*
- Rotate_log_event::Rotate_log_event() (2 constructors)
-*/
-
-
-#ifndef MYSQL_CLIENT
-Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg,
- uint ident_len_arg, ulonglong pos_arg,
- uint flags_arg)
- :Log_event(), new_log_ident(new_log_ident_arg),
- pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
- (uint) strlen(new_log_ident_arg)), flags(flags_arg)
-{
- DBUG_ENTER("Rotate_log_event::Rotate_log_event(...,flags)");
- DBUG_PRINT("enter",("new_log_ident: %s pos: %llu flags: %lu", new_log_ident_arg,
- pos_arg, (ulong) flags));
- cache_type= EVENT_NO_CACHE;
- if (flags & DUP_NAME)
- new_log_ident= my_strndup(new_log_ident_arg, ident_len, MYF(MY_WME));
- if (flags & RELAY_LOG)
- set_relay_log_event();
- DBUG_VOID_RETURN;
-}
-#endif
-
-
Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event) ,new_log_ident(0), flags(DUP_NAME)
@@ -7695,191 +2504,10 @@ Rotate_log_event::Rotate_log_event(const char* buf, uint event_len,
}
-/*
- Rotate_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Rotate_log_event::write()
-{
- char buf[ROTATE_HEADER_LEN];
- int8store(buf + R_POS_OFFSET, pos);
- return (write_header(ROTATE_HEADER_LEN + ident_len) ||
- write_data(buf, ROTATE_HEADER_LEN) ||
- write_data(new_log_ident, (uint) ident_len) ||
- write_footer());
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/*
- Got a rotate log event from the master.
-
- This is mainly used so that we can later figure out the logname and
- position for the master.
-
- We can't rotate the slave's BINlog as this will cause infinitive rotations
- in a A -> B -> A setup.
- The NOTES below is a wrong comment which will disappear when 4.1 is merged.
-
- This must only be called from the Slave SQL thread, since it calls
- Relay_log_info::flush().
-
- @retval
- 0 ok
- 1 error
-*/
-int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
-{
- int error= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Rotate_log_event::do_update_pos");
-
- DBUG_PRINT("info", ("server_id=%lu; ::server_id=%lu",
- (ulong) this->server_id, (ulong) global_system_variables.server_id));
- DBUG_PRINT("info", ("new_log_ident: %s", this->new_log_ident));
- DBUG_PRINT("info", ("pos: %llu", this->pos));
-
- /*
- If we are in a transaction or in a group: the only normal case is
- when the I/O thread was copying a big transaction, then it was
- stopped and restarted: we have this in the relay log:
-
- BEGIN
- ...
- ROTATE (a fake one)
- ...
- COMMIT or ROLLBACK
-
- In that case, we don't want to touch the coordinates which
- correspond to the beginning of the transaction. Starting from
- 5.0.0, there also are some rotates from the slave itself, in the
- relay log, which shall not change the group positions.
-
- In parallel replication, rotate event is executed out-of-band with normal
- events, so we cannot update group_master_log_name or _pos here, it will
- be updated with the next normal event instead.
- */
- if ((server_id != global_system_variables.server_id ||
- rli->replicate_same_server_id) &&
- !is_relay_log_event() &&
- !rli->is_in_group() &&
- !rgi->is_parallel_exec)
- {
- mysql_mutex_lock(&rli->data_lock);
- DBUG_PRINT("info", ("old group_master_log_name: '%s' "
- "old group_master_log_pos: %lu",
- rli->group_master_log_name,
- (ulong) rli->group_master_log_pos));
- memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
- rli->notify_group_master_log_name_update();
- rli->inc_group_relay_log_pos(pos, rgi, TRUE /* skip_lock */);
- DBUG_PRINT("info", ("new group_master_log_name: '%s' "
- "new group_master_log_pos: %lu",
- rli->group_master_log_name,
- (ulong) rli->group_master_log_pos));
- mysql_mutex_unlock(&rli->data_lock);
- rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- error= rli->flush();
-
- /*
- Reset thd->variables.option_bits and sql_mode etc, because this could
- be the signal of a master's downgrade from 5.0 to 4.0.
- However, no need to reset description_event_for_exec: indeed, if the next
- master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
- master is 4.0 then the events are in the slave's format (conversion).
- */
- set_slave_thread_options(thd);
- set_slave_thread_default_charset(thd, rgi);
- thd->variables.sql_mode= global_system_variables.sql_mode;
- thd->variables.auto_increment_increment=
- thd->variables.auto_increment_offset= 1;
- }
- else
- rgi->inc_event_relay_log_pos();
-
- DBUG_RETURN(error);
-}
-
-
-Log_event::enum_skip_reason
-Rotate_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
-
- switch (reason) {
- case Log_event::EVENT_SKIP_NOT:
- case Log_event::EVENT_SKIP_COUNT:
- return Log_event::EVENT_SKIP_NOT;
-
- case Log_event::EVENT_SKIP_IGNORE:
- return Log_event::EVENT_SKIP_IGNORE;
- }
- DBUG_ASSERT(0);
- return Log_event::EVENT_SKIP_NOT; // To keep compiler happy
-}
-
-#endif
-
-
/**************************************************************************
Binlog_checkpoint_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Binlog_checkpoint_log_event::pack_info(Protocol *protocol)
-{
- protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin);
-}
-
-
-Log_event::enum_skip_reason
-Binlog_checkpoint_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
- if (reason == EVENT_SKIP_COUNT)
- reason= EVENT_SKIP_NOT;
- return reason;
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Binlog_checkpoint_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tBinlog checkpoint ") ||
- my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len) ||
- my_b_write_byte(&cache, '\n'))
- return 1;
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-
-#ifdef MYSQL_SERVER
-Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
- const char *binlog_file_name_arg,
- uint binlog_file_len_arg)
- :Log_event(),
- binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg,
- MYF(MY_WME))),
- binlog_file_len(binlog_file_len_arg)
-{
- cache_type= EVENT_NO_CACHE;
-}
-#endif /* MYSQL_SERVER */
-
-
Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
const char *buf, uint event_len,
const Format_description_log_event *description_event)
@@ -7903,19 +2531,6 @@ Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
}
-#ifndef MYSQL_CLIENT
-bool Binlog_checkpoint_log_event::write()
-{
- uchar buf[BINLOG_CHECKPOINT_HEADER_LEN];
- int4store(buf, binlog_file_len);
- return write_header(BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) ||
- write_data(buf, BINLOG_CHECKPOINT_HEADER_LEN) ||
- write_data(binlog_file_name, binlog_file_len) ||
- write_footer();
-}
-#endif /* MYSQL_CLIENT */
-
-
/**************************************************************************
Global transaction ID stuff
**************************************************************************/
@@ -7949,333 +2564,6 @@ Gtid_log_event::Gtid_log_event(const char *buf, uint event_len,
}
-#ifdef MYSQL_SERVER
-
-Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
- uint32 domain_id_arg, bool standalone,
- uint16 flags_arg, bool is_transactional,
- uint64 commit_id_arg)
- : Log_event(thd_arg, flags_arg, is_transactional),
- seq_no(seq_no_arg), commit_id(commit_id_arg), domain_id(domain_id_arg),
- flags2((standalone ? FL_STANDALONE : 0) | (commit_id_arg ? FL_GROUP_COMMIT_ID : 0))
-{
- cache_type= Log_event::EVENT_NO_CACHE;
- bool is_tmp_table= thd_arg->lex->stmt_accessed_temp_table();
- if (thd_arg->transaction.stmt.trans_did_wait() ||
- thd_arg->transaction.all.trans_did_wait())
- flags2|= FL_WAITED;
- if (thd_arg->transaction.stmt.trans_did_ddl() ||
- thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
- thd_arg->transaction.all.trans_did_ddl() ||
- thd_arg->transaction.all.has_created_dropped_temp_table())
- flags2|= FL_DDL;
- else if (is_transactional && !is_tmp_table)
- flags2|= FL_TRANSACTIONAL;
- if (!(thd_arg->variables.option_bits & OPTION_RPL_SKIP_PARALLEL))
- flags2|= FL_ALLOW_PARALLEL;
- /* Preserve any DDL or WAITED flag in the slave's binlog. */
- if (thd_arg->rgi_slave)
- flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
-}
-
-
-/*
- Used to record GTID while sending binlog to slave, without having to
- fully contruct every Gtid_log_event() needlessly.
-*/
-bool
-Gtid_log_event::peek(const char *event_start, size_t event_len,
- enum enum_binlog_checksum_alg checksum_alg,
- uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
- uchar *flags2, const Format_description_log_event *fdev)
-{
- const char *p;
-
- if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
- {
- if (event_len > BINLOG_CHECKSUM_LEN)
- event_len-= BINLOG_CHECKSUM_LEN;
- else
- event_len= 0;
- }
- else
- DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
- checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
-
- if (event_len < (uint32)fdev->common_header_len + GTID_HEADER_LEN)
- return true;
- *server_id= uint4korr(event_start + SERVER_ID_OFFSET);
- p= event_start + fdev->common_header_len;
- *seq_no= uint8korr(p);
- p+= 8;
- *domain_id= uint4korr(p);
- p+= 4;
- *flags2= (uchar)*p;
- return false;
-}
-
-
-bool
-Gtid_log_event::write()
-{
- uchar buf[GTID_HEADER_LEN+2];
- size_t write_len;
-
- int8store(buf, seq_no);
- int4store(buf+8, domain_id);
- buf[12]= flags2;
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- int8store(buf+13, commit_id);
- write_len= GTID_HEADER_LEN + 2;
- }
- else
- {
- bzero(buf+13, GTID_HEADER_LEN-13);
- write_len= GTID_HEADER_LEN;
- }
- return write_header(write_len) ||
- write_data(buf, write_len) ||
- write_footer();
-}
-
-
-/*
- Replace a GTID event with either a BEGIN event, dummy event, or nothing, as
- appropriate to work with old slave that does not know global transaction id.
-
- The need_dummy_event argument is an IN/OUT argument. It is passed as TRUE
- if slave has capability lower than MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES.
- It is returned TRUE if we return a BEGIN (or dummy) event to be sent to the
- slave, FALSE if event should be skipped completely.
-*/
-int
-Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
- ulong ev_offset,
- enum enum_binlog_checksum_alg checksum_alg)
-{
- uchar flags2;
- if (packet->length() - ev_offset < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
- return 1;
- flags2= (*packet)[ev_offset + LOG_EVENT_HEADER_LEN + 12];
- if (flags2 & FL_STANDALONE)
- {
- if (*need_dummy_event)
- return Query_log_event::dummy_event(packet, ev_offset, checksum_alg);
- return 0;
- }
-
- *need_dummy_event= true;
- return Query_log_event::begin_event(packet, ev_offset, checksum_alg);
-}
-
-
-#ifdef HAVE_REPLICATION
-void
-Gtid_log_event::pack_info(Protocol *protocol)
-{
- char buf[6+5+10+1+10+1+20+1+4+20+1];
- char *p;
- p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
- p= longlong10_to_str(domain_id, p, 10);
- *p++= '-';
- p= longlong10_to_str(server_id, p, 10);
- *p++= '-';
- p= longlong10_to_str(seq_no, p, 10);
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- p= strmov(p, " cid=");
- p= longlong10_to_str(commit_id, p, 10);
- }
-
- protocol->store(buf, p-buf, &my_charset_bin);
-}
-
-static char gtid_begin_string[] = "BEGIN";
-
-int
-Gtid_log_event::do_apply_event(rpl_group_info *rgi)
-{
- ulonglong bits= thd->variables.option_bits;
- thd->variables.server_id= this->server_id;
- thd->variables.gtid_domain_id= this->domain_id;
- thd->variables.gtid_seq_no= this->seq_no;
- rgi->gtid_ev_flags2= flags2;
- thd->reset_for_next_command();
-
- if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates)
- {
- if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id,
- this->server_id, this->seq_no))
- return 1;
- }
-
- DBUG_ASSERT((bits & OPTION_GTID_BEGIN) == 0);
-
- Master_info *mi=rgi->rli->mi;
- switch (flags2 & (FL_DDL | FL_TRANSACTIONAL))
- {
- case FL_TRANSACTIONAL:
- mi->total_trans_groups++;
- break;
- case FL_DDL:
- mi->total_ddl_groups++;
- break;
- default:
- mi->total_non_trans_groups++;
- }
-
- if (flags2 & FL_STANDALONE)
- return 0;
-
- /* Execute this like a BEGIN query event. */
- bits|= OPTION_GTID_BEGIN;
- if (flags2 & FL_ALLOW_PARALLEL)
- bits&= ~(ulonglong)OPTION_RPL_SKIP_PARALLEL;
- else
- bits|= (ulonglong)OPTION_RPL_SKIP_PARALLEL;
- thd->variables.option_bits= bits;
- DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN"));
- thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
- &my_charset_bin, next_query_id());
- thd->lex->sql_command= SQLCOM_BEGIN;
- thd->is_slave_error= 0;
- status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
- if (trans_begin(thd, 0))
- {
- DBUG_PRINT("error", ("trans_begin() failed"));
- thd->is_slave_error= 1;
- }
- thd->update_stats();
-
- if (likely(!thd->is_slave_error))
- general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
-
- thd->reset_query();
- free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
- return thd->is_slave_error;
-}
-
-
-int
-Gtid_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Gtid_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- /*
- An event skipped due to @@skip_replication must not be counted towards the
- number of events to be skipped due to @@sql_slave_skip_counter.
- */
- if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
- opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
- return Log_event::EVENT_SKIP_IGNORE;
-
- if (rli->slave_skip_counter > 0)
- {
- if (!(flags2 & FL_STANDALONE))
- {
- thd->variables.option_bits|= OPTION_BEGIN;
- DBUG_ASSERT(rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
- }
- return Log_event::continue_group(rgi);
- }
- return Log_event::do_shall_skip(rgi);
-}
-
-
-#endif /* HAVE_REPLICATION */
-
-#else /* !MYSQL_SERVER */
-
-bool
-Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
- char buf[21];
- char buf2[21];
-
- if (!print_event_info->short_form && !is_flashback)
- {
- print_header(&cache, print_event_info, FALSE);
- longlong10_to_str(seq_no, buf, 10);
- if (my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf))
- goto err;
- if (flags2 & FL_GROUP_COMMIT_ID)
- {
- longlong10_to_str(commit_id, buf2, 10);
- if (my_b_printf(&cache, " cid=%s", buf2))
- goto err;
- }
- if (flags2 & FL_DDL)
- if (my_b_write_string(&cache, " ddl"))
- goto err;
- if (flags2 & FL_TRANSACTIONAL)
- if (my_b_write_string(&cache, " trans"))
- goto err;
- if (flags2 & FL_WAITED)
- if (my_b_write_string(&cache, " waited"))
- goto err;
- if (my_b_printf(&cache, "\n"))
- goto err;
-
- if (!print_event_info->allow_parallel_printed ||
- print_event_info->allow_parallel != !!(flags2 & FL_ALLOW_PARALLEL))
- {
- if (my_b_printf(&cache,
- "/*!100101 SET @@session.skip_parallel_replication=%u*/%s\n",
- !(flags2 & FL_ALLOW_PARALLEL),
- print_event_info->delimiter))
- goto err;
- print_event_info->allow_parallel= !!(flags2 & FL_ALLOW_PARALLEL);
- print_event_info->allow_parallel_printed= true;
- }
-
- if (!print_event_info->domain_id_printed ||
- print_event_info->domain_id != domain_id)
- {
- if (my_b_printf(&cache,
- "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
- domain_id, print_event_info->delimiter))
- goto err;
- print_event_info->domain_id= domain_id;
- print_event_info->domain_id_printed= true;
- }
-
- if (!print_event_info->server_id_printed ||
- print_event_info->server_id != server_id)
- {
- if (my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
- server_id, print_event_info->delimiter))
- goto err;
- print_event_info->server_id= server_id;
- print_event_info->server_id_printed= true;
- }
-
- if (!is_flashback)
- if (my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
- buf, print_event_info->delimiter))
- goto err;
- }
- if (!(flags2 & FL_STANDALONE))
- if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-
-#endif /* MYSQL_SERVER */
-
-
/* GTID list. */
Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
@@ -8337,213 +2625,6 @@ Gtid_list_log_event::Gtid_list_log_event(const char *buf, uint event_len,
}
-#ifdef MYSQL_SERVER
-
-Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set,
- uint32 gl_flags_)
- : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
-{
- cache_type= EVENT_NO_CACHE;
- /* Failure to allocate memory will be caught by is_valid() returning false. */
- if (count < (1<<28) &&
- (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
- MYF(MY_WME))))
- gtid_set->get_gtid_list(list, count);
-}
-
-
-Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set,
- uint32 gl_flags_)
- : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
-{
- cache_type= EVENT_NO_CACHE;
- /* Failure to allocate memory will be caught by is_valid() returning false. */
- if (count < (1<<28) &&
- (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
- MYF(MY_WME))))
- {
- gtid_set->get_gtid_list(list, count);
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
- if (gl_flags & FLAG_IGN_GTIDS)
- {
- uint32 i;
-
- if (!(sub_id_list= (uint64 *)my_malloc(count * sizeof(uint64),
- MYF(MY_WME))))
- {
- my_free(list);
- list= NULL;
- return;
- }
- for (i= 0; i < count; ++i)
- {
- if (!(sub_id_list[i]=
- rpl_global_gtid_slave_state->next_sub_id(list[i].domain_id)))
- {
- my_free(list);
- my_free(sub_id_list);
- list= NULL;
- sub_id_list= NULL;
- return;
- }
- }
- }
-#endif
- }
-}
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-bool
-Gtid_list_log_event::to_packet(String *packet)
-{
- uint32 i;
- uchar *p;
- uint32 needed_length;
-
- DBUG_ASSERT(count < 1<<28);
-
- needed_length= packet->length() + get_data_size();
- if (packet->reserve(needed_length))
- return true;
- p= (uchar *)packet->ptr() + packet->length();;
- packet->length(needed_length);
- int4store(p, (count & ((1<<28)-1)) | gl_flags);
- p += 4;
- /* Initialise the padding for empty Gtid_list. */
- if (count == 0)
- int2store(p, 0);
- for (i= 0; i < count; ++i)
- {
- int4store(p, list[i].domain_id);
- int4store(p+4, list[i].server_id);
- int8store(p+8, list[i].seq_no);
- p += 16;
- }
-
- return false;
-}
-
-
-bool
-Gtid_list_log_event::write()
-{
- char buf[128];
- String packet(buf, sizeof(buf), system_charset_info);
-
- packet.length(0);
- if (to_packet(&packet))
- return true;
- return write_header(get_data_size()) ||
- write_data(packet.ptr(), packet.length()) ||
- write_footer();
-}
-
-
-int
-Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info *rli= const_cast<Relay_log_info*>(rgi->rli);
- int ret;
- if (gl_flags & FLAG_IGN_GTIDS)
- {
- void *hton= NULL;
- uint32 i;
-
- for (i= 0; i < count; ++i)
- {
- if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
- sub_id_list[i],
- false, false, &hton)))
- return ret;
- rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
- hton, NULL);
- }
- }
- ret= Log_event::do_apply_event(rgi);
- if (rli->until_condition == Relay_log_info::UNTIL_GTID &&
- (gl_flags & FLAG_UNTIL_REACHED))
- {
- char str_buf[128];
- String str(str_buf, sizeof(str_buf), system_charset_info);
- rli->until_gtid_pos.to_string(&str);
- sql_print_information("Slave SQL thread stops because it reached its"
- " UNTIL master_gtid_pos %s", str.c_ptr_safe());
- rli->abort_slave= true;
- rli->stop_for_until= true;
- }
- free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
- return ret;
-}
-
-
-Log_event::enum_skip_reason
-Gtid_list_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- enum_skip_reason reason= Log_event::do_shall_skip(rgi);
- if (reason == EVENT_SKIP_COUNT)
- reason= EVENT_SKIP_NOT;
- return reason;
-}
-
-
-void
-Gtid_list_log_event::pack_info(Protocol *protocol)
-{
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- uint32 i;
- bool first;
-
- buf.length(0);
- buf.append(STRING_WITH_LEN("["));
- first= true;
- for (i= 0; i < count; ++i)
- rpl_slave_state_tostring_helper(&buf, &list[i], &first);
- buf.append(STRING_WITH_LEN("]"));
-
- protocol->store(&buf);
-}
-#endif /* HAVE_REPLICATION */
-
-#else /* !MYSQL_SERVER */
-
-bool
-Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
- char buf[21];
- uint32 i;
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tGtid list ["))
- goto err;
-
- for (i= 0; i < count; ++i)
- {
- longlong10_to_str(list[i].seq_no, buf, 10);
- if (my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
- list[i].server_id, buf))
- goto err;
- if (i < count-1)
- if (my_b_printf(&cache, ",\n# "))
- goto err;
- }
- if (my_b_printf(&cache, "]\n"))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-
-#endif /* MYSQL_SERVER */
-
-
/*
Used to record gtid_list event while sending binlog to slave, without having to
fully contruct the event object.
@@ -8603,22 +2684,6 @@ Gtid_list_log_event::peek(const char *event_start, size_t event_len,
**************************************************************************/
/*
- Intvar_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Intvar_log_event::pack_info(Protocol *protocol)
-{
- char buf[256], *pos;
- pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
- *pos++= '=';
- pos= longlong10_to_str(val, pos, -10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
-
-/*
Intvar_log_event::Intvar_log_event()
*/
@@ -8648,135 +2713,10 @@ const char* Intvar_log_event::get_var_type_name()
}
-/*
- Intvar_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Intvar_log_event::write()
-{
- uchar buf[9];
- buf[I_TYPE_OFFSET]= (uchar) type;
- int8store(buf + I_VAL_OFFSET, val);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Intvar_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- char llbuff[22];
- const char *UNINIT_VAR(msg);
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tIntvar\n"))
- goto err;
- }
-
- if (my_b_printf(&cache, "SET "))
- goto err;
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- msg="LAST_INSERT_ID";
- break;
- case INSERT_ID_EVENT:
- msg="INSERT_ID";
- break;
- case INVALID_INT_EVENT:
- default: // cannot happen
- msg="INVALID_INT";
- break;
- }
- if (my_b_printf(&cache, "%s=%s%s\n",
- msg, llstr(val,llbuff), print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
-
-/*
- Intvar_log_event::do_apply_event()
-*/
-
-int Intvar_log_event::do_apply_event(rpl_group_info *rgi)
-{
- DBUG_ENTER("Intvar_log_event::do_apply_event");
- if (rgi->deferred_events_collecting)
- {
- DBUG_PRINT("info",("deferring event"));
- DBUG_RETURN(rgi->deferred_events->add(this));
- }
-
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- thd->first_successful_insert_id_in_prev_stmt= val;
- DBUG_PRINT("info",("last_insert_id_event: %ld", (long) val));
- break;
- case INSERT_ID_EVENT:
- thd->force_one_auto_inc_interval(val);
- break;
- }
- DBUG_RETURN(0);
-}
-
-int Intvar_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Intvar_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead of
- 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-
-#endif
-
-
/**************************************************************************
Rand_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rand_log_event::pack_info(Protocol *protocol)
-{
- char buf1[256], *pos;
- pos= strmov(buf1,"rand_seed1=");
- pos= int10_to_str((long) seed1, pos, 10);
- pos= strmov(pos, ",rand_seed2=");
- pos= int10_to_str((long) seed2, pos, 10);
- protocol->store(buf1, (uint) (pos-buf1), &my_charset_bin);
-}
-#endif
-
-
Rand_log_event::Rand_log_event(const char* buf,
const Format_description_log_event* description_event)
:Log_event(buf, description_event)
@@ -8789,118 +2729,10 @@ Rand_log_event::Rand_log_event(const char* buf,
}
-#ifndef MYSQL_CLIENT
-bool Rand_log_event::write()
-{
- uchar buf[16];
- int8store(buf + RAND_SEED1_OFFSET, seed1);
- int8store(buf + RAND_SEED2_OFFSET, seed2);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- char llbuff[22],llbuff2[22];
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tRand\n"))
- goto err;
- }
- if (my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
- llstr(seed1, llbuff),llstr(seed2, llbuff2),
- print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Rand_log_event::do_apply_event(rpl_group_info *rgi)
-{
- if (rgi->deferred_events_collecting)
- return rgi->deferred_events->add(this);
-
- thd->rand.seed1= (ulong) seed1;
- thd->rand.seed2= (ulong) seed2;
- return 0;
-}
-
-int Rand_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-
-Log_event::enum_skip_reason
-Rand_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead of
- 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-
-/**
- Exec deferred Int-, Rand- and User- var events prefixing
- a Query-log-event event.
-
- @param thd THD handle
-
- @return false on success, true if a failure in an event applying occurred.
-*/
-bool slave_execute_deferred_events(THD *thd)
-{
- bool res= false;
- rpl_group_info *rgi= thd->rgi_slave;
-
- DBUG_ASSERT(rgi && (!rgi->deferred_events_collecting || rgi->deferred_events));
-
- if (!rgi->deferred_events_collecting || rgi->deferred_events->is_empty())
- return res;
-
- res= rgi->deferred_events->execute(rgi);
- rgi->deferred_events->rewind();
-
- return res;
-}
-
-#endif /* !MYSQL_CLIENT */
-
-
/**************************************************************************
Xid_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Xid_log_event::pack_info(Protocol *protocol)
-{
- char buf[128], *pos;
- pos= strmov(buf, "COMMIT /* xid=");
- pos= longlong10_to_str(xid, pos, 10);
- pos= strmov(pos, " */");
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif
-
/**
@note
It's ok not to use int8store here,
@@ -8922,266 +2754,10 @@ Xid_log_event(const char* buf,
}
-#ifndef MYSQL_CLIENT
-bool Xid_log_event::write()
-{
- DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
- return write_header(sizeof(xid)) ||
- write_data((uchar*)&xid, sizeof(xid)) ||
- write_footer();
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
-
- if (!print_event_info->short_form)
- {
- char buf[64];
- longlong10_to_str(xid, buf, 10);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\tXid = %s\n", buf))
- goto err;
- }
- if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
- print_event_info->delimiter))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Xid_log_event::do_apply_event(rpl_group_info *rgi)
-{
- bool res;
- int err;
- rpl_gtid gtid;
- uint64 sub_id= 0;
- Relay_log_info const *rli= rgi->rli;
- void *hton= NULL;
-
- /*
- XID_EVENT works like a COMMIT statement. And it also updates the
- mysql.gtid_slave_pos table with the GTID of the current transaction.
-
- Therefore, it acts much like a normal SQL statement, so we need to do
- THD::reset_for_next_command() as if starting a new statement.
- */
- thd->reset_for_next_command();
- /*
- Record any GTID in the same transaction, so slave state is transactionally
- consistent.
- */
-#ifdef WITH_WSREP
- thd->wsrep_affected_rows= 0;
-#endif
-
- if (rgi->gtid_pending)
- {
- sub_id= rgi->gtid_sub_id;
- rgi->gtid_pending= false;
-
- gtid= rgi->current_gtid;
- err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, true,
- false, &hton);
- if (unlikely(err))
- {
- int ec= thd->get_stmt_da()->sql_errno();
- /*
- Do not report an error if this is really a kill due to a deadlock.
- In this case, the transaction will be re-tried instead.
- */
- if (!is_parallel_retry_error(rgi, ec))
- rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
- "Error during XID COMMIT: failed to update GTID state in "
- "%s.%s: %d: %s",
- "mysql", rpl_gtid_slave_state_table_name.str, ec,
- thd->get_stmt_da()->message());
- thd->is_slave_error= 1;
- return err;
- }
-
- DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
- { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
- thd->is_slave_error= 1;
- return 1;
- });
- }
-
- /* For a slave Xid_log_event is COMMIT */
- general_log_print(thd, COM_QUERY,
- "COMMIT /* implicit, from Xid_log_event */");
- thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
- res= trans_commit(thd); /* Automatically rolls back on error. */
- thd->mdl_context.release_transactional_locks();
-
- if (likely(!res) && sub_id)
- rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
-
- /*
- Increment the global status commit count variable
- */
- status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
-
- return res;
-}
-
-Log_event::enum_skip_reason
-Xid_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- DBUG_ENTER("Xid_log_event::do_shall_skip");
- if (rgi->rli->slave_skip_counter > 0)
- {
- DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
- thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
- DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
- }
-#ifdef WITH_WSREP
- else if (wsrep_mysql_replication_bundle && WSREP_ON &&
- opt_slave_domain_parallel_threads == 0)
- {
- if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
- {
- WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
- DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
- }
- else
- {
- thd->wsrep_mysql_replicated = 0;
- }
- }
-#endif
- DBUG_RETURN(Log_event::do_shall_skip(rgi));
-}
-#endif /* !MYSQL_CLIENT */
-
-
/**************************************************************************
User_var_log_event methods
**************************************************************************/
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-static bool
-user_var_append_name_part(THD *thd, String *buf,
- const char *name, size_t name_len)
-{
- return buf->append("@") ||
- append_identifier(thd, buf, name, name_len) ||
- buf->append("=");
-}
-
-void User_var_log_event::pack_info(Protocol* protocol)
-{
- if (is_null)
- {
- char buf_mem[FN_REFLEN+7];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append("NULL"))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- {
- double real_val;
- char buf2[MY_GCVT_MAX_FIELD_WIDTH+1];
- char buf_mem[FN_REFLEN + MY_GCVT_MAX_FIELD_WIDTH + 1];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- float8get(real_val, val);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
- MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case INT_RESULT:
- {
- char buf2[22];
- char buf_mem[FN_REFLEN + 22];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.length(0);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2,
- longlong10_to_str(uint8korr(val), buf2,
- ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case DECIMAL_RESULT:
- {
- char buf_mem[FN_REFLEN + DECIMAL_MAX_STR_LENGTH];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- char buf2[DECIMAL_MAX_STR_LENGTH+1];
- String str(buf2, sizeof(buf2), &my_charset_bin);
- buf.length(0);
- my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append(buf2))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case STRING_RESULT:
- {
- /* 15 is for 'COLLATE' and other chars */
- char buf_mem[FN_REFLEN + 512 + 1 + 2*MY_CS_NAME_SIZE+15];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- CHARSET_INFO *cs;
- buf.length(0);
- if (!(cs= get_charset(charset_number, MYF(0))))
- {
- if (buf.append("???"))
- return;
- }
- else
- {
- size_t old_len;
- char *beg, *end;
- if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
- buf.append("_") ||
- buf.append(cs->csname) ||
- buf.append(" "))
- return;
- old_len= buf.length();
- if (buf.reserve(old_len + val_len * 2 + 3 + sizeof(" COLLATE ") +
- MY_CS_NAME_SIZE))
- return;
- beg= const_cast<char *>(buf.ptr()) + old_len;
- end= str_to_hex(beg, val, val_len);
- buf.length(old_len + (end - beg));
- if (buf.append(" COLLATE ") ||
- buf.append(cs->name))
- return;
- }
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- return;
- }
- }
-}
-#endif /* !MYSQL_CLIENT */
-
-
User_var_log_event::
User_var_log_event(const char* buf, uint event_len,
const Format_description_log_event* description_event)
@@ -9269,434 +2845,6 @@ err:
}
-#ifndef MYSQL_CLIENT
-bool User_var_log_event::write()
-{
- char buf[UV_NAME_LEN_SIZE];
- char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
- UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
- uchar buf2[MY_MAX(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
- uint unsigned_len= 0;
- uint buf1_length;
- size_t event_length;
-
- int4store(buf, name_len);
-
- if ((buf1[0]= is_null))
- {
- buf1_length= 1;
- val_len= 0; // Length of 'pos'
- }
- else
- {
- buf1[1]= type;
- int4store(buf1 + 2, charset_number);
-
- switch (type) {
- case REAL_RESULT:
- float8store(buf2, *(double*) val);
- break;
- case INT_RESULT:
- int8store(buf2, *(longlong*) val);
- unsigned_len= 1;
- break;
- case DECIMAL_RESULT:
- {
- my_decimal *dec= (my_decimal *)val;
- dec->fix_buffer_pointer();
- buf2[0]= (char)(dec->intg + dec->frac);
- buf2[1]= (char)dec->frac;
- decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
- val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
- break;
- }
- case STRING_RESULT:
- pos= (uchar*) val;
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- return 0;
- }
- int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
- buf1_length= 10;
- }
-
- /* Length of the whole event */
- event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
-
- return write_header(event_length) ||
- write_data(buf, sizeof(buf)) ||
- write_data(name, name_len) ||
- write_data(buf1, buf1_length) ||
- write_data(pos, val_len) ||
- write_data(&flags, unsigned_len) ||
- write_footer();
-}
-#endif
-
-
-/*
- User_var_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F);
-
- if (!print_event_info->short_form)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tUser_var\n"))
- goto err;
- }
-
- if (my_b_write_string(&cache, "SET @") ||
- my_b_write_backtick_quote(&cache, name, name_len))
- goto err;
-
- if (is_null)
- {
- if (my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter))
- goto err;
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- double real_val;
- char real_buf[FMT_G_BUFSIZE(14)];
- float8get(real_val, val);
- sprintf(real_buf, "%.14g", real_val);
- if (my_b_printf(&cache, ":=%s%s\n", real_buf,
- print_event_info->delimiter))
- goto err;
- break;
- case INT_RESULT:
- char int_buf[22];
- longlong10_to_str(uint8korr(val), int_buf,
- ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
- if (my_b_printf(&cache, ":=%s%s\n", int_buf,
- print_event_info->delimiter))
- goto err;
- break;
- case DECIMAL_RESULT:
- {
- char str_buf[200];
- int str_len= sizeof(str_buf) - 1;
- int precision= (int)val[0];
- int scale= (int)val[1];
- decimal_digit_t dec_buf[10];
- decimal_t dec;
- dec.len= 10;
- dec.buf= dec_buf;
-
- bin2decimal((uchar*) val+2, &dec, precision, scale);
- decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
- str_buf[str_len]= 0;
- if (my_b_printf(&cache, ":=%s%s\n", str_buf,
- print_event_info->delimiter))
- goto err;
- break;
- }
- case STRING_RESULT:
- {
- /*
- Let's express the string in hex. That's the most robust way. If we
- print it in character form instead, we need to escape it with
- character_set_client which we don't know (we will know it in 5.0, but
- in 4.1 we don't know it easily when we are printing
- User_var_log_event). Explanation why we would need to bother with
- character_set_client (quoting Bar):
- > Note, the parser doesn't switch to another unescaping mode after
- > it has met a character set introducer.
- > For example, if an SJIS client says something like:
- > SET @a= _ucs2 \0a\0b'
- > the string constant is still unescaped according to SJIS, not
- > according to UCS2.
- */
- char *hex_str;
- CHARSET_INFO *cs;
- bool error;
-
- // 2 hex digits / byte
- hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME));
- if (!hex_str)
- goto err;
- str_to_hex(hex_str, val, val_len);
- /*
- For proper behaviour when mysqlbinlog|mysql, we need to explicitly
- specify the variable's collation. It will however cause problems when
- people want to mysqlbinlog|mysql into another server not supporting the
- character set. But there's not much to do about this and it's unlikely.
- */
- if (!(cs= get_charset(charset_number, MYF(0))))
- { /*
- Generate an unusable command (=> syntax error) is probably the best
- thing we can do here.
- */
- error= my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
- }
- else
- error= my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
- cs->csname, hex_str, cs->name,
- print_event_info->delimiter);
- my_free(hex_str);
- if (unlikely(error))
- goto err;
- break;
- }
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- break;
- }
- }
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-/*
- User_var_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int User_var_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Item *it= 0;
- CHARSET_INFO *charset;
- DBUG_ENTER("User_var_log_event::do_apply_event");
- query_id_t sav_query_id= 0; /* memorize orig id when deferred applying */
-
- if (rgi->deferred_events_collecting)
- {
- set_deferred(current_thd->query_id);
- DBUG_RETURN(rgi->deferred_events->add(this));
- }
- else if (is_deferred())
- {
- sav_query_id= current_thd->query_id;
- current_thd->query_id= query_id; /* recreating original time context */
- }
-
- if (!(charset= get_charset(charset_number, MYF(MY_WME))))
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid character set for User var event");
- DBUG_RETURN(1);
- }
- LEX_CSTRING user_var_name;
- user_var_name.str= name;
- user_var_name.length= name_len;
- double real_val;
- longlong int_val;
-
- if (is_null)
- {
- it= new (thd->mem_root) Item_null(thd);
- }
- else
- {
- switch (type) {
- case REAL_RESULT:
- if (val_len != 8)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- float8get(real_val, val);
- it= new (thd->mem_root) Item_float(thd, real_val, 0);
- val= (char*) &real_val; // Pointer to value in native format
- val_len= 8;
- break;
- case INT_RESULT:
- if (val_len != 8)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- int_val= (longlong) uint8korr(val);
- it= new (thd->mem_root) Item_int(thd, int_val);
- val= (char*) &int_val; // Pointer to value in native format
- val_len= 8;
- break;
- case DECIMAL_RESULT:
- {
- if (val_len < 3)
- {
- rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
- ER_THD(thd, ER_SLAVE_FATAL_ERROR),
- "Invalid variable length at User var event");
- return 1;
- }
- Item_decimal *dec= new (thd->mem_root) Item_decimal(thd, (uchar*) val+2, val[0], val[1]);
- it= dec;
- val= (char *)dec->val_decimal(NULL);
- val_len= sizeof(my_decimal);
- break;
- }
- case STRING_RESULT:
- it= new (thd->mem_root) Item_string(thd, val, (uint)val_len, charset);
- break;
- case ROW_RESULT:
- default:
- DBUG_ASSERT(0);
- DBUG_RETURN(0);
- }
- }
-
- Item_func_set_user_var *e= new (thd->mem_root) Item_func_set_user_var(thd, &user_var_name, it);
- /*
- Item_func_set_user_var can't substitute something else on its place =>
- 0 can be passed as last argument (reference on item)
-
- Fix_fields() can fail, in which case a call of update_hash() might
- crash the server, so if fix fields fails, we just return with an
- error.
- */
- if (e->fix_fields(thd, 0))
- DBUG_RETURN(1);
-
- /*
- A variable can just be considered as a table with
- a single record and with a single column. Thus, like
- a column value, it could always have IMPLICIT derivation.
- */
- e->update_hash((void*) val, val_len, type, charset,
- (flags & User_var_log_event::UNSIGNED_F));
- if (!is_deferred())
- free_root(thd->mem_root, 0);
- else
- current_thd->query_id= sav_query_id; /* restore current query's context */
-
- DBUG_RETURN(0);
-}
-
-int User_var_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-Log_event::enum_skip_reason
-User_var_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- It is a common error to set the slave skip counter to 1 instead
- of 2 when recovering from an insert which used a auto increment,
- rand, or user var. Therefore, if the slave skip counter is 1, we
- just say that this event should be skipped by ignoring it, meaning
- that we do not change the value of the slave skip counter since it
- will be decreased by the following insert event.
- */
- return continue_group(rgi);
-}
-#endif /* !MYSQL_CLIENT */
-
-#ifdef HAVE_REPLICATION
-#ifdef MYSQL_CLIENT
-bool Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
-
- if (what != ENCRYPTED)
- {
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n# Unknown event\n"))
- goto err;
- }
- else if (my_b_printf(&cache, "# Encrypted event\n"))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-/**************************************************************************
- Stop_log_event methods
-**************************************************************************/
-
-/*
- Stop_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file,
- Write_on_release_cache::FLUSH_F, this);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_write_string(&cache, "\tStop\n"))
- return 1;
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-
-#ifndef MYSQL_CLIENT
-/*
- The master stopped. We used to clean up all temporary tables but
- this is useless as, as the master has shut down properly, it has
- written all DROP TEMPORARY TABLE (prepared statements' deletion is
- TODO only when we binlog prep stmts). We used to clean up
- slave_load_tmpdir, but this is useless as it has been cleared at the
- end of LOAD DATA INFILE. So we have nothing to do here. The place
- were we must do this cleaning is in
- Start_log_event_v3::do_apply_event(), not here. Because if we come
- here, the master was sane.
-
- This must only be called from the Slave SQL thread, since it calls
- Relay_log_info::flush().
-*/
-
-int Stop_log_event::do_update_pos(rpl_group_info *rgi)
-{
- int error= 0;
- Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Stop_log_event::do_update_pos");
- /*
- We do not want to update master_log pos because we get a rotate event
- before stop, so by now group_master_log_name is set to the next log.
- If we updated it, we will have incorrect master coordinates and this
- could give false triggers in MASTER_POS_WAIT() that we have reached
- the target position when in fact we have not.
- */
- if (rli->get_flag(Relay_log_info::IN_TRANSACTION))
- rgi->inc_event_relay_log_pos();
- else if (!rgi->is_parallel_exec)
- {
- rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- rli->inc_group_relay_log_pos(0, rgi);
- if (rli->flush())
- error= 1;
- }
- DBUG_RETURN(error);
-}
-
-#endif /* !MYSQL_CLIENT */
-#endif /* HAVE_REPLICATION */
-
-
/**************************************************************************
Create_file_log_event methods
**************************************************************************/
@@ -9705,75 +2853,6 @@ int Stop_log_event::do_update_pos(rpl_group_info *rgi)
Create_file_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Create_file_log_event::
-Create_file_log_event(THD* thd_arg, sql_exchange* ex,
- const char* db_arg, const char* table_name_arg,
- List<Item>& fields_arg,
- bool is_concurrent_arg,
- enum enum_duplicates handle_dup,
- bool ignore,
- uchar* block_arg, uint block_len_arg, bool using_trans)
- :Load_log_event(thd_arg, ex, db_arg, table_name_arg, fields_arg,
- is_concurrent_arg,
- handle_dup, ignore, using_trans),
- fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg),
- file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
-{
- DBUG_ENTER("Create_file_log_event");
- sql_ex.force_new_format();
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Create_file_log_event::write_data_body()
-*/
-
-bool Create_file_log_event::write_data_body()
-{
- bool res;
- if ((res= Load_log_event::write_data_body()) || fake_base)
- return res;
- return write_data("", 1) ||
- write_data(block, block_len);
-}
-
-
-/*
- Create_file_log_event::write_data_header()
-*/
-
-bool Create_file_log_event::write_data_header()
-{
- bool res;
- uchar buf[CREATE_FILE_HEADER_LEN];
- if ((res= Load_log_event::write_data_header()) || fake_base)
- return res;
- int4store(buf + CF_FILE_ID_OFFSET, file_id);
- return write_data(buf, CREATE_FILE_HEADER_LEN) != 0;
-}
-
-
-/*
- Create_file_log_event::write_base()
-*/
-
-bool Create_file_log_event::write_base()
-{
- bool res;
- fake_base= 1; // pretend we are Load event
- res= write();
- fake_base= 0;
- return res;
-}
-
-#endif /* !MYSQL_CLIENT */
-
-/*
- Create_file_log_event ctor
-*/
-
Create_file_log_event::Create_file_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Load_log_event(buf,0,description_event),fake_base(0),block(0),inited_from_old(0)
@@ -9825,172 +2904,6 @@ Create_file_log_event::Create_file_log_event(const char* buf, uint len,
}
-/*
- Create_file_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Create_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info,
- bool enable_local)
-{
- if (print_event_info->short_form)
- {
- if (enable_local && check_fname_outside_temp_buf())
- return Load_log_event::print(file, print_event_info);
- return 0;
- }
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (enable_local)
- {
- if (Load_log_event::print(file, print_event_info,
- !check_fname_outside_temp_buf()))
- goto err;
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_printf().
- */
- DBUG_EXECUTE_IF ("simulate_create_event_write_error",
- {(&cache)->write_pos= (&cache)->write_end;
- DBUG_SET("+d,simulate_file_write_error");});
- /*
- That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
- SHOW BINLOG EVENTS we don't.
- */
- if (my_b_write_byte(&cache, '#'))
- goto err;
- }
-
- if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-
-}
-
-
-bool Create_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Create_file_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Create_file_log_event::pack_info(Protocol *protocol)
-{
- char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos;
- pos= strmov(buf, "db=");
- memcpy(pos, db, db_len);
- pos= strmov(pos + db_len, ";table=");
- memcpy(pos, table_name, table_name_len);
- pos= strmov(pos + table_name_len, ";file_id=");
- pos= int10_to_str((long) file_id, pos, 10);
- pos= strmov(pos, ";block_len=");
- pos= int10_to_str((long) block_len, pos, 10);
- protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-/**
- Create_file_log_event::do_apply_event()
- Constructor for Create_file_log_event to intantiate an event
- from the relay log on the slave.
-
- @retval
- 0 Success
- @retval
- 1 Failure
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname_buf[FN_REFLEN];
- char *ext;
- int fd = -1;
- IO_CACHE file;
- Log_event_writer lew(&file, 0);
- int error = 1;
- Relay_log_info const *rli= rgi->rli;
-
- THD_STAGE_INFO(thd, stage_making_temp_file_create_before_load_data);
- bzero((char*)&file, sizeof(file));
- ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info",
- &rli->mi->connection_name);
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_info,
- fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
- MYF(MY_WME|MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not open file '%s'",
- fname_buf);
- goto err;
- }
-
- // a trick to avoid allocating another buffer
- fname= fname_buf;
- fname_len= (uint) (strmov(ext, ".data") - fname);
- writer= &lew;
- if (write_base())
- {
- strmov(ext, ".info"); // to have it right in the error message
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not write to file '%s'",
- fname_buf);
- goto err;
- }
- end_io_cache(&file);
- mysql_file_close(fd, MYF(0));
-
- // fname_buf now already has .data, not .info, because we did our trick
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_data, fname_buf, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_data,
- fname_buf, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: could not open file '%s'",
- fname_buf);
- goto err;
- }
- if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Create_file event: write to '%s' failed",
- fname_buf);
- goto err;
- }
- error=0; // Everything is ok
-
-err:
- if (unlikely(error))
- end_io_cache(&file);
- if (likely(fd >= 0))
- mysql_file_close(fd, MYF(0));
- return error != 0;
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Append_block_log_event methods
**************************************************************************/
@@ -9999,23 +2912,6 @@ err:
Append_block_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Append_block_log_event::Append_block_log_event(THD *thd_arg,
- const char *db_arg,
- uchar *block_arg,
- uint block_len_arg,
- bool using_trans)
- :Log_event(thd_arg,0, using_trans), block(block_arg),
- block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-
-/*
- Append_block_log_event ctor
-*/
-
Append_block_log_event::Append_block_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event),block(0)
@@ -10034,140 +2930,6 @@ Append_block_log_event::Append_block_log_event(const char* buf, uint len,
}
-/*
- Append_block_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Append_block_log_event::write()
-{
- uchar buf[APPEND_BLOCK_HEADER_LEN];
- int4store(buf + AB_FILE_ID_OFFSET, file_id);
- return write_header(APPEND_BLOCK_HEADER_LEN + block_len) ||
- write_data(buf, APPEND_BLOCK_HEADER_LEN) ||
- write_data(block, block_len) ||
- write_footer();
-}
-#endif
-
-
-/*
- Append_block_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Append_block_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
- get_type_str(), file_id, block_len))
- goto err;
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Append_block_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Append_block_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u;block_len=%u", file_id, block_len);
- protocol->store(buf, length, &my_charset_bin);
-}
-
-
-/*
- Append_block_log_event::get_create_or_append()
-*/
-
-int Append_block_log_event::get_create_or_append() const
-{
- return 0; /* append to the file, fail if not exists */
-}
-
-/*
- Append_block_log_event::do_apply_event()
-*/
-
-int Append_block_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN];
- int fd;
- int error = 1;
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Append_block_log_event::do_apply_event");
-
- THD_STAGE_INFO(thd, stage_making_temp_file_append_before_load_data);
- slave_load_file_stem(fname, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- if (get_create_or_append())
- {
- /*
- Usually lex_start() is called by mysql_parse(), but we need it here
- as the present method does not call mysql_parse().
- */
- lex_start(thd);
- thd->reset_for_next_command();
- /* old copy may exist already */
- mysql_file_delete(key_file_log_event_data, fname, MYF(0));
- if ((fd= mysql_file_create(key_file_log_event_data,
- fname, CREATE_MODE,
- O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: could not create file '%s'",
- get_type_str(), fname);
- goto err;
- }
- }
- else if ((fd= mysql_file_open(key_file_log_event_data,
- fname,
- O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0)
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: could not open file '%s'",
- get_type_str(), fname);
- goto err;
- }
-
- DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
- {
- my_delete(fname, MYF(0));
- });
-
- if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in %s event: write to '%s' failed",
- get_type_str(), fname);
- goto err;
- }
- error=0;
-
-err:
- if (fd >= 0)
- mysql_file_close(fd, MYF(0));
- DBUG_RETURN(error);
-}
-#endif
-
-
/**************************************************************************
Delete_file_log_event methods
**************************************************************************/
@@ -10176,18 +2938,6 @@ err:
Delete_file_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
- bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-/*
- Delete_file_log_event ctor
-*/
-
Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event),file_id(0)
@@ -10200,76 +2950,6 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, uint len,
}
-/*
- Delete_file_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Delete_file_log_event::write()
-{
- uchar buf[DELETE_FILE_HEADER_LEN];
- int4store(buf + DF_FILE_ID_OFFSET, file_id);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Delete_file_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Delete_file_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id))
- return 1;
-
- return cache.flush_data();
-}
-#endif /* MYSQL_CLIENT */
-
-/*
- Delete_file_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Delete_file_log_event::pack_info(Protocol *protocol)
-{
- char buf[64];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
- protocol->store(buf, (int32) length, &my_charset_bin);
-}
-#endif
-
-/*
- Delete_file_log_event::do_apply_event()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN+10];
- Relay_log_info const *rli= rgi->rli;
- char *ext= slave_load_file_stem(fname, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
- strmov(ext, ".info");
- mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
- return 0;
-}
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Execute_load_log_event methods
**************************************************************************/
@@ -10278,20 +2958,6 @@ int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
Execute_load_log_event ctor
*/
-#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD *thd_arg,
- const char* db_arg,
- bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
-{
-}
-#endif
-
-
-/*
- Execute_load_log_event ctor
-*/
-
Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
const Format_description_log_event* description_event)
:Log_event(buf, description_event), file_id(0)
@@ -10304,167 +2970,10 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, uint len,
}
-/*
- Execute_load_log_event::write()
-*/
-
-#ifndef MYSQL_CLIENT
-bool Execute_load_log_event::write()
-{
- uchar buf[EXEC_LOAD_HEADER_LEN];
- int4store(buf + EL_FILE_ID_OFFSET, file_id);
- return write_header(sizeof(buf)) ||
- write_data(buf, sizeof(buf)) ||
- write_footer();
-}
-#endif
-
-
-/*
- Execute_load_log_event::print()
-*/
-
-#ifdef MYSQL_CLIENT
-bool Execute_load_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
- file_id))
- return 1;
-
- return cache.flush_data();
-}
-#endif
-
-/*
- Execute_load_log_event::pack_info()
-*/
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Execute_load_log_event::pack_info(Protocol *protocol)
-{
- char buf[64];
- uint length;
- length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
- protocol->store(buf, (int32) length, &my_charset_bin);
-}
-
-
-/*
- Execute_load_log_event::do_apply_event()
-*/
-
-int Execute_load_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char fname[FN_REFLEN+10];
- char *ext;
- int fd;
- int error= 1;
- IO_CACHE file;
- Load_log_event *lev= 0;
- Relay_log_info const *rli= rgi->rli;
-
- ext= slave_load_file_stem(fname, file_id, server_id, ".info",
- &rli->mi->cmp_connection_name);
- if ((fd= mysql_file_open(key_file_log_event_info,
- fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
- MYF(MY_WME|MY_NABP)))
- {
- rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
- "Error in Exec_load event: could not open file '%s'",
- fname);
- goto err;
- }
- if (!(lev= (Load_log_event*)
- Log_event::read_log_event(&file,
- rli->relay_log.description_event_for_exec,
- opt_slave_sql_verify_checksum)) ||
- lev->get_type_code() != NEW_LOAD_EVENT)
- {
- rli->report(ERROR_LEVEL, 0, rgi->gtid_info(), "Error in Exec_load event: "
- "file '%s' appears corrupted", fname);
- goto err;
- }
- lev->thd = thd;
- /*
- lev->do_apply_event should use rli only for errors i.e. should
- not advance rli's position.
-
- lev->do_apply_event is the place where the table is loaded (it
- calls mysql_load()).
- */
-
- if (lev->do_apply_event(0,rgi,1))
- {
- /*
- We want to indicate the name of the file that could not be loaded
- (SQL_LOADxxx).
- But as we are here we are sure the error is in rli->last_slave_error and
- rli->last_slave_errno (example of error: duplicate entry for key), so we
- don't want to overwrite it with the filename.
- What we want instead is add the filename to the current error message.
- */
- char *tmp= my_strdup(rli->last_error().message, MYF(MY_WME));
- if (tmp)
- {
- rli->report(ERROR_LEVEL, rli->last_error().number, rgi->gtid_info(),
- "%s. Failed executing load from '%s'", tmp, fname);
- my_free(tmp);
- }
- goto err;
- }
- /*
- We have an open file descriptor to the .info file; we need to close it
- or Windows will refuse to delete the file in mysql_file_delete().
- */
- if (fd >= 0)
- {
- mysql_file_close(fd, MYF(0));
- end_io_cache(&file);
- fd= -1;
- }
- mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
- memcpy(ext, ".data", 6);
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
- error = 0;
-
-err:
- delete lev;
- if (fd >= 0)
- {
- mysql_file_close(fd, MYF(0));
- end_io_cache(&file);
- }
- return error;
-}
-
-#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
/**************************************************************************
Begin_load_query_log_event methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Begin_load_query_log_event::
-Begin_load_query_log_event(THD* thd_arg, const char* db_arg, uchar* block_arg,
- uint block_len_arg, bool using_trans)
- :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
- using_trans)
-{
- file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
-}
-#endif
-
-
Begin_load_query_log_event::
Begin_load_query_log_event(const char* buf, uint len,
const Format_description_log_event* desc_event)
@@ -10473,49 +2982,11 @@ Begin_load_query_log_event(const char* buf, uint len,
}
-#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int Begin_load_query_log_event::get_create_or_append() const
-{
- return 1; /* create the file */
-}
-#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
-
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-Log_event::enum_skip_reason
-Begin_load_query_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1, then we should not start executing
- on the next event.
- */
- return continue_group(rgi);
-}
-#endif
-
-
/**************************************************************************
Execute_load_query_log_event methods
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Execute_load_query_log_event::
-Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
- ulong query_length_arg, uint fn_pos_start_arg,
- uint fn_pos_end_arg,
- enum_load_dup_handling dup_handling_arg,
- bool using_trans, bool direct, bool suppress_use,
- int errcode):
- Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, direct,
- suppress_use, errcode),
- file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
- fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
-{
-}
-#endif /* !MYSQL_CLIENT */
-
-
Execute_load_query_log_event::
Execute_load_query_log_event(const char* buf, uint event_len,
const Format_description_log_event* desc_event):
@@ -10545,165 +3016,6 @@ ulong Execute_load_query_log_event::get_post_header_size_for_derived()
}
-#ifndef MYSQL_CLIENT
-bool
-Execute_load_query_log_event::write_post_header_for_derived()
-{
- uchar buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
- int4store(buf, file_id);
- int4store(buf + 4, fn_pos_start);
- int4store(buf + 4 + 4, fn_pos_end);
- *(buf + 4 + 4 + 4)= (uchar) dup_handling;
- return write_data(buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Execute_load_query_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return print(file, print_event_info, 0);
-}
-
-/**
- Prints the query as LOAD DATA LOCAL and with rewritten filename.
-*/
-bool Execute_load_query_log_event::print(FILE* file,
- PRINT_EVENT_INFO* print_event_info,
- const char *local_fname)
-{
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_query_header(&cache, print_event_info))
- goto err;
-
- /**
- reduce the size of io cache so that the write function is called
- for every call to my_b_printf().
- */
- DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
- {(&cache)->write_pos= (&cache)->write_end;
- DBUG_SET("+d,simulate_file_write_error");});
-
- if (local_fname)
- {
- if (my_b_write(&cache, (uchar*) query, fn_pos_start) ||
- my_b_write_string(&cache, " LOCAL INFILE ") ||
- pretty_print_str(&cache, local_fname, (int)strlen(local_fname)))
- goto err;
-
- if (dup_handling == LOAD_DUP_REPLACE)
- if (my_b_write_string(&cache, " REPLACE"))
- goto err;
-
- if (my_b_write_string(&cache, " INTO") ||
- my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
- else
- {
- if (my_b_write(&cache, (uchar*) query, q_len) ||
- my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
- goto err;
- }
-
- if (!print_event_info->short_form)
- my_b_printf(&cache, "# file_id: %d \n", file_id);
-
- return cache.flush_data();
-err:
- return 1;
-}
-#endif
-
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Execute_load_query_log_event::pack_info(Protocol *protocol)
-{
- char buf_mem[1024];
- String buf(buf_mem, sizeof(buf_mem), system_charset_info);
- buf.real_alloc(9 + db_len + q_len + 10 + 21);
- if (db && db_len)
- {
- if (buf.append(STRING_WITH_LEN("use ")) ||
- append_identifier(protocol->thd, &buf, db, db_len) ||
- buf.append(STRING_WITH_LEN("; ")))
- return;
- }
- if (query && q_len && buf.append(query, q_len))
- return;
- if (buf.append(" ;file_id=") ||
- buf.append_ulonglong(file_id))
- return;
- protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
-}
-
-
-int
-Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi)
-{
- char *p;
- char *buf;
- char *fname;
- char *fname_end;
- int error;
- Relay_log_info const *rli= rgi->rli;
-
- buf= (char*) my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
- (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
-
- DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", my_free(buf); buf= NULL;);
-
- /* Replace filename and LOCAL keyword in query before executing it */
- if (buf == NULL)
- {
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(rgi->thd, ER_SLAVE_FATAL_ERROR), "Not enough memory");
- return 1;
- }
-
- p= buf;
- memcpy(p, query, fn_pos_start);
- p+= fn_pos_start;
- fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'")));
- p= slave_load_file_stem(p, file_id, server_id, ".data",
- &rli->mi->cmp_connection_name);
- fname_end= p= strend(p); // Safer than p=p+5
- *(p++)='\'';
- switch (dup_handling) {
- case LOAD_DUP_IGNORE:
- p= strmake(p, STRING_WITH_LEN(" IGNORE"));
- break;
- case LOAD_DUP_REPLACE:
- p= strmake(p, STRING_WITH_LEN(" REPLACE"));
- break;
- default:
- /* Ordinary load data */
- break;
- }
- p= strmake(p, STRING_WITH_LEN(" INTO "));
- p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
-
- error= Query_log_event::do_apply_event(rgi, buf, (uint32)(p-buf));
-
- /* Forging file name for deletion in same buffer */
- *fname_end= 0;
-
- /*
- If there was an error the slave is going to stop, leave the
- file so that we can re-execute this event at START SLAVE.
- */
- if (unlikely(!error))
- mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
-
- my_free(buf);
- return error;
-}
-#endif
-
-
/**************************************************************************
sql_ex_info methods
**************************************************************************/
@@ -10758,105 +3070,12 @@ const char *sql_ex_info::init(const char *buf, const char *buf_end,
return buf;
}
-#ifndef MYSQL_CLIENT
-/*
- write_str()
-*/
-
-static bool write_str(Log_event_writer *writer, const char *str, uint length)
-{
- uchar tmp[1];
- tmp[0]= (uchar) length;
- return (writer->write_data(tmp, sizeof(tmp)) ||
- writer->write_data((uchar*) str, length));
-}
-
-/*
- sql_ex_info::write_data()
-*/
-
-bool sql_ex_info::write_data(Log_event_writer *writer)
-{
- if (new_format())
- {
- return write_str(writer, field_term, field_term_len) ||
- write_str(writer, enclosed, enclosed_len) ||
- write_str(writer, line_term, line_term_len) ||
- write_str(writer, line_start, line_start_len) ||
- write_str(writer, escaped, escaped_len) ||
- writer->write_data((uchar*) &opt_flags, 1);
- }
- else
- {
- uchar old_ex[7];
- old_ex[0]= *field_term;
- old_ex[1]= *enclosed;
- old_ex[2]= *line_term;
- old_ex[3]= *line_start;
- old_ex[4]= *escaped;
- old_ex[5]= opt_flags;
- old_ex[6]= empty_flags;
- return writer->write_data(old_ex, sizeof(old_ex));
- }
-}
-
/**************************************************************************
Rows_log_event member functions
**************************************************************************/
-Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
- MY_BITMAP const *cols, bool is_transactional,
- Log_event_type event_type)
- : Log_event(thd_arg, 0, is_transactional),
- m_row_count(0),
- m_table(tbl_arg),
- m_table_id(tid),
- m_width(tbl_arg ? tbl_arg->s->fields : 1),
- m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0),
- m_type(event_type), m_extra_row_data(0)
-#ifdef HAVE_REPLICATION
- , m_curr_row(NULL), m_curr_row_end(NULL),
- m_key(NULL), m_key_info(NULL), m_key_nr(0),
- master_had_triggers(0)
-#endif
-{
- /*
- We allow a special form of dummy event when the table, and cols
- are null and the table id is ~0UL. This is a temporary
- solution, to be able to terminate a started statement in the
- binary log: the extraneous events will be removed in the future.
- */
- DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
- (!tbl_arg && !cols && tid == ~0UL));
-
- if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
- set_flags(NO_FOREIGN_KEY_CHECKS_F);
- if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
- set_flags(RELAXED_UNIQUE_CHECKS_F);
- if (thd_arg->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS)
- set_flags(NO_CHECK_CONSTRAINT_CHECKS_F);
- /* if my_bitmap_init fails, caught in is_valid() */
- if (likely(!my_bitmap_init(&m_cols,
- m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
- m_width,
- false)))
- {
- /* Cols can be zero if this is a dummy binrows event */
- if (likely(cols != NULL))
- {
- memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
- create_last_word_mask(&m_cols);
- }
- }
- else
- {
- // Needed because my_bitmap_init() does not set it to null on failure
- m_cols.bitmap= 0;
- }
-}
-#endif
Rows_log_event::Rows_log_event(const char *buf, uint event_len,
const Format_description_log_event
@@ -11112,1150 +3331,10 @@ int Rows_log_event::get_data_size()
}
-#ifndef MYSQL_CLIENT
-int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
-{
- /*
- When the table has a primary key, we would probably want, by default, to
- log only the primary key value instead of the entire "before image". This
- would save binlog space. TODO
- */
- DBUG_ENTER("Rows_log_event::do_add_row_data");
- DBUG_PRINT("enter", ("row_data:%p length: %lu", row_data,
- (ulong) length));
-
- /*
- If length is zero, there is nothing to write, so we just
- return. Note that this is not an optimization, since calling
- realloc() with size 0 means free().
- */
- if (length == 0)
- {
- m_row_count++;
- DBUG_RETURN(0);
- }
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_DUMP("row_data", row_data, MY_MIN(length, 32));
-#endif
-
- DBUG_ASSERT(m_rows_buf <= m_rows_cur);
- DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end));
- DBUG_ASSERT(m_rows_cur <= m_rows_end);
-
- /* The cast will always work since m_rows_cur <= m_rows_end */
- if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
- {
- size_t const block_size= 1024;
- size_t cur_size= m_rows_cur - m_rows_buf;
- DBUG_EXECUTE_IF("simulate_too_big_row_case1",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= UINT_MAX32 - (block_size * 10););
- DBUG_EXECUTE_IF("simulate_too_big_row_case2",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= block_size * 10;);
- DBUG_EXECUTE_IF("simulate_too_big_row_case3",
- cur_size= block_size * 10;
- length= UINT_MAX32 - (block_size * 10););
- DBUG_EXECUTE_IF("simulate_too_big_row_case4",
- cur_size= UINT_MAX32 - (block_size * 10);
- length= (block_size * 10) - block_size + 1;);
- size_t remaining_space= UINT_MAX32 - cur_size;
- /* Check that the new data fits within remaining space and we can add
- block_size without wrapping.
- */
- if (cur_size > UINT_MAX32 || length > remaining_space ||
- ((length + block_size) > remaining_space))
- {
- sql_print_error("The row data is greater than 4GB, which is too big to "
- "write to the binary log.");
- DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED);
- }
- size_t const new_alloc=
- block_size * ((cur_size + length + block_size - 1) / block_size);
-
- uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, new_alloc,
- MYF(MY_ALLOW_ZERO_PTR|MY_WME));
- if (unlikely(!new_buf))
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- /* If the memory moved, we need to move the pointers */
- if (new_buf != m_rows_buf)
- {
- m_rows_buf= new_buf;
- m_rows_cur= m_rows_buf + cur_size;
- }
-
- /*
- The end pointer should always be changed to point to the end of
- the allocated memory.
- */
- m_rows_end= m_rows_buf + new_alloc;
- }
-
- DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
- memcpy(m_rows_cur, row_data, length);
- m_rows_cur+= length;
- m_row_count++;
- DBUG_RETURN(0);
-}
-#endif
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-
-/**
- Restores empty table list as it was before trigger processing.
-
- @note We have a lot of ASSERTS that check the lists when we close tables.
- There was the same problem with MERGE MYISAM tables and so here we try to
- go the same way.
-*/
-static void restore_empty_query_table_list(LEX *lex)
-{
- if (lex->first_not_own_table())
- (*lex->first_not_own_table()->prev_global)= NULL;
- lex->query_tables= NULL;
- lex->query_tables_last= &lex->query_tables;
-}
-
-
-int Rows_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info const *rli= rgi->rli;
- TABLE* table;
- DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
- int error= 0;
- /*
- If m_table_id == ~0ULL, then we have a dummy event that does not
- contain any data. In that case, we just remove all tables in the
- tables_to_lock list, close the thread tables, and return with
- success.
- */
- if (m_table_id == ~0ULL)
- {
- /*
- This one is supposed to be set: just an extra check so that
- nothing strange has happened.
- */
- DBUG_ASSERT(get_flags(STMT_END_F));
-
- rgi->slave_close_thread_tables(thd);
- thd->clear_error();
- DBUG_RETURN(0);
- }
-
- /*
- 'thd' has been set by exec_relay_log_event(), just before calling
- do_apply_event(). We still check here to prevent future coding
- errors.
- */
- DBUG_ASSERT(rgi->thd == thd);
-
- /*
- If there is no locks taken, this is the first binrow event seen
- after the table map events. We should then lock all the tables
- used in the transaction and proceed with execution of the actual
- event.
- */
- if (!thd->lock)
- {
- /*
- Lock_tables() reads the contents of thd->lex, so they must be
- initialized.
-
- We also call the THD::reset_for_next_command(), since this
- is the logical start of the next "statement". Note that this
- call might reset the value of current_stmt_binlog_format, so
- we need to do any changes to that value after this function.
- */
- delete_explain_query(thd->lex);
- lex_start(thd);
- thd->reset_for_next_command();
- /*
- The current statement is just about to begin and
- has not yet modified anything. Note, all.modified is reset
- by THD::reset_for_next_command().
- */
- thd->transaction.stmt.modified_non_trans_table= FALSE;
- thd->transaction.stmt.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
- /*
- This is a row injection, so we flag the "statement" as
- such. Note that this code is called both when the slave does row
- injections and when the BINLOG statement is used to do row
- injections.
- */
- thd->lex->set_stmt_row_injection();
-
- /*
- There are a few flags that are replicated with each row event.
- Make sure to set/clear them before executing the main body of
- the event.
- */
- if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
- thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
-
- if (get_flags(RELAXED_UNIQUE_CHECKS_F))
- thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
-
- if (get_flags(NO_CHECK_CONSTRAINT_CHECKS_F))
- thd->variables.option_bits|= OPTION_NO_CHECK_CONSTRAINT_CHECKS;
- else
- thd->variables.option_bits&= ~OPTION_NO_CHECK_CONSTRAINT_CHECKS;
-
- /* A small test to verify that objects have consistent types */
- DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
-
- DBUG_EXECUTE_IF("rows_log_event_before_open_table",
- {
- const char action[] = "now SIGNAL before_open_table WAIT_FOR go_ahead_sql";
- DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
- };);
-
- if (slave_run_triggers_for_rbr)
- {
- LEX *lex= thd->lex;
- uint8 new_trg_event_map= get_trg_event_map();
-
- /*
- Trigger's procedures work with global table list. So we have to add
- rgi->tables_to_lock content there to get trigger's in the list.
-
- Then restore_empty_query_table_list() restore the list as it was
- */
- DBUG_ASSERT(lex->query_tables == NULL);
- if ((lex->query_tables= rgi->tables_to_lock))
- rgi->tables_to_lock->prev_global= &lex->query_tables;
-
- for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
- tables= tables->next_global)
- {
- tables->trg_event_map= new_trg_event_map;
- lex->query_tables_last= &tables->next_global;
- }
- }
- if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
- {
-#ifdef WITH_WSREP
- if (WSREP(thd))
- {
- WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
- "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
- thd->get_stmt_da()->sql_errno(),
- thd->is_fatal_error,
- thd->wsrep_cs().mode(),
- thd->wsrep_trx().state(),
- (long long) wsrep_thd_trx_seqno(thd));
- }
-#endif /* WITH_WSREP */
- if (thd->is_error() &&
- !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno()))
- {
- /*
- Error reporting borrowed from Query_log_event with many excessive
- simplifications.
- We should not honour --slave-skip-errors at this point as we are
- having severe errors which should not be skipped.
- */
- rli->report(ERROR_LEVEL, error, rgi->gtid_info(),
- "Error executing row event: '%s'",
- (error ? thd->get_stmt_da()->message() :
- "unexpected success or fatal error"));
- thd->is_slave_error= 1;
- }
- /* remove trigger's tables */
- goto err;
- }
-
- /*
- When the open and locking succeeded, we check all tables to
- ensure that they still have the correct type.
- */
-
- {
- DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
- rgi->tables_to_lock));
-
- /**
- When using RBR and MyISAM MERGE tables the base tables that make
- up the MERGE table can be appended to the list of tables to lock.
-
- Thus, we just check compatibility for those that tables that have
- a correspondent table map event (ie, those that are actually going
- to be accessed while applying the event). That's why the loop stops
- at rli->tables_to_lock_count .
-
- NOTE: The base tables are added here are removed when
- close_thread_tables is called.
- */
- TABLE_LIST *table_list_ptr= rgi->tables_to_lock;
- for (uint i=0 ; table_list_ptr && (i < rgi->tables_to_lock_count);
- table_list_ptr= table_list_ptr->next_global, i++)
- {
- /*
- Below if condition takes care of skipping base tables that
- make up the MERGE table (which are added by open_tables()
- call). They are added next to the merge table in the list.
- For eg: If RPL_TABLE_LIST is t3->t1->t2 (where t1 and t2
- are base tables for merge table 't3'), open_tables will modify
- the list by adding t1 and t2 again immediately after t3 in the
- list (*not at the end of the list*). New table_to_lock list will
- look like t3->t1'->t2'->t1->t2 (where t1' and t2' are TABLE_LIST
- objects added by open_tables() call). There is no flag(or logic) in
- open_tables() that can skip adding these base tables to the list.
- So the logic here should take care of skipping them.
-
- tables_to_lock_count logic will take care of skipping base tables
- that are added at the end of the list.
- For eg: If RPL_TABLE_LIST is t1->t2->t3, open_tables will modify
- the list into t1->t2->t3->t1'->t2'. t1' and t2' will be skipped
- because tables_to_lock_count logic in this for loop.
- */
- if (table_list_ptr->parent_l)
- continue;
- /*
- We can use a down cast here since we know that every table added
- to the tables_to_lock is a RPL_TABLE_LIST (or child table which is
- skipped above).
- */
- RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(table_list_ptr);
- DBUG_ASSERT(ptr->m_tabledef_valid);
- TABLE *conv_table;
- if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table))
- {
- DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master",
- ptr->table->s->db.str,
- ptr->table->s->table_name.str));
- /*
- We should not honour --slave-skip-errors at this point as we are
- having severe errors which should not be skiped.
- */
- thd->is_slave_error= 1;
- /* remove trigger's tables */
- error= ERR_BAD_TABLE_DEF;
- goto err;
- }
- DBUG_PRINT("debug", ("Table: %s.%s is compatible with master"
- " - conv_table: %p",
- ptr->table->s->db.str,
- ptr->table->s->table_name.str, conv_table));
- ptr->m_conv_table= conv_table;
- }
- }
-
- /*
- ... and then we add all the tables to the table map and but keep
- them in the tables to lock list.
-
- We also invalidate the query cache for all the tables, since
- they will now be changed.
-
- TODO [/Matz]: Maybe the query cache should not be invalidated
- here? It might be that a table is not changed, even though it
- was locked for the statement. We do know that each
- Rows_log_event contain at least one row, so after processing one
- Rows_log_event, we can invalidate the query cache for the
- associated table.
- */
- TABLE_LIST *ptr= rgi->tables_to_lock;
- for (uint i=0 ; ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
- {
- /*
- Please see comment in above 'for' loop to know the reason
- for this if condition
- */
- if (ptr->parent_l)
- continue;
- rgi->m_table_map.set_table(ptr->table_id, ptr->table);
- /*
- Following is passing flag about triggers on the server. The problem was
- to pass it between table map event and row event. I do it via extended
- TABLE_LIST (RPL_TABLE_LIST) but row event uses only TABLE so I need to
- find somehow the corresponding TABLE_LIST.
- */
- if (m_table_id == ptr->table_id)
- {
- ptr->table->master_had_triggers=
- ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
- }
- }
-
-#ifdef HAVE_QUERY_CACHE
-#ifdef WITH_WSREP
- /*
- Moved invalidation right before the call to rows_event_stmt_cleanup(),
- to avoid query cache being polluted with stale entries,
- */
- if (! (WSREP(thd) && wsrep_thd_is_applying(thd)))
- {
-#endif /* WITH_WSREP */
- query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
-#ifdef WITH_WSREP
- }
-#endif /* WITH_WSREP */
-#endif
- }
-
- table= m_table= rgi->m_table_map.get_table(m_table_id);
-
- DBUG_PRINT("debug", ("m_table:%p, m_table_id: %llu%s",
- m_table, m_table_id,
- table && master_had_triggers ?
- " (master had triggers)" : ""));
- if (table)
- {
- master_had_triggers= table->master_had_triggers;
- bool transactional_table= table->file->has_transactions();
- /*
- table == NULL means that this table should not be replicated
- (this was set up by Table_map_log_event::do_apply_event()
- which tested replicate-* rules).
- */
-
- /*
- It's not needed to set_time() but
- 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
- much slave is behind
- 2) it will be needed when we allow replication from a table with no
- TIMESTAMP column to a table with one.
- So we call set_time(), like in SBR. Presently it changes nothing.
- */
- thd->set_time(when, when_sec_part);
-
- if (m_width == table->s->fields && bitmap_is_set_all(&m_cols))
- set_flags(COMPLETE_ROWS_F);
-
- /*
- Set tables write and read sets.
-
- Read_set contains all slave columns (in case we are going to fetch
- a complete record from slave)
-
- Write_set equals the m_cols bitmap sent from master but it can be
- longer if slave has extra columns.
- */
-
- DBUG_PRINT_BITSET("debug", "Setting table's read_set from: %s", &m_cols);
-
- bitmap_set_all(table->read_set);
- if (get_general_type_code() == DELETE_ROWS_EVENT ||
- get_general_type_code() == UPDATE_ROWS_EVENT)
- bitmap_intersect(table->read_set,&m_cols);
-
- bitmap_set_all(table->write_set);
- table->rpl_write_set= table->write_set;
-
- /* WRITE ROWS EVENTS store the bitmap in m_cols instead of m_cols_ai */
- MY_BITMAP *after_image= ((get_general_type_code() == UPDATE_ROWS_EVENT) ?
- &m_cols_ai : &m_cols);
- bitmap_intersect(table->write_set, after_image);
-
- this->slave_exec_mode= slave_exec_mode_options; // fix the mode
-
- // Do event specific preparations
- error= do_before_row_operations(rli);
-
- /*
- Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
- Don't allow generation of auto_increment value when processing
- rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception
- to this rule happens when the auto_inc column exists on some
- extra columns on the slave. In that case, do not force
- MODE_NO_AUTO_VALUE_ON_ZERO.
- */
- sql_mode_t saved_sql_mode= thd->variables.sql_mode;
- if (!is_auto_inc_in_extra_columns())
- thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
-
- // row processing loop
-
- /*
- set the initial time of this ROWS statement if it was not done
- before in some other ROWS event.
- */
- rgi->set_row_stmt_start_timestamp();
-
- THD_STAGE_INFO(thd, stage_executing);
- do
- {
- /* in_use can have been set to NULL in close_tables_for_reopen */
- THD* old_thd= table->in_use;
- if (!table->in_use)
- table->in_use= thd;
-
- error= do_exec_row(rgi);
-
- if (unlikely(error))
- DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
- DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
-
- table->in_use = old_thd;
-
- if (unlikely(error))
- {
- int actual_error= convert_handler_error(error, thd, table);
- bool idempotent_error= (idempotent_error_code(error) &&
- (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT));
- bool ignored_error= (idempotent_error == 0 ?
- ignored_error_code(actual_error) : 0);
-
-#ifdef WITH_WSREP
- if (WSREP(thd) && wsrep_ignored_error_code(this, actual_error))
- {
- idempotent_error= true;
- thd->wsrep_has_ignored_error= true;
- }
-#endif /* WITH_WSREP */
- if (idempotent_error || ignored_error)
- {
- if (global_system_variables.log_warnings)
- slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- thd->clear_error(1);
- error= 0;
- if (idempotent_error == 0)
- break;
- }
- }
-
- /*
- If m_curr_row_end was not set during event execution (e.g., because
- of errors) we can't proceed to the next row. If the error is transient
- (i.e., error==0 at this point) we must call unpack_current_row() to set
- m_curr_row_end.
- */
-
- DBUG_PRINT("info", ("curr_row: %p; curr_row_end: %p; rows_end:%p",
- m_curr_row, m_curr_row_end, m_rows_end));
-
- if (!m_curr_row_end && likely(!error))
- error= unpack_current_row(rgi);
-
- m_curr_row= m_curr_row_end;
-
- if (likely(error == 0) && !transactional_table)
- thd->transaction.all.modified_non_trans_table=
- thd->transaction.stmt.modified_non_trans_table= TRUE;
- } // row processing loop
- while (error == 0 && (m_curr_row != m_rows_end));
-
- /*
- Restore the sql_mode after the rows event is processed.
- */
- thd->variables.sql_mode= saved_sql_mode;
-
- {/**
- The following failure injecion works in cooperation with tests
- setting @@global.debug= 'd,stop_slave_middle_group'.
- The sql thread receives the killed status and will proceed
- to shutdown trying to finish incomplete events group.
- */
- DBUG_EXECUTE_IF("stop_slave_middle_group",
- if (thd->transaction.all.modified_non_trans_table)
- const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
- }
-
- if (unlikely(error= do_after_row_operations(rli, error)) &&
- ignored_error_code(convert_handler_error(error, thd, table)))
- {
-
- if (global_system_variables.log_warnings)
- slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- thd->clear_error(1);
- error= 0;
- }
- } // if (table)
-
-
- if (unlikely(error))
- {
- slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- /*
- @todo We should probably not call
- reset_current_stmt_binlog_format_row() from here.
-
- Note: this applies to log_event_old.cc too.
- /Sven
- */
- thd->reset_current_stmt_binlog_format_row();
- thd->is_slave_error= 1;
- /* remove trigger's tables */
- goto err;
- }
-
- /* remove trigger's tables */
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
-
-#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
- if (WSREP(thd) && wsrep_thd_is_applying(thd))
- {
- query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
- }
-#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
-
- if (unlikely(get_flags(STMT_END_F) &&
- (error= rows_event_stmt_cleanup(rgi, thd))))
- slave_rows_error_report(ERROR_LEVEL,
- thd->is_error() ? 0 : error,
- rgi, thd, table,
- get_type_str(),
- RPL_LOG_NAME, log_pos);
- DBUG_RETURN(error);
-
-err:
- if (slave_run_triggers_for_rbr)
- restore_empty_query_table_list(thd->lex);
- rgi->slave_close_thread_tables(thd);
- DBUG_RETURN(error);
-}
-
-Log_event::enum_skip_reason
-Rows_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1 and this event does not end a
- statement, then we should not start executing on the next event.
- Otherwise, we defer the decision to the normal skipping logic.
- */
- if (rgi->rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
- return Log_event::EVENT_SKIP_IGNORE;
- else
- return Log_event::do_shall_skip(rgi);
-}
-
-/**
- The function is called at Rows_log_event statement commit time,
- normally from Rows_log_event::do_update_pos() and possibly from
- Query_log_event::do_apply_event() of the COMMIT.
- The function commits the last statement for engines, binlog and
- releases resources have been allocated for the statement.
-
- @retval 0 Ok.
- @retval non-zero Error at the commit.
- */
-
-static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD * thd)
-{
- int error;
- DBUG_ENTER("rows_event_stmt_cleanup");
-
- {
- /*
- This is the end of a statement or transaction, so close (and
- unlock) the tables we opened when processing the
- Table_map_log_event starting the statement.
-
- OBSERVER. This will clear *all* mappings, not only those that
- are open for the table. There is not good handle for on-close
- actions for tables.
-
- NOTE. Even if we have no table ('table' == 0) we still need to be
- here, so that we increase the group relay log position. If we didn't, we
- could have a group relay log position which lags behind "forever"
- (assume the last master's transaction is ignored by the slave because of
- replicate-ignore rules).
- */
- error= thd->binlog_flush_pending_rows_event(TRUE);
-
- /*
- If this event is not in a transaction, the call below will, if some
- transactional storage engines are involved, commit the statement into
- them and flush the pending event to binlog.
- If this event is in a transaction, the call will do nothing, but a
- Xid_log_event will come next which will, if some transactional engines
- are involved, commit the transaction and flush the pending event to the
- binlog.
- If there was a deadlock the transaction should have been rolled back
- already. So there should be no need to rollback the transaction.
- */
- DBUG_ASSERT(! thd->transaction_rollback_request);
- error|= (int)(error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
-
- /*
- Now what if this is not a transactional engine? we still need to
- flush the pending event to the binlog; we did it with
- thd->binlog_flush_pending_rows_event(). Note that we imitate
- what is done for real queries: a call to
- ha_autocommit_or_rollback() (sometimes only if involves a
- transactional engine), and a call to be sure to have the pending
- event flushed.
- */
-
- /*
- @todo We should probably not call
- reset_current_stmt_binlog_format_row() from here.
-
- Note: this applies to log_event_old.cc too
-
- Btw, the previous comment about transactional engines does not
- seem related to anything that happens here.
- /Sven
- */
- thd->reset_current_stmt_binlog_format_row();
-
- /*
- Reset modified_non_trans_table that we have set in
- rows_log_event::do_apply_event()
- */
- if (!thd->in_multi_stmt_transaction_mode())
- {
- thd->transaction.all.modified_non_trans_table= 0;
- thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
- }
-
- rgi->cleanup_context(thd, 0);
- }
- DBUG_RETURN(error);
-}
-
-/**
- The method either increments the relay log position or
- commits the current statement and increments the master group
- possition if the event is STMT_END_F flagged and
- the statement corresponds to the autocommit query (i.e replicated
- without wrapping in BEGIN/COMMIT)
-
- @retval 0 Success
- @retval non-zero Error in the statement commit
- */
-int
-Rows_log_event::do_update_pos(rpl_group_info *rgi)
-{
- Relay_log_info *rli= rgi->rli;
- int error= 0;
- DBUG_ENTER("Rows_log_event::do_update_pos");
-
- DBUG_PRINT("info", ("flags: %s",
- get_flags(STMT_END_F) ? "STMT_END_F " : ""));
-
- if (get_flags(STMT_END_F))
- {
- /*
- Indicate that a statement is finished.
- Step the group log position if we are not in a transaction,
- otherwise increase the event log position.
- */
- error= rli->stmt_done(log_pos, thd, rgi);
- /*
- Clear any errors in thd->net.last_err*. It is not known if this is
- needed or not. It is believed that any errors that may exist in
- thd->net.last_err* are allowed. Examples of errors are "key not
- found", which is produced in the test case rpl_row_conflicts.test
- */
- thd->clear_error();
- }
- else
- {
- rgi->inc_event_relay_log_pos();
- }
-
- DBUG_RETURN(error);
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifndef MYSQL_CLIENT
-bool Rows_log_event::write_data_header()
-{
- uchar buf[ROWS_HEADER_LEN_V2]; // No need to init the buffer
- DBUG_ASSERT(m_table_id != ~0ULL);
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
- {
- int4store(buf + 0, m_table_id);
- int2store(buf + 4, m_flags);
- return (write_data(buf, 6));
- });
- int6store(buf + RW_MAPID_OFFSET, m_table_id);
- int2store(buf + RW_FLAGS_OFFSET, m_flags);
- return write_data(buf, ROWS_HEADER_LEN);
-}
-
-bool Rows_log_event::write_data_body()
-{
- /*
- Note that this should be the number of *bits*, not the number of
- bytes.
- */
- uchar sbuf[MAX_INT_WIDTH];
- my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
- bool res= false;
- uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
- DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
-
- DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
- res= res || write_data(sbuf, (size_t) (sbuf_end - sbuf));
-
- DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
- res= res || write_data((uchar*)m_cols.bitmap, no_bytes_in_map(&m_cols));
- /*
- TODO[refactor write]: Remove the "down cast" here (and elsewhere).
- */
- if (get_general_type_code() == UPDATE_ROWS_EVENT)
- {
- DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
- no_bytes_in_map(&m_cols_ai));
- res= res || write_data((uchar*)m_cols_ai.bitmap,
- no_bytes_in_map(&m_cols_ai));
- }
- DBUG_DUMP("rows", m_rows_buf, data_size);
- res= res || write_data(m_rows_buf, (size_t) data_size);
-
- return res;
-
-}
-
-bool Rows_log_event::write_compressed()
-{
- uchar *m_rows_buf_tmp = m_rows_buf;
- uchar *m_rows_cur_tmp = m_rows_cur;
- bool ret = true;
- uint32 comlen, alloc_size;
- comlen= alloc_size= binlog_get_compress_len((uint32)(m_rows_cur_tmp - m_rows_buf_tmp));
- m_rows_buf = (uchar *)my_safe_alloca(alloc_size);
- if(m_rows_buf &&
- !binlog_buf_compress((const char *)m_rows_buf_tmp, (char *)m_rows_buf,
- (uint32)(m_rows_cur_tmp - m_rows_buf_tmp), &comlen))
- {
- m_rows_cur= comlen + m_rows_buf;
- ret= Log_event::write();
- }
- my_safe_afree(m_rows_buf, alloc_size);
- m_rows_buf= m_rows_buf_tmp;
- m_rows_cur= m_rows_cur_tmp;
- return ret;
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Rows_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- char const *const flagstr=
- get_flags(STMT_END_F) ? " flags: STMT_END_F" : "";
- size_t bytes= my_snprintf(buf, sizeof(buf),
- "table_id: %llu%s", m_table_id, flagstr);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-
-const char str_binlog[]= "\nBINLOG '\n";
-const char fmt_delim[]= "'%s\n";
-const char fmt_n_delim[]= "\n'%s";
-const char fmt_frag[]= "\nSET @binlog_fragment_%d ='\n";
-const char fmt_binlog2[]= "BINLOG @binlog_fragment_0, @binlog_fragment_1%s\n";
-
-/**
- Print an event "body" cache to @c file possibly in two fragments.
- Each fragement is optionally per @c do_wrap to produce an SQL statement.
-
- @param file a file to print to
- @param body the "body" IO_CACHE of event
- @param do_wrap whether to wrap base64-encoded strings with
- SQL cover.
- @param delimiter delimiter string
-
- @param is_verbose MDEV-10362 workraround parameter to pass
- info on presence of verbose printout in cache encoded data
-
- The function signals on any error through setting @c body->error to -1.
-*/
-bool copy_cache_to_file_wrapped(IO_CACHE *body,
- FILE *file,
- bool do_wrap,
- const char *delimiter,
- bool is_verbose)
-{
- const my_off_t cache_size= my_b_tell(body);
-
- if (reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE))
- goto err;
-
- if (!do_wrap)
- {
- my_b_copy_to_file(body, file, SIZE_T_MAX);
- }
- else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
- opt_binlog_rows_event_max_encoded_size)
- {
- /*
- 2 fragments can always represent near 1GB row-based
- base64-encoded event as two strings each of size less than
- max(max_allowed_packet). Greater number of fragments does not
- save from potential need to tweak (increase) @@max_allowed_packet
- before to process the fragments. So 2 is safe and enough.
-
- Split the big query when its packet size's estimation exceeds a
- limit. The estimate includes the maximum packet header
- contribution of non-compressed packet.
- */
- my_fprintf(file, fmt_frag, 0);
- if (my_b_copy_to_file(body, file, (size_t) cache_size/2 + 1))
- goto err;
- my_fprintf(file, fmt_n_delim, delimiter);
-
- my_fprintf(file, fmt_frag, 1);
- if (my_b_copy_to_file(body, file, SIZE_T_MAX))
- goto err;
- if (!is_verbose)
- my_fprintf(file, fmt_delim, delimiter);
-
- my_fprintf(file, fmt_binlog2, delimiter);
- }
- else
- {
- my_fprintf(file, str_binlog);
- if (my_b_copy_to_file(body, file, SIZE_T_MAX))
- goto err;
- if (!is_verbose)
- my_fprintf(file, fmt_delim, delimiter);
- }
- reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
-
- return false;
-
-err:
- body->error = -1;
- return true;
-}
-
-
-/**
- Print an event "body" cache to @c file possibly in two fragments.
- Each fragement is optionally per @c do_wrap to produce an SQL statement.
-
- @param file a file to print to
- @param body the "body" IO_CACHE of event
- @param do_wrap whether to wrap base64-encoded strings with
- SQL cover.
- @param delimiter delimiter string
-
- The function signals on any error through setting @c body->error to -1.
-*/
-bool copy_cache_to_string_wrapped(IO_CACHE *cache,
- LEX_STRING *to,
- bool do_wrap,
- const char *delimiter,
- bool is_verbose)
-{
- const my_off_t cache_size= my_b_tell(cache);
- // contribution to total size estimate of formating
- const size_t fmt_size=
- sizeof(str_binlog) + 2*(sizeof(fmt_frag) + 2 /* %d */) +
- sizeof(fmt_delim) + sizeof(fmt_n_delim) +
- sizeof(fmt_binlog2) +
- 3*PRINT_EVENT_INFO::max_delimiter_size;
-
- if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
- goto err;
-
- if (!(to->str= (char*) my_malloc((size_t)cache->end_of_file + fmt_size,
- MYF(0))))
- {
- perror("Out of memory: can't allocate memory in "
- "copy_cache_to_string_wrapped().");
- goto err;
- }
-
- if (!do_wrap)
- {
- if (my_b_read(cache, (uchar*) to->str,
- (to->length= (size_t)cache->end_of_file)))
- goto err;
- }
- else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
- opt_binlog_rows_event_max_encoded_size)
- {
- /*
- 2 fragments can always represent near 1GB row-based
- base64-encoded event as two strings each of size less than
- max(max_allowed_packet). Greater number of fragments does not
- save from potential need to tweak (increase) @@max_allowed_packet
- before to process the fragments. So 2 is safe and enough.
-
- Split the big query when its packet size's estimation exceeds a
- limit. The estimate includes the maximum packet header
- contribution of non-compressed packet.
- */
- char *str= to->str;
- size_t add_to_len;
-
- str += (to->length= sprintf(str, fmt_frag, 0));
- if (my_b_read(cache, (uchar*) str, (uint32) (cache_size/2 + 1)))
- goto err;
- str += (add_to_len = (uint32) (cache_size/2 + 1));
- to->length += add_to_len;
- str += (add_to_len= sprintf(str, fmt_n_delim, delimiter));
- to->length += add_to_len;
-
- str += (add_to_len= sprintf(str, fmt_frag, 1));
- to->length += add_to_len;
- if (my_b_read(cache, (uchar*) str, uint32(cache->end_of_file - (cache_size/2 + 1))))
- goto err;
- str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1)));
- to->length += add_to_len;
- if (!is_verbose)
- {
- str += (add_to_len= sprintf(str , fmt_delim, delimiter));
- to->length += add_to_len;
- }
- to->length += sprintf(str, fmt_binlog2, delimiter);
- }
- else
- {
- char *str= to->str;
-
- str += (to->length= sprintf(str, str_binlog));
- if (my_b_read(cache, (uchar*) str, (size_t)cache->end_of_file))
- goto err;
- str += cache->end_of_file;
- to->length += (size_t)cache->end_of_file;
- if (!is_verbose)
- to->length += sprintf(str , fmt_delim, delimiter);
- }
-
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
-
- return false;
-
-err:
- cache->error= -1;
- return true;
-}
-
-/**
- The function invokes base64 encoder to run on the current
- event string and store the result into two caches.
- When the event ends the current statement the caches are is copied into
- the argument file.
- Copying is also concerned how to wrap the event, specifically to produce
- a valid SQL syntax.
- When the encoded data size is within max(MAX_ALLOWED_PACKET)
- a regular BINLOG query is composed. Otherwise it is build as fragmented
-
- SET @binlog_fragment_0='...';
- SET @binlog_fragment_1='...';
- BINLOG @binlog_fragment_0, @binlog_fragment_1;
-
- where fragments are represented by a pair of indexed user
- "one shot" variables.
-
- @note
- If any changes made don't forget to duplicate them to
- Old_rows_log_event as long as it's supported.
-
- @param file pointer to IO_CACHE
- @param print_event_info pointer to print_event_info specializing
- what out of and how to print the event
- @param name the name of a table that the event operates on
-
- The function signals on any error of cache access through setting
- that cache's @c error to -1.
-*/
-bool Rows_log_event::print_helper(FILE *file,
- PRINT_EVENT_INFO *print_event_info,
- char const *const name)
-{
- IO_CACHE *const head= &print_event_info->head_cache;
- IO_CACHE *const body= &print_event_info->body_cache;
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- IO_CACHE *const sql= &print_event_info->review_sql_cache;
-#endif
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
- !print_event_info->short_form;
- bool const last_stmt_event= get_flags(STMT_END_F);
-
- if (!print_event_info->short_form)
- {
- char llbuff[22];
-
- print_header(head, print_event_info, !last_stmt_event);
- if (my_b_printf(head, "\t%s: table id %s%s\n",
- name, ullstr(m_table_id, llbuff),
- last_stmt_event ? " flags: STMT_END_F" : ""))
- goto err;
- }
- if (!print_event_info->short_form || print_event_info->print_row_count)
- if (print_base64(body, print_event_info, do_print_encoded))
- goto err;
-
- if (last_stmt_event)
- {
- if (!is_flashback)
- {
- if (copy_event_cache_to_file_and_reinit(head, file) ||
- copy_cache_to_file_wrapped(body, file, do_print_encoded,
- print_event_info->delimiter,
- print_event_info->verbose))
- goto err;
- }
- else
- {
- LEX_STRING tmp_str;
-
- if (copy_event_cache_to_string_and_reinit(head, &tmp_str))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated);
- my_free(tmp_str.str);
-
- if (copy_cache_to_string_wrapped(body, &tmp_str, do_print_encoded,
- print_event_info->delimiter,
- print_event_info->verbose))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length);
- my_free(tmp_str.str);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- if (copy_event_cache_to_string_and_reinit(sql, &tmp_str))
- return 1;
- output_buf.append(tmp_str.str, tmp_str.length);
- my_free(tmp_str.str);
-#endif
- }
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
/**************************************************************************
Annotate_rows_log_event member functions
**************************************************************************/
-#ifndef MYSQL_CLIENT
-Annotate_rows_log_event::Annotate_rows_log_event(THD *thd,
- bool using_trans,
- bool direct)
- : Log_event(thd, 0, using_trans),
- m_save_thd_query_txt(0),
- m_save_thd_query_len(0),
- m_saved_thd_query(false),
- m_used_query_txt(0)
-{
- m_query_txt= thd->query();
- m_query_len= thd->query_length();
- if (direct)
- cache_type= Log_event::EVENT_NO_CACHE;
-}
-#endif
-
Annotate_rows_log_event::Annotate_rows_log_event(const char *buf,
uint event_len,
const Format_description_log_event *desc)
@@ -12296,103 +3375,6 @@ bool Annotate_rows_log_event::is_valid() const
return (m_query_txt != NULL && m_query_len != 0);
}
-#ifndef MYSQL_CLIENT
-bool Annotate_rows_log_event::write_data_header()
-{
- return 0;
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-bool Annotate_rows_log_event::write_data_body()
-{
- return write_data(m_query_txt, m_query_len);
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-void Annotate_rows_log_event::pack_info(Protocol* protocol)
-{
- if (m_query_txt && m_query_len)
- protocol->store(m_query_txt, m_query_len, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-bool Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
-{
- char *pbeg; // beginning of the next line
- char *pend; // end of the next line
- uint cnt= 0; // characters counter
-
- if (!pinfo->short_form)
- {
- if (print_header(&pinfo->head_cache, pinfo, TRUE) ||
- my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n"))
- goto err;
- }
- else if (my_b_printf(&pinfo->head_cache, "# Annotate_rows:\n"))
- goto err;
-
- for (pbeg= m_query_txt; ; pbeg= pend)
- {
- // skip all \r's and \n's at the beginning of the next line
- for (;; pbeg++)
- {
- if (++cnt > m_query_len)
- return 0;
-
- if (*pbeg != '\r' && *pbeg != '\n')
- break;
- }
-
- // find end of the next line
- for (pend= pbeg + 1;
- ++cnt <= m_query_len && *pend != '\r' && *pend != '\n';
- pend++)
- ;
-
- // print next line
- if (my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4) ||
- my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg) ||
- my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int Annotate_rows_log_event::do_apply_event(rpl_group_info *rgi)
-{
- rgi->free_annotate_event();
- m_save_thd_query_txt= thd->query();
- m_save_thd_query_len= thd->query_length();
- m_saved_thd_query= true;
- m_used_query_txt= 1;
- thd->set_query(m_query_txt, m_query_len);
- return 0;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int Annotate_rows_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-#endif
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-Log_event::enum_skip_reason
-Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- return continue_group(rgi);
-}
-#endif
/**************************************************************************
Table_map_log_event member functions and support functions
@@ -12430,142 +3412,6 @@ Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
type used is uint32.
*/
-#if !defined(MYSQL_CLIENT)
-/**
- Save the field metadata based on the real_type of the field.
- The metadata saved depends on the type of the field. Some fields
- store a single byte for pack_length() while others store two bytes
- for field_length (max length).
-
- @retval 0 Ok.
-
- @todo
- We may want to consider changing the encoding of the information.
- Currently, the code attempts to minimize the number of bytes written to
- the tablemap. There are at least two other alternatives; 1) using
- net_store_length() to store the data allowing it to choose the number of
- bytes that are appropriate thereby making the code much easier to
- maintain (only 1 place to change the encoding), or 2) use a fixed number
- of bytes for each field. The problem with option 1 is that net_store_length()
- will use one byte if the value < 251, but 3 bytes if it is > 250. Thus,
- for fields like CHAR which can be no larger than 255 characters, the method
- will use 3 bytes when the value is > 250. Further, every value that is
- encoded using 2 parts (e.g., pack_length, field_length) will be numerically
- > 250 therefore will use 3 bytes for eah value. The problem with option 2
- is less wasteful for space but does waste 1 byte for every field that does
- not encode 2 parts.
-*/
-int Table_map_log_event::save_field_metadata()
-{
- DBUG_ENTER("Table_map_log_event::save_field_metadata");
- int index= 0;
- for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
- {
- DBUG_PRINT("debug", ("field_type: %d", m_coltype[i]));
- index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]);
- }
- DBUG_RETURN(index);
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
-/*
- Constructor used to build an event for writing to the binary log.
- Mats says tbl->s lives longer than this event so it's ok to copy pointers
- (tbl->s->db etc) and not pointer content.
- */
-#if !defined(MYSQL_CLIENT)
-Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
- bool is_transactional)
- : Log_event(thd, 0, is_transactional),
- m_table(tbl),
- m_dbnam(tbl->s->db.str),
- m_dblen(m_dbnam ? tbl->s->db.length : 0),
- m_tblnam(tbl->s->table_name.str),
- m_tbllen(tbl->s->table_name.length),
- m_colcnt(tbl->s->fields),
- m_memory(NULL),
- m_table_id(tid),
- m_flags(TM_BIT_LEN_EXACT_F),
- m_data_size(0),
- m_field_metadata(0),
- m_field_metadata_size(0),
- m_null_bits(0),
- m_meta_memory(NULL)
-{
- uchar cbuf[MAX_INT_WIDTH];
- uchar *cbuf_end;
- DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)");
- DBUG_ASSERT(m_table_id != ~0ULL);
- /*
- In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
- table.cc / alloc_table_share():
- Use the fact the key is db/0/table_name/0
- As we rely on this let's assert it.
- */
- DBUG_ASSERT((tbl->s->db.str == 0) ||
- (tbl->s->db.str[tbl->s->db.length] == 0));
- DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0);
-
-
- m_data_size= TABLE_MAP_HEADER_LEN;
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
- m_data_size+= m_dblen + 2; // Include length and terminating \0
- m_data_size+= m_tbllen + 2; // Include length and terminating \0
- cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
- DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
- m_data_size+= (cbuf_end - cbuf) + m_colcnt; // COLCNT and column types
-
- if (tbl->triggers)
- m_flags|= TM_BIT_HAS_TRIGGERS_F;
-
- /* If malloc fails, caught in is_valid() */
- if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
- {
- m_coltype= reinterpret_cast<uchar*>(m_memory);
- for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- m_coltype[i]= m_table->field[i]->binlog_type();
- }
-
- /*
- Calculate a bitmap for the results of maybe_null() for all columns.
- The bitmap is used to determine when there is a column from the master
- that is not on the slave and is null and thus not in the row data during
- replication.
- */
- uint num_null_bytes= (m_table->s->fields + 7) / 8;
- m_data_size+= num_null_bytes;
- m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
- &m_null_bits, num_null_bytes,
- &m_field_metadata, (m_colcnt * 2),
- NULL);
-
- bzero(m_field_metadata, (m_colcnt * 2));
-
- /*
- Create an array for the field metadata and store it.
- */
- m_field_metadata_size= save_field_metadata();
- DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
-
- /*
- Now set the size of the data to the size of the field metadata array
- plus one or three bytes (see pack.c:net_store_length) for number of
- elements in the field metadata array.
- */
- if (m_field_metadata_size < 251)
- m_data_size+= m_field_metadata_size + 1;
- else
- m_data_size+= m_field_metadata_size + 3;
-
- bzero(m_null_bits, num_null_bytes);
- for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
- if (m_table->field[i]->maybe_null())
- m_null_bits[(i / 8)]+= 1 << (i % 8);
-
- DBUG_VOID_RETURN;
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
/*
Constructor used by slave to read the event from the binary log.
*/
@@ -12685,494 +3531,10 @@ Table_map_log_event::~Table_map_log_event()
}
-#ifdef MYSQL_CLIENT
-
-/*
- Rewrite database name for the event to name specified by new_db
- SYNOPSIS
- new_db Database name to change to
- new_len Length
- desc Event describing binlog that we're writing to.
-
- DESCRIPTION
- Reset db name. This function assumes that temp_buf member contains event
- representation taken from a binary log. It resets m_dbnam and m_dblen and
- rewrites temp_buf with new db name.
-
- RETURN
- 0 - Success
- other - Error
-*/
-
-int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len,
- const Format_description_log_event* desc)
-{
- DBUG_ENTER("Table_map_log_event::rewrite_db");
- DBUG_ASSERT(temp_buf);
-
- uint header_len= MY_MIN(desc->common_header_len,
- LOG_EVENT_MINIMAL_HEADER_LEN) + TABLE_MAP_HEADER_LEN;
- int len_diff;
-
- if (!(len_diff= (int)(new_len - m_dblen)))
- {
- memcpy((void*) (temp_buf + header_len + 1), new_db, m_dblen + 1);
- memcpy((void*) m_dbnam, new_db, m_dblen + 1);
- DBUG_RETURN(0);
- }
-
- // Create new temp_buf
- ulong event_cur_len= uint4korr(temp_buf + EVENT_LEN_OFFSET);
- ulong event_new_len= event_cur_len + len_diff;
- char* new_temp_buf= (char*) my_malloc(event_new_len, MYF(MY_WME));
-
- if (!new_temp_buf)
- {
- sql_print_error("Table_map_log_event::rewrite_db: "
- "failed to allocate new temp_buf (%d bytes required)",
- event_new_len);
- DBUG_RETURN(-1);
- }
-
- // Rewrite temp_buf
- char* ptr= new_temp_buf;
- size_t cnt= 0;
-
- // Copy header and change event length
- memcpy(ptr, temp_buf, header_len);
- int4store(ptr + EVENT_LEN_OFFSET, event_new_len);
- ptr += header_len;
- cnt += header_len;
-
- // Write new db name length and new name
- DBUG_ASSERT(new_len < 0xff);
- *ptr++ = (char)new_len;
- memcpy(ptr, new_db, new_len + 1);
- ptr += new_len + 1;
- cnt += m_dblen + 2;
-
- // Copy rest part
- memcpy(ptr, temp_buf + cnt, event_cur_len - cnt);
-
- // Reregister temp buf
- free_temp_buf();
- register_temp_buf(new_temp_buf, TRUE);
-
- // Reset m_dbnam and m_dblen members
- m_dblen= new_len;
-
- // m_dbnam resides in m_memory together with m_tblnam and m_coltype
- uchar* memory= m_memory;
- char const* tblnam= m_tblnam;
- uchar* coltype= m_coltype;
-
- m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
- &m_dbnam, (uint) m_dblen + 1,
- &m_tblnam, (uint) m_tbllen + 1,
- &m_coltype, (uint) m_colcnt,
- NullS);
-
- if (!m_memory)
- {
- sql_print_error("Table_map_log_event::rewrite_db: "
- "failed to allocate new m_memory (%d + %d + %d bytes required)",
- m_dblen + 1, m_tbllen + 1, m_colcnt);
- DBUG_RETURN(-1);
- }
-
- memcpy((void*)m_dbnam, new_db, m_dblen + 1);
- memcpy((void*)m_tblnam, tblnam, m_tbllen + 1);
- memcpy(m_coltype, coltype, m_colcnt);
-
- my_free(memory);
- DBUG_RETURN(0);
-}
-#endif /* MYSQL_CLIENT */
-
-
-/*
- Return value is an error code, one of:
-
- -1 Failure to open table [from open_tables()]
- 0 Success
- 1 No room for more tables [from set_table()]
- 2 Out of memory [from set_table()]
- 3 Wrong table definition
- 4 Daisy-chaining RBR with SBR not possible
- */
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-enum enum_tbl_map_status
-{
- /* no duplicate identifier found */
- OK_TO_PROCESS= 0,
-
- /* this table map must be filtered out */
- FILTERED_OUT= 1,
-
- /* identifier mapping table with different properties */
- SAME_ID_MAPPING_DIFFERENT_TABLE= 2,
-
- /* a duplicate identifier was found mapping the same table */
- SAME_ID_MAPPING_SAME_TABLE= 3
-};
-
-/*
- Checks if this table map event should be processed or not. First
- it checks the filtering rules, and then looks for duplicate identifiers
- in the existing list of rli->tables_to_lock.
-
- It checks that there hasn't been any corruption by verifying that there
- are no duplicate entries with different properties.
-
- In some cases, some binary logs could get corrupted, showing several
- tables mapped to the same table_id, 0 (see: BUG#56226). Thus we do this
- early sanity check for such cases and avoid that the server crashes
- later.
-
- In some corner cases, the master logs duplicate table map events, i.e.,
- same id, same database name, same table name (see: BUG#37137). This is
- different from the above as it's the same table that is mapped again
- to the same identifier. Thus we cannot just check for same ids and
- assume that the event is corrupted we need to check every property.
-
- NOTE: in the event that BUG#37137 ever gets fixed, this extra check
- will still be valid because we would need to support old binary
- logs anyway.
-
- @param rli The relay log info reference.
- @param table_list A list element containing the table to check against.
- @return OK_TO_PROCESS
- if there was no identifier already in rli->tables_to_lock
-
- FILTERED_OUT
- if the event is filtered according to the filtering rules
-
- SAME_ID_MAPPING_DIFFERENT_TABLE
- if the same identifier already maps a different table in
- rli->tables_to_lock
-
- SAME_ID_MAPPING_SAME_TABLE
- if the same identifier already maps the same table in
- rli->tables_to_lock.
-*/
-static enum_tbl_map_status
-check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
-{
- DBUG_ENTER("check_table_map");
- enum_tbl_map_status res= OK_TO_PROCESS;
- Relay_log_info *rli= rgi->rli;
- if ((rgi->thd->slave_thread /* filtering is for slave only */ ||
- IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) &&
- (!rli->mi->rpl_filter->db_ok(table_list->db.str) ||
- (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list))))
- res= FILTERED_OUT;
- else
- {
- RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rgi->tables_to_lock);
- for(uint i=0 ; ptr && (i< rgi->tables_to_lock_count);
- ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local), i++)
- {
- if (ptr->table_id == table_list->table_id)
- {
-
- if (cmp(&ptr->db, &table_list->db) ||
- cmp(&ptr->alias, &table_list->table_name) ||
- ptr->lock_type != TL_WRITE) // the ::do_apply_event always sets TL_WRITE
- res= SAME_ID_MAPPING_DIFFERENT_TABLE;
- else
- res= SAME_ID_MAPPING_SAME_TABLE;
-
- break;
- }
- }
- }
-
- DBUG_PRINT("debug", ("check of table map ended up with: %u", res));
-
- DBUG_RETURN(res);
-}
-
-int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
-{
- RPL_TABLE_LIST *table_list;
- char *db_mem, *tname_mem, *ptr;
- size_t dummy_len, db_mem_length, tname_mem_length;
- void *memory;
- Rpl_filter *filter;
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Table_map_log_event::do_apply_event(Relay_log_info*)");
-
- /* Step the query id to mark what columns that are actually used. */
- thd->set_query_id(next_query_id());
-
- if (!(memory= my_multi_malloc(MYF(MY_WME),
- &table_list, (uint) sizeof(RPL_TABLE_LIST),
- &db_mem, (uint) NAME_LEN + 1,
- &tname_mem, (uint) NAME_LEN + 1,
- NullS)))
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
-
- db_mem_length= strmov(db_mem, m_dbnam) - db_mem;
- tname_mem_length= strmov(tname_mem, m_tblnam) - tname_mem;
- if (lower_case_table_names)
- {
- my_casedn_str(files_charset_info, (char*)tname_mem);
- my_casedn_str(files_charset_info, (char*)db_mem);
- }
-
- /* call from mysql_client_binlog_statement() will not set rli->mi */
- filter= rgi->thd->slave_thread ? rli->mi->rpl_filter : global_rpl_filter;
-
- /* rewrite rules changed the database */
- if (((ptr= (char*) filter->get_rewrite_db(db_mem, &dummy_len)) != db_mem))
- db_mem_length= strmov(db_mem, ptr) - db_mem;
-
- LEX_CSTRING tmp_db_name= {db_mem, db_mem_length };
- LEX_CSTRING tmp_tbl_name= {tname_mem, tname_mem_length };
-
- table_list->init_one_table(&tmp_db_name, &tmp_tbl_name, 0, TL_WRITE);
- table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
- table_list->updating= 1;
- table_list->required_type= TABLE_TYPE_NORMAL;
-
- DBUG_PRINT("debug", ("table: %s is mapped to %llu",
- table_list->table_name.str,
- table_list->table_id));
- table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0);
- DBUG_PRINT("debug", ("table->master_had_triggers=%d",
- (int)table_list->master_had_triggers));
-
- enum_tbl_map_status tblmap_status= check_table_map(rgi, table_list);
- if (tblmap_status == OK_TO_PROCESS)
- {
- DBUG_ASSERT(thd->lex->query_tables != table_list);
-
- /*
- Use placement new to construct the table_def instance in the
- memory allocated for it inside table_list.
-
- The memory allocated by the table_def structure (i.e., not the
- memory allocated *for* the table_def structure) is released
- inside Relay_log_info::clear_tables_to_lock() by calling the
- table_def destructor explicitly.
- */
- new (&table_list->m_tabledef)
- table_def(m_coltype, m_colcnt,
- m_field_metadata, m_field_metadata_size,
- m_null_bits, m_flags);
- table_list->m_tabledef_valid= TRUE;
- table_list->m_conv_table= NULL;
- table_list->open_type= OT_BASE_ONLY;
-
- /*
- We record in the slave's information that the table should be
- locked by linking the table into the list of tables to lock.
- */
- table_list->next_global= table_list->next_local= rgi->tables_to_lock;
- rgi->tables_to_lock= table_list;
- rgi->tables_to_lock_count++;
- /* 'memory' is freed in clear_tables_to_lock */
- }
- else // FILTERED_OUT, SAME_ID_MAPPING_*
- {
- /*
- If mapped already but with different properties, we raise an
- error.
- If mapped already but with same properties we skip the event.
- If filtered out we skip the event.
-
- In all three cases, we need to free the memory previously
- allocated.
- */
- if (tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE)
- {
- /*
- Something bad has happened. We need to stop the slave as strange things
- could happen if we proceed: slave crash, wrong table being updated, ...
- As a consequence we push an error in this case.
- */
-
- char buf[256];
-
- my_snprintf(buf, sizeof(buf),
- "Found table map event mapping table id %u which "
- "was already mapped but with different settings.",
- table_list->table_id);
-
- if (thd->slave_thread)
- rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
- else
- /*
- For the cases in which a 'BINLOG' statement is set to
- execute in a user session
- */
- my_error(ER_SLAVE_FATAL_ERROR, MYF(0), buf);
- }
-
- my_free(memory);
- }
-
- DBUG_RETURN(tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE);
-}
-
-Log_event::enum_skip_reason
-Table_map_log_event::do_shall_skip(rpl_group_info *rgi)
-{
- /*
- If the slave skip counter is 1, then we should not start executing
- on the next event.
- */
- return continue_group(rgi);
-}
-
-int Table_map_log_event::do_update_pos(rpl_group_info *rgi)
-{
- rgi->inc_event_relay_log_pos();
- return 0;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifndef MYSQL_CLIENT
-bool Table_map_log_event::write_data_header()
-{
- DBUG_ASSERT(m_table_id != ~0ULL);
- uchar buf[TABLE_MAP_HEADER_LEN];
- DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
- {
- int4store(buf + 0, m_table_id);
- int2store(buf + 4, m_flags);
- return (write_data(buf, 6));
- });
- int6store(buf + TM_MAPID_OFFSET, m_table_id);
- int2store(buf + TM_FLAGS_OFFSET, m_flags);
- return write_data(buf, TABLE_MAP_HEADER_LEN);
-}
-
-bool Table_map_log_event::write_data_body()
-{
- DBUG_ASSERT(m_dbnam != NULL);
- DBUG_ASSERT(m_tblnam != NULL);
- /* We use only one byte per length for storage in event: */
- DBUG_ASSERT(m_dblen <= MY_MIN(NAME_LEN, 255));
- DBUG_ASSERT(m_tbllen <= MY_MIN(NAME_LEN, 255));
-
- uchar const dbuf[]= { (uchar) m_dblen };
- uchar const tbuf[]= { (uchar) m_tbllen };
-
- uchar cbuf[MAX_INT_WIDTH];
- uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
- DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
-
- /*
- Store the size of the field metadata.
- */
- uchar mbuf[MAX_INT_WIDTH];
- uchar *const mbuf_end= net_store_length(mbuf, m_field_metadata_size);
-
- return write_data(dbuf, sizeof(dbuf)) ||
- write_data(m_dbnam, m_dblen+1) ||
- write_data(tbuf, sizeof(tbuf)) ||
- write_data(m_tblnam, m_tbllen+1) ||
- write_data(cbuf, (size_t) (cbuf_end - cbuf)) ||
- write_data(m_coltype, m_colcnt) ||
- write_data(mbuf, (size_t) (mbuf_end - mbuf)) ||
- write_data(m_field_metadata, m_field_metadata_size),
- write_data(m_null_bits, (m_colcnt + 7) / 8);
- }
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-
-/*
- Print some useful information for the SHOW BINARY LOG information
- field.
- */
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-void Table_map_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- size_t bytes= my_snprintf(buf, sizeof(buf),
- "table_id: %llu (%s.%s)",
- m_table_id, m_dbnam, m_tblnam);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
-
-
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
-{
- if (!print_event_info->short_form)
- {
- char llbuff[22];
-
- print_header(&print_event_info->head_cache, print_event_info, TRUE);
- if (my_b_printf(&print_event_info->head_cache,
- "\tTable_map: %`s.%`s mapped to number %s%s\n",
- m_dbnam, m_tblnam, ullstr(m_table_id, llbuff),
- ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
- " (has triggers)" : "")))
- goto err;
- }
- if (!print_event_info->short_form || print_event_info->print_row_count)
- {
- bool do_print_encoded=
- print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
- print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
- !print_event_info->short_form;
-
- if (print_base64(&print_event_info->body_cache, print_event_info,
- do_print_encoded) ||
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
- file))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
/**************************************************************************
Write_rows_log_event member functions
**************************************************************************/
-/*
- Constructor used to build an event for writing to the binary log.
- */
-#if !defined(MYSQL_CLIENT)
-Write_rows_log_event::Write_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- :Rows_log_event(thd_arg, tbl_arg, tid_arg, tbl_arg->rpl_write_set,
- is_transactional, WRITE_ROWS_EVENT_V1)
-{
-}
-
-Write_rows_compressed_log_event::Write_rows_compressed_log_event(
- THD *thd_arg,
- TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- : Write_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
-{
- m_type = WRITE_ROWS_COMPRESSED_EVENT_V1;
-}
-
-bool Write_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-#endif
/*
Constructor used by slave to read the event from the binary log.
@@ -13195,1121 +3557,11 @@ Write_rows_compressed_log_event::Write_rows_compressed_log_event(
}
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-int
-Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- int error= 0;
-
- /*
- Increment the global status insert count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_INSERT]);
-
- /**
- todo: to introduce a property for the event (handler?) which forces
- applying the event in the replace (idempotent) fashion.
- */
- if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
- {
- /*
- We are using REPLACE semantics and not INSERT IGNORE semantics
- when writing rows, that is: new rows replace old rows. We need to
- inform the storage engine that it should use this behaviour.
- */
-
- /* Tell the storage engine that we are using REPLACE semantics. */
- thd->lex->duplicates= DUP_REPLACE;
-
- /*
- Pretend we're executing a REPLACE command: this is needed for
- InnoDB since it is not (properly) checking the lex->duplicates flag.
- */
- thd->lex->sql_command= SQLCOM_REPLACE;
- /*
- Do not raise the error flag in case of hitting to an unique attribute
- */
- m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- /*
- The following is needed in case if we have AFTER DELETE triggers.
- */
- m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
- m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
- }
- if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
- m_table->prepare_triggers_for_insert_stmt_or_event();
-
- /* Honor next number column if present */
- m_table->next_number_field= m_table->found_next_number_field;
- /*
- * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new
- * sequence numbers for auto_increment fields if the values of them are 0.
- * If generateing a sequence number is decided by the values of
- * table->auto_increment_field_not_null and SQL_MODE(if includes
- * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
- * SQL_MODE of slave sql thread is always consistency with master's.
- * In RBR, auto_increment fields never are NULL, except if the auto_inc
- * column exists only on the slave side (i.e., in an extra column
- * on the slave's table).
- */
- if (!is_auto_inc_in_extra_columns())
- m_table->auto_increment_field_not_null= TRUE;
- else
- {
- /*
- Here we have checked that there is an extra field
- on this server's table that has an auto_inc column.
-
- Mark that the auto_increment field is null and mark
- the read and write set bits.
-
- (There can only be one AUTO_INC column, it is always
- indexed and it cannot have a DEFAULT value).
- */
- m_table->auto_increment_field_not_null= FALSE;
- m_table->mark_auto_increment_column();
- }
-
- return error;
-}
-
-int
-Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
-{
- int local_error= 0;
-
- /**
- Clear the write_set bit for auto_inc field that only
- existed on the destination table as an extra column.
- */
- if (is_auto_inc_in_extra_columns())
- {
- bitmap_clear_bit(m_table->rpl_write_set,
- m_table->next_number_field->field_index);
- bitmap_clear_bit(m_table->read_set,
- m_table->next_number_field->field_index);
-
- if (get_flags(STMT_END_F))
- m_table->file->ha_release_auto_increment();
- }
- m_table->next_number_field=0;
- m_table->auto_increment_field_not_null= FALSE;
- if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
- {
- m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
- m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- /*
- resetting the extra with
- table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY);
- fires bug#27077
- explanation: file->reset() performs this duty
- ultimately. Still todo: fix
- */
- }
- if (unlikely((local_error= m_table->file->ha_end_bulk_insert())))
- {
- m_table->file->print_error(local_error, MYF(0));
- }
- return error? error : local_error;
-}
-
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-bool Rows_log_event::process_triggers(trg_event_type event,
- trg_action_time_type time_type,
- bool old_row_is_record1)
-{
- bool result;
- DBUG_ENTER("Rows_log_event::process_triggers");
- m_table->triggers->mark_fields_used(event);
- if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
- {
- tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
- result= m_table->triggers->process_triggers(thd, event,
- time_type, old_row_is_record1);
- reenable_binlog(thd);
- }
- else
- result= m_table->triggers->process_triggers(thd, event,
- time_type, old_row_is_record1);
-
- DBUG_RETURN(result);
-}
-/*
- Check if there are more UNIQUE keys after the given key.
-*/
-static int
-last_uniq_key(TABLE *table, uint keyno)
-{
- while (++keyno < table->s->keys)
- if (table->key_info[keyno].flags & HA_NOSAME)
- return 0;
- return 1;
-}
-
-/**
- Check if an error is a duplicate key error.
-
- This function is used to check if an error code is one of the
- duplicate key error, i.e., and error code for which it is sensible
- to do a <code>get_dup_key()</code> to retrieve the duplicate key.
-
- @param errcode The error code to check.
-
- @return <code>true</code> if the error code is such that
- <code>get_dup_key()</code> will return true, <code>false</code>
- otherwise.
- */
-bool
-is_duplicate_key_error(int errcode)
-{
- switch (errcode)
- {
- case HA_ERR_FOUND_DUPP_KEY:
- case HA_ERR_FOUND_DUPP_UNIQUE:
- return true;
- }
- return false;
-}
-
-/**
- Write the current row into event's table.
-
- The row is located in the row buffer, pointed by @c m_curr_row member.
- Number of columns of the row is stored in @c m_width member (it can be
- different from the number of columns in the table to which we insert).
- Bitmap @c m_cols indicates which columns are present in the row. It is assumed
- that event's table is already open and pointed by @c m_table.
-
- If the same record already exists in the table it can be either overwritten
- or an error is reported depending on the value of @c overwrite flag
- (error reporting not yet implemented). Note that the matching record can be
- different from the row we insert if we use primary keys to identify records in
- the table.
-
- The row to be inserted can contain values only for selected columns. The
- missing columns are filled with default values using @c prepare_record()
- function. If a matching record is found in the table and @c overwritte is
- true, the missing columns are taken from it.
-
- @param rli Relay log info (needed for row unpacking).
- @param overwrite
- Shall we overwrite if the row already exists or signal
- error (currently ignored).
-
- @returns Error code on failure, 0 on success.
-
- This method, if successful, sets @c m_curr_row_end pointer to point at the
- next row in the rows buffer. This is done when unpacking the row to be
- inserted.
-
- @note If a matching record is found, it is either updated using
- @c ha_update_row() or first deleted and then new record written.
-*/
-
-int
-Rows_log_event::write_row(rpl_group_info *rgi,
- const bool overwrite)
-{
- DBUG_ENTER("write_row");
- DBUG_ASSERT(m_table != NULL && thd != NULL);
-
- TABLE *table= m_table; // pointer to event's table
- int error;
- int UNINIT_VAR(keynum);
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && table->triggers;
- auto_afree_ptr<char> key(NULL);
-
- prepare_record(table, m_width, true);
-
- /* unpack row into table->record[0] */
- if (unlikely((error= unpack_current_row(rgi))))
- {
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
-
- if (m_curr_row == m_rows_buf && !invoke_triggers)
- {
- /*
- This table has no triggers so we can do bulk insert.
-
- This is the first row to be inserted, we estimate the rows with
- the size of the first row and use that value to initialize
- storage engine for bulk insertion.
- */
- /* this is the first row to be inserted, we estimate the rows with
- the size of the first row and use that value to initialize
- storage engine for bulk insertion */
- DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
- ha_rows estimated_rows= 0;
- if (m_curr_row < m_curr_row_end)
- estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
- else if (m_curr_row == m_curr_row_end)
- estimated_rows= 1;
-
- table->file->ha_start_bulk_insert(estimated_rows);
- }
-
- /*
- Explicitly set the auto_inc to null to make sure that
- it gets an auto_generated value.
- */
- if (is_auto_inc_in_extra_columns())
- m_table->next_number_field->set_null();
-
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
- DBUG_PRINT_BITSET("debug", "rpl_write_set: %s", table->rpl_write_set);
- DBUG_PRINT_BITSET("debug", "read_set: %s", table->read_set);
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE)))
- {
- DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
- }
-
- // Handle INSERT.
- if (table->versioned(VERS_TIMESTAMP))
- {
- ulong sec_part;
- bitmap_set_bit(table->read_set, table->vers_start_field()->field_index);
- // Check whether a row came from unversioned table and fix vers fields.
- if (table->vers_start_field()->get_timestamp(&sec_part) == 0 && sec_part == 0)
- table->vers_update_fields();
- }
-
- /*
- Try to write record. If a corresponding record already exists in the table,
- we try to change it using ha_update_row() if possible. Otherwise we delete
- it and repeat the whole process again.
-
- TODO: Add safety measures against infinite looping.
- */
-
- if (table->s->sequence)
- error= update_sequence();
- else while (unlikely(error= table->file->ha_write_row(table->record[0])))
- {
- if (error == HA_ERR_LOCK_DEADLOCK ||
- error == HA_ERR_LOCK_WAIT_TIMEOUT ||
- (keynum= table->file->get_dup_key(error)) < 0 ||
- !overwrite)
- {
- DBUG_PRINT("info",("get_dup_key returns %d)", keynum));
- /*
- Deadlock, waiting for lock or just an error from the handler
- such as HA_ERR_FOUND_DUPP_KEY when overwrite is false.
- Retrieval of the duplicate key number may fail
- - either because the error was not "duplicate key" error
- - or because the information which key is not available
- */
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- /*
- We need to retrieve the old row into record[1] to be able to
- either update or delete the offending record. We either:
-
- - use rnd_pos() with a row-id (available as dupp_row) to the
- offending row, if that is possible (MyISAM and Blackhole), or else
-
- - use index_read_idx() with the key that is duplicated, to
- retrieve the offending row.
- */
- if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
- {
- DBUG_PRINT("info",("Locating offending record using rnd_pos()"));
-
- if ((error= table->file->ha_rnd_init_with_error(0)))
- {
- DBUG_RETURN(error);
- }
-
- error= table->file->ha_rnd_pos(table->record[1], table->file->dup_ref);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("rnd_pos() returns error %d",error));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- table->file->ha_rnd_end();
- }
- else
- {
- DBUG_PRINT("info",("Locating offending record using index_read_idx()"));
-
- if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
- {
- DBUG_PRINT("info",("Error when setting HA_EXTRA_FLUSH_CACHE"));
- DBUG_RETURN(my_errno);
- }
-
- if (key.get() == NULL)
- {
- key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
- if (key.get() == NULL)
- {
- DBUG_PRINT("info",("Can't allocate key buffer"));
- DBUG_RETURN(ENOMEM);
- }
- }
-
- key_copy((uchar*)key.get(), table->record[0], table->key_info + keynum,
- 0);
- error= table->file->ha_index_read_idx_map(table->record[1], keynum,
- (const uchar*)key.get(),
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error)));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- }
-
- /*
- Now, record[1] should contain the offending row. That
- will enable us to update it or, alternatively, delete it (so
- that we can insert the new row afterwards).
- */
-
- /*
- If row is incomplete we will use the record found to fill
- missing columns.
- */
- if (!get_flags(COMPLETE_ROWS_F))
- {
- restore_record(table,record[1]);
- error= unpack_current_row(rgi);
- }
-
- DBUG_PRINT("debug",("preparing for update: before and after image"));
- DBUG_DUMP("record[1] (before)", table->record[1], table->s->reclength);
- DBUG_DUMP("record[0] (after)", table->record[0], table->s->reclength);
-
- /*
- REPLACE is defined as either INSERT or DELETE + INSERT. If
- possible, we can replace it with an UPDATE, but that will not
- work on InnoDB if FOREIGN KEY checks are necessary.
-
- I (Matz) am not sure of the reason for the last_uniq_key()
- check as, but I'm guessing that it's something along the
- following lines.
-
- Suppose that we got the duplicate key to be a key that is not
- the last unique key for the table and we perform an update:
- then there might be another key for which the unique check will
- fail, so we're better off just deleting the row and inserting
- the correct row.
-
- Additionally we don't use UPDATE if rbr triggers should be invoked -
- when triggers are used we want a simple and predictable execution path.
- */
- if (last_uniq_key(table, keynum) && !invoke_triggers &&
- !table->file->referenced_by_foreign_key())
- {
- DBUG_PRINT("info",("Updating row using ha_update_row()"));
- error= table->file->ha_update_row(table->record[1],
- table->record[0]);
- switch (error) {
-
- case HA_ERR_RECORD_IS_THE_SAME:
- DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
- " ha_update_row()"));
- error= 0;
-
- case 0:
- break;
-
- default:
- DBUG_PRINT("info",("ha_update_row() returns error %d",error));
- table->file->print_error(error, MYF(0));
- }
-
- DBUG_RETURN(error);
- }
- else
- {
- DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE,
- TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- else
- {
- if (unlikely((error= table->file->ha_delete_row(table->record[1]))))
- {
- DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
- table->file->print_error(error, MYF(0));
- DBUG_RETURN(error);
- }
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER,
- TRUE)))
- DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
- }
- /* Will retry ha_write_row() with the offending row removed. */
- }
- }
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
-
- DBUG_RETURN(error);
-}
-
-
-int Rows_log_event::update_sequence()
-{
- TABLE *table= m_table; // pointer to event's table
-
- if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO))
- {
- /* This event come from a setval function executed on the master.
- Update the sequence next_number and round, like we do with setval()
- */
- my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
- table->read_set);
- longlong nextval= table->field[NEXT_FIELD_NO]->val_int();
- longlong round= table->field[ROUND_FIELD_NO]->val_int();
- dbug_tmp_restore_column_map(table->read_set, old_map);
-
- return table->s->sequence->set_value(table, nextval, round, 0) > 0;
- }
-
- /*
- Update all fields in table and update the active sequence, like with
- ALTER SEQUENCE
- */
- return table->file->ha_write_row(table->record[0]);
-}
-
-
-#endif
-
-int
-Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
-{
- DBUG_ASSERT(m_table != NULL);
- const char *tmp= thd->get_proc_info();
- const char *message= "Write_rows_log_event::write_row()";
- int error;
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Write_rows_log_event::write_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
- thd_proc_info(thd, tmp);
-
- if (unlikely(error) && unlikely(!thd->is_error()))
- {
- DBUG_ASSERT(0);
- my_error(ER_UNKNOWN_ERROR, MYF(0));
- }
-
- return error;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifdef MYSQL_CLIENT
-bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
-{
- DBUG_EXECUTE_IF("simulate_cache_read_error",
- {DBUG_SET("+d,simulate_my_b_fill_error");});
- return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
-}
-
-bool Write_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- char *new_buf;
- ulong len;
- bool is_malloc = false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Write_compressed_rows"))
- goto err;
- }
- else
- {
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress write_compressed_rows failed\n"))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Write_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) |
- trg2bit(TRG_EVENT_DELETE);
-}
-#endif
/**************************************************************************
Delete_rows_log_event member functions
**************************************************************************/
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-/*
- Compares table->record[0] and table->record[1]
-
- Returns TRUE if different.
-*/
-static bool record_compare(TABLE *table)
-{
- bool result= FALSE;
- /**
- Compare full record only if:
- - there are no blob fields (otherwise we would also need
- to compare blobs contents as well);
- - there are no varchar fields (otherwise we would also need
- to compare varchar contents as well);
- - there are no null fields, otherwise NULLed fields
- contents (i.e., the don't care bytes) may show arbitrary
- values, depending on how each engine handles internally.
- */
- if ((table->s->blob_fields +
- table->s->varchar_fields +
- table->s->null_fields) == 0)
- {
- result= cmp_record(table,record[1]);
- goto record_compare_exit;
- }
-
- /* Compare null bits */
- if (memcmp(table->null_flags,
- table->null_flags+table->s->rec_buff_length,
- table->s->null_bytes))
- {
- result= TRUE; // Diff in NULL value
- goto record_compare_exit;
- }
-
- /* Compare fields */
- for (Field **ptr=table->field ; *ptr ; ptr++)
- {
- if (table->versioned() && (*ptr)->vers_sys_field())
- {
- continue;
- }
- /**
- We only compare field contents that are not null.
- NULL fields (i.e., their null bits) were compared
- earlier.
- */
- if (!(*(ptr))->is_null())
- {
- if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
- {
- result= TRUE;
- goto record_compare_exit;
- }
- }
- }
-
-record_compare_exit:
- return result;
-}
-
-
-/**
- Find the best key to use when locating the row in @c find_row().
-
- A primary key is preferred if it exists; otherwise a unique index is
- preferred. Else we pick the index with the smalles rec_per_key value.
-
- If a suitable key is found, set @c m_key, @c m_key_nr and @c m_key_info
- member fields appropriately.
-
- @returns Error code on failure, 0 on success.
-*/
-int Rows_log_event::find_key()
-{
- uint i, best_key_nr, last_part;
- KEY *key, *UNINIT_VAR(best_key);
- ulong UNINIT_VAR(best_rec_per_key), tmp;
- DBUG_ENTER("Rows_log_event::find_key");
- DBUG_ASSERT(m_table);
-
- best_key_nr= MAX_KEY;
-
- /*
- Keys are sorted so that any primary key is first, followed by unique keys,
- followed by any other. So we will automatically pick the primary key if
- it exists.
- */
- for (i= 0, key= m_table->key_info; i < m_table->s->keys; i++, key++)
- {
- if (!m_table->s->keys_in_use.is_set(i))
- continue;
- /*
- We cannot use a unique key with NULL-able columns to uniquely identify
- a row (but we can still select it for range scan below if nothing better
- is available).
- */
- if ((key->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
- {
- best_key_nr= i;
- best_key= key;
- break;
- }
- /*
- We can only use a non-unique key if it allows range scans (ie. skip
- FULLTEXT indexes and such).
- */
- last_part= key->user_defined_key_parts - 1;
- DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu",
- key->name.str, last_part, key->rec_per_key[last_part]));
- if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT))
- continue;
-
- tmp= key->rec_per_key[last_part];
- if (best_key_nr == MAX_KEY || (tmp > 0 && tmp < best_rec_per_key))
- {
- best_key_nr= i;
- best_key= key;
- best_rec_per_key= tmp;
- }
- }
-
- if (best_key_nr == MAX_KEY)
- {
- m_key_info= NULL;
- DBUG_RETURN(0);
- }
-
- // Allocate buffer for key searches
- m_key= (uchar *) my_malloc(best_key->key_length, MYF(MY_WME));
- if (m_key == NULL)
- DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- m_key_info= best_key;
- m_key_nr= best_key_nr;
-
- DBUG_RETURN(0);;
-}
-
-
-/*
- Check if we are already spending too much time on this statement.
- if we are, warn user that it might be because table does not have
- a PK, but only if the warning was not printed before for this STMT.
-
- @param type The event type code.
- @param table_name The name of the table that the slave is
- operating.
- @param is_index_scan States whether the slave is doing an index scan
- or not.
- @param rli The relay metadata info.
-*/
-static inline
-void issue_long_find_row_warning(Log_event_type type,
- const char *table_name,
- bool is_index_scan,
- rpl_group_info *rgi)
-{
- if ((global_system_variables.log_warnings > 1 &&
- !rgi->is_long_find_row_note_printed()))
- {
- ulonglong now= microsecond_interval_timer();
- ulonglong stmt_ts= rgi->get_row_stmt_start_timestamp();
-
- DBUG_EXECUTE_IF("inject_long_find_row_note",
- stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2*HRTIME_RESOLUTION););
-
- longlong delta= (now - stmt_ts)/HRTIME_RESOLUTION;
-
- if (delta > LONG_FIND_ROW_THRESHOLD)
- {
- rgi->set_long_find_row_note_printed();
- const char* evt_type= LOG_EVENT_IS_DELETE_ROW(type) ? " DELETE" : "n UPDATE";
- const char* scan_type= is_index_scan ? "scanning an index" : "scanning the table";
-
- sql_print_information("The slave is applying a ROW event on behalf of a%s statement "
- "on table %s and is currently taking a considerable amount "
- "of time (%lld seconds). This is due to the fact that it is %s "
- "while looking up records to be processed. Consider adding a "
- "primary key (or unique key) to the table to improve "
- "performance.",
- evt_type, table_name, (long) delta, scan_type);
- }
- }
-}
-
-
-/*
- HA_ERR_KEY_NOT_FOUND is a fatal error normally, but it's an expected
- error in speculate optimistic mode, so use something non-fatal instead
-*/
-static int row_not_found_error(rpl_group_info *rgi)
-{
- return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC
- ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED;
-}
-
-/**
- Locate the current row in event's table.
-
- The current row is pointed by @c m_curr_row. Member @c m_width tells
- how many columns are there in the row (this can be differnet from
- the number of columns in the table). It is assumed that event's
- table is already open and pointed by @c m_table.
-
- If a corresponding record is found in the table it is stored in
- @c m_table->record[0]. Note that when record is located based on a primary
- key, it is possible that the record found differs from the row being located.
-
- If no key is specified or table does not have keys, a table scan is used to
- find the row. In that case the row should be complete and contain values for
- all columns. However, it can still be shorter than the table, i.e. the table
- can contain extra columns not present in the row. It is also possible that
- the table has fewer columns than the row being located.
-
- @returns Error code on failure, 0 on success.
-
- @post In case of success @c m_table->record[0] contains the record found.
- Also, the internal "cursor" of the table is positioned at the record found.
-
- @note If the engine allows random access of the records, a combination of
- @c position() and @c rnd_pos() will be used.
-
- Note that one MUST call ha_index_or_rnd_end() after this function if
- it returns 0 as we must leave the row position in the handler intact
- for any following update/delete command.
-*/
-
-int Rows_log_event::find_row(rpl_group_info *rgi)
-{
- DBUG_ENTER("Rows_log_event::find_row");
-
- DBUG_ASSERT(m_table && m_table->in_use != NULL);
-
- TABLE *table= m_table;
- int error= 0;
- bool is_table_scan= false, is_index_scan= false;
-
- /*
- rpl_row_tabledefs.test specifies that
- if the extra field on the slave does not have a default value
- and this is okay with Delete or Update events.
- Todo: fix wl3228 hld that requires defauls for all types of events
- */
-
- prepare_record(table, m_width, FALSE);
- error= unpack_current_row(rgi);
-
- m_vers_from_plain= false;
- if (table->versioned())
- {
- Field *row_end= table->vers_end_field();
- DBUG_ASSERT(table->read_set);
- bitmap_set_bit(table->read_set, row_end->field_index);
- // check whether master table is unversioned
- if (row_end->val_int() == 0)
- {
- bitmap_set_bit(table->write_set, row_end->field_index);
- // Plain source table may have a PRIMARY KEY. And row_end is always
- // a part of PRIMARY KEY. Set it to max value for engine to find it in
- // index. Needed for an UPDATE/DELETE cases.
- table->vers_end_field()->set_max();
- m_vers_from_plain= true;
- }
- }
-
- DBUG_PRINT("info",("looking for the following record"));
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-
- if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
- table->s->primary_key < MAX_KEY)
- {
- /*
- Use a more efficient method to fetch the record given by
- table->record[0] if the engine allows it. We first compute a
- row reference using the position() member function (it will be
- stored in table->file->ref) and the use rnd_pos() to position
- the "cursor" (i.e., record[0] in this case) at the correct row.
-
- TODO: Add a check that the correct record has been fetched by
- comparing with the original record. Take into account that the
- record on the master and slave can be of different
- length. Something along these lines should work:
-
- ADD>>> store_record(table,record[1]);
- int error= table->file->ha_rnd_pos(table->record[0],
- table->file->ref);
- ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0],
- table->s->reclength) == 0);
-
- */
- int error;
- DBUG_PRINT("info",("locating record using primary key (position)"));
-
- error= table->file->ha_rnd_pos_by_record(table->record[0]);
- if (unlikely(error))
- {
- DBUG_PRINT("info",("rnd_pos returns error %d",error));
- if (error == HA_ERR_KEY_NOT_FOUND)
- error= row_not_found_error(rgi);
- table->file->print_error(error, MYF(0));
- }
- DBUG_RETURN(error);
- }
-
- // We can't use position() - try other methods.
-
- /*
- We need to retrieve all fields
- TODO: Move this out from this function to main loop
- */
- table->use_all_columns();
-
- /*
- Save copy of the record in table->record[1]. It might be needed
- later if linear search is used to find exact match.
- */
- store_record(table,record[1]);
-
- if (m_key_info)
- {
- DBUG_PRINT("info",("locating record using key #%u [%s] (index_read)",
- m_key_nr, m_key_info->name.str));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_wrong_index",
- if(0 != strcmp(m_key_info->name.str,"expected_key")) abort(););
-
- /* The key is active: search the table using the index */
- if (!table->file->inited &&
- (error= table->file->ha_index_init(m_key_nr, FALSE)))
- {
- DBUG_PRINT("info",("ha_index_init returns error %d",error));
- table->file->print_error(error, MYF(0));
- goto end;
- }
-
- /* Fill key data for the row */
-
- DBUG_ASSERT(m_key);
- key_copy(m_key, table->record[0], m_key_info, 0);
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_DUMP("key data", m_key, m_key_info->key_length);
-#endif
-
- /*
- We need to set the null bytes to ensure that the filler bit are
- all set when returning. There are storage engines that just set
- the necessary bits on the bytes and don't set the filler bits
- correctly.
- */
- if (table->s->null_bytes > 0)
- table->record[0][table->s->null_bytes - 1]|=
- 256U - (1U << table->s->last_null_bit_pos);
-
- if (unlikely((error= table->file->ha_index_read_map(table->record[0],
- m_key,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))))
- {
- DBUG_PRINT("info",("no record matching the key found in the table"));
- if (error == HA_ERR_KEY_NOT_FOUND)
- error= row_not_found_error(rgi);
- table->file->print_error(error, MYF(0));
- table->file->ha_index_end();
- goto end;
- }
-
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
-#ifndef HAVE_valgrind
- DBUG_PRINT("info",("found first matching record"));
- DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
-#endif
- /*
- Below is a minor "optimization". If the key (i.e., key number
- 0) has the HA_NOSAME flag set, we know that we have found the
- correct record (since there can be no duplicates); otherwise, we
- have to compare the record with the one found to see if it is
- the correct one.
-
- CAVEAT! This behaviour is essential for the replication of,
- e.g., the mysql.proc table since the correct record *shall* be
- found using the primary key *only*. There shall be no
- comparison of non-PK columns to decide if the correct record is
- found. I can see no scenario where it would be incorrect to
- chose the row to change only using a PK or an UNNI.
- */
- if (table->key_info->flags & HA_NOSAME)
- {
- /* Unique does not have non nullable part */
- if (!(table->key_info->flags & (HA_NULL_PART_KEY)))
- {
- error= 0;
- goto end;
- }
- else
- {
- KEY *keyinfo= table->key_info;
- /*
- Unique has nullable part. We need to check if there is any
- field in the BI image that is null and part of UNNI.
- */
- bool null_found= FALSE;
- for (uint i=0; i < keyinfo->user_defined_key_parts && !null_found; i++)
- {
- uint fieldnr= keyinfo->key_part[i].fieldnr - 1;
- Field **f= table->field+fieldnr;
- null_found= (*f)->is_null();
- }
-
- if (!null_found)
- {
- error= 0;
- goto end;
- }
-
- /* else fall through to index scan */
- }
- }
-
- is_index_scan=true;
-
- /*
- In case key is not unique, we still have to iterate over records found
- and find the one which is identical to the row given. A copy of the
- record we are looking for is stored in record[1].
- */
- DBUG_PRINT("info",("non-unique index, scanning it to find matching record"));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort(););
-
- while (record_compare(table))
- {
- while ((error= table->file->ha_index_next(table->record[0])))
- {
- DBUG_PRINT("info",("no record matching the given row found"));
- table->file->print_error(error, MYF(0));
- table->file->ha_index_end();
- goto end;
- }
- }
- }
- else
- {
- DBUG_PRINT("info",("locating record using table scan (rnd_next)"));
- /* We use this to test that the correct key is used in test cases. */
- DBUG_EXECUTE_IF("slave_crash_if_table_scan", abort(););
-
- /* We don't have a key: search the table using rnd_next() */
- if (unlikely((error= table->file->ha_rnd_init_with_error(1))))
- {
- DBUG_PRINT("info",("error initializing table scan"
- " (ha_rnd_init returns %d)",error));
- goto end;
- }
-
- is_table_scan= true;
-
- /* Continue until we find the right record or have made a full loop */
- do
- {
- error= table->file->ha_rnd_next(table->record[0]);
-
- if (unlikely(error))
- DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
- switch (error) {
-
- case 0:
- DBUG_DUMP("record found", table->record[0], table->s->reclength);
- break;
-
- case HA_ERR_END_OF_FILE:
- DBUG_PRINT("info", ("Record not found"));
- table->file->ha_rnd_end();
- goto end;
-
- default:
- DBUG_PRINT("info", ("Failed to get next record"
- " (rnd_next returns %d)",error));
- table->file->print_error(error, MYF(0));
- table->file->ha_rnd_end();
- goto end;
- }
- }
- while (record_compare(table));
-
- /*
- Note: above record_compare will take into accout all record fields
- which might be incorrect in case a partial row was given in the event
- */
-
- DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
- }
-
-end:
- if (is_table_scan || is_index_scan)
- issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(),
- is_index_scan, rgi);
- table->default_column_bitmaps();
- DBUG_RETURN(error);
-}
-
-#endif
-
-/*
- Constructor used to build an event for writing to the binary log.
- */
-
-#ifndef MYSQL_CLIENT
-Delete_rows_log_event::Delete_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid, bool is_transactional)
- : Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
- DELETE_ROWS_EVENT_V1)
-{
-}
-
-Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
- THD *thd_arg, TABLE *tbl_arg,
- ulong tid_arg,
- bool is_transactional)
- : Delete_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
-{
- m_type= DELETE_ROWS_COMPRESSED_EVENT_V1;
-}
-
-bool Delete_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-#endif /* #if !defined(MYSQL_CLIENT) */
-
/*
Constructor used by slave to read the event from the binary log.
*/
@@ -14331,199 +3583,10 @@ Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
}
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-int
-Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- /*
- Increment the global status delete count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]);
-
- if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
- m_table->s->primary_key < MAX_KEY)
- {
- /*
- We don't need to allocate any memory for m_key since it is not used.
- */
- return 0;
- }
- if (slave_run_triggers_for_rbr && !master_had_triggers)
- m_table->prepare_triggers_for_delete_stmt_or_event();
-
- return find_key();
-}
-
-int
-Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
-{
- m_table->file->ha_index_or_rnd_end();
- my_free(m_key);
- m_key= NULL;
- m_key_info= NULL;
-
- return error;
-}
-
-int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
-{
- int error;
- const char *tmp= thd->get_proc_info();
- const char *message= "Delete_rows_log_event::find_row()";
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
- DBUG_ASSERT(m_table != NULL);
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Delete_rows_log_event::find_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- if (likely(!(error= find_row(rgi))))
- {
- /*
- Delete the record found, located in record[0]
- */
- message= "Delete_rows_log_event::ha_delete_row()";
-#ifdef WSREP_PROC_INFO
- snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Delete_rows_log_event::ha_delete_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif
- thd_proc_info(thd, message);
-
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- if (likely(!error))
- {
- m_table->mark_columns_per_binlog_row_image();
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- {
- Field *end= m_table->vers_end_field();
- bitmap_set_bit(m_table->write_set, end->field_index);
- store_record(m_table, record[1]);
- end->set_time();
- error= m_table->file->ha_update_row(m_table->record[1],
- m_table->record[0]);
- }
- else
- {
- error= m_table->file->ha_delete_row(m_table->record[0]);
- }
- m_table->default_column_bitmaps();
- }
- if (invoke_triggers && likely(!error) &&
- unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
- m_table->file->ha_index_or_rnd_end();
- }
- thd_proc_info(thd, tmp);
- return error;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifdef MYSQL_CLIENT
-bool Delete_rows_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
-}
-
-bool Delete_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- char *new_buf;
- ulong len;
- bool is_malloc = false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Delete_compressed_rows"))
- goto err;
- }
- else
- {
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress delete_compressed_rows failed\n"))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Delete_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_DELETE);
-}
-#endif
-
/**************************************************************************
Update_rows_log_event member functions
**************************************************************************/
-/*
- Constructor used to build an event for writing to the binary log.
- */
-#if !defined(MYSQL_CLIENT)
-Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid,
- bool is_transactional)
-: Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
- UPDATE_ROWS_EVENT_V1)
-{
- init(tbl_arg->rpl_write_set);
-}
-
-Update_rows_compressed_log_event::Update_rows_compressed_log_event(THD *thd_arg, TABLE *tbl_arg,
- ulong tid,
- bool is_transactional)
-: Update_rows_log_event(thd_arg, tbl_arg, tid, is_transactional)
-{
- m_type = UPDATE_ROWS_COMPRESSED_EVENT_V1;
-}
-
-bool Update_rows_compressed_log_event::write()
-{
- return Rows_log_event::write_compressed();
-}
-
-void Update_rows_log_event::init(MY_BITMAP const *cols)
-{
- /* if my_bitmap_init fails, caught in is_valid() */
- if (likely(!my_bitmap_init(&m_cols_ai,
- m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
- m_width,
- false)))
- {
- /* Cols can be zero if this is a dummy binrows event */
- if (likely(cols != NULL))
- {
- memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
- create_last_word_mask(&m_cols_ai);
- }
- }
-}
-#endif /* !defined(MYSQL_CLIENT) */
-
-
Update_rows_log_event::~Update_rows_log_event()
{
if (m_cols_ai.bitmap == m_bitbuf_ai) // no my_malloc happened
@@ -14554,202 +3617,6 @@ Update_rows_compressed_log_event::Update_rows_compressed_log_event(
}
#endif
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-
-int
-Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
-{
- /*
- Increment the global status update count variable
- */
- if (get_flags(STMT_END_F))
- status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]);
-
- int err;
- if ((err= find_key()))
- return err;
-
- if (slave_run_triggers_for_rbr && !master_had_triggers)
- m_table->prepare_triggers_for_update_stmt_or_event();
-
- return 0;
-}
-
-int
-Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
- int error)
-{
- /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
- m_table->file->ha_index_or_rnd_end();
- my_free(m_key); // Free for multi_malloc
- m_key= NULL;
- m_key_info= NULL;
-
- return error;
-}
-
-int
-Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
-{
- const bool invoke_triggers=
- slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
- const char *tmp= thd->get_proc_info();
- const char *message= "Update_rows_log_event::find_row()";
- DBUG_ASSERT(m_table != NULL);
-
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::find_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- int error= find_row(rgi);
- if (unlikely(error))
- {
- /*
- We need to read the second image in the event of error to be
- able to skip to the next pair of updates
- */
- if ((m_curr_row= m_curr_row_end))
- unpack_current_row(rgi, &m_cols_ai);
- thd_proc_info(thd, tmp);
- return error;
- }
-
- /*
- This is the situation after locating BI:
-
- ===|=== before image ====|=== after image ===|===
- ^ ^
- m_curr_row m_curr_row_end
-
- BI found in the table is stored in record[0]. We copy it to record[1]
- and unpack AI to record[0].
- */
-
- store_record(m_table,record[1]);
-
- m_curr_row= m_curr_row_end;
- message= "Update_rows_log_event::unpack_current_row()";
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::unpack_current_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- /* this also updates m_curr_row_end */
- thd_proc_info(thd, message);
- if (unlikely((error= unpack_current_row(rgi, &m_cols_ai))))
- goto err;
-
- /*
- Now we have the right row to update. The old row (the one we're
- looking for) is in record[1] and the new row is in record[0].
- */
-#ifndef HAVE_valgrind
- /*
- Don't print debug messages when running valgrind since they can
- trigger false warnings.
- */
- DBUG_PRINT("info",("Updating row in table"));
- DBUG_DUMP("old record", m_table->record[1], m_table->s->reclength);
- DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
-#endif
-
- message= "Update_rows_log_event::ha_update_row()";
-#ifdef WSREP_PROC_INFO
- my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
- "Update_rows_log_event::ha_update_row(%lld)",
- (long long) wsrep_thd_trx_seqno(thd));
- message= thd->wsrep_info;
-#endif /* WSREP_PROC_INFO */
-
- thd_proc_info(thd, message);
- if (invoke_triggers &&
- unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)))
- {
- error= HA_ERR_GENERIC; // in case if error is not set yet
- goto err;
- }
-
- // Temporary fix to find out why it fails [/Matz]
- memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8);
- memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8);
-
- m_table->mark_columns_per_binlog_row_image();
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- m_table->vers_update_fields();
- error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
- if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
- error= 0;
- if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
- {
- store_record(m_table, record[2]);
- error= vers_insert_history_row(m_table);
- restore_record(m_table, record[2]);
- }
- m_table->default_column_bitmaps();
-
- if (invoke_triggers && likely(!error) &&
- unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)))
- error= HA_ERR_GENERIC; // in case if error is not set yet
-
- thd_proc_info(thd, tmp);
-
-err:
- m_table->file->ha_index_or_rnd_end();
- return error;
-}
-
-#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
-
-#ifdef MYSQL_CLIENT
-bool Update_rows_log_event::print(FILE *file,
- PRINT_EVENT_INFO* print_event_info)
-{
- return Rows_log_event::print_helper(file, print_event_info, "Update_rows");
-}
-
-bool
-Update_rows_compressed_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- char *new_buf;
- ulong len;
- bool is_malloc= false;
- if(!row_log_event_uncompress(glob_description_event,
- checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
- temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
- {
- free_temp_buf();
- register_temp_buf(new_buf, true);
- if (Rows_log_event::print_helper(file, print_event_info,
- "Update_compressed_rows"))
- goto err;
- }
- else
- {
- if (my_b_printf(&print_event_info->head_cache,
- "ERROR: uncompress update_compressed_rows failed\n"))
- goto err;
- }
-
- return 0;
-err:
- return 1;
-}
-#endif
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-uint8 Update_rows_log_event::get_trg_event_map()
-{
- return trg2bit(TRG_EVENT_UPDATE);
-}
-#endif
-
Incident_log_event::Incident_log_event(const char *buf, uint event_len,
const Format_description_log_event *descr_event)
: Log_event(buf, descr_event)
@@ -14819,123 +3686,6 @@ Incident_log_event::description() const
}
-#ifndef MYSQL_CLIENT
-void Incident_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- size_t bytes;
- if (m_message.length > 0)
- bytes= my_snprintf(buf, sizeof(buf), "#%d (%s)",
- m_incident, description());
- else
- bytes= my_snprintf(buf, sizeof(buf), "#%d (%s): %s",
- m_incident, description(), m_message.str);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif /* MYSQL_CLIENT */
-
-
-#if defined(WITH_WSREP) && !defined(MYSQL_CLIENT)
-/*
- read the first event from (*buf). The size of the (*buf) is (*buf_len).
- At the end (*buf) is shitfed to point to the following event or NULL and
- (*buf_len) will be changed to account just being read bytes of the 1st event.
-*/
-#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
-
-Log_event* wsrep_read_log_event(
- char **arg_buf, size_t *arg_buf_len,
- const Format_description_log_event *description_event)
-{
- char *head= (*arg_buf);
- uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
- char *buf= (*arg_buf);
- const char *error= 0;
- Log_event *res= 0;
- DBUG_ENTER("wsrep_read_log_event");
-
- if (data_len > WSREP_MAX_ALLOWED_PACKET)
- {
- error = "Event too big";
- goto err;
- }
-
- res= Log_event::read_log_event(buf, data_len, &error, description_event, false);
-
-err:
- if (!res)
- {
- DBUG_ASSERT(error != 0);
- sql_print_error("Error in Log_event::read_log_event(): "
- "'%s', data_len: %d, event_type: %d",
- error,data_len,(uchar)head[EVENT_TYPE_OFFSET]);
- }
- (*arg_buf)+= data_len;
- (*arg_buf_len)-= data_len;
- DBUG_RETURN(res);
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-bool Incident_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- Write_on_release_cache cache(&print_event_info->head_cache, file);
-
- if (print_header(&cache, print_event_info, FALSE) ||
- my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description()))
- return 1;
- return cache.flush_data();
-}
-#endif
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-int
-Incident_log_event::do_apply_event(rpl_group_info *rgi)
-{
- Relay_log_info const *rli= rgi->rli;
- DBUG_ENTER("Incident_log_event::do_apply_event");
-
- if (ignored_error_code(ER_SLAVE_INCIDENT))
- {
- DBUG_PRINT("info", ("Ignoring Incident"));
- DBUG_RETURN(0);
- }
-
- rli->report(ERROR_LEVEL, ER_SLAVE_INCIDENT, NULL,
- ER_THD(rgi->thd, ER_SLAVE_INCIDENT),
- description(),
- m_message.length > 0 ? m_message.str : "<none>");
- DBUG_RETURN(1);
-}
-#endif
-
-#ifdef MYSQL_SERVER
-bool
-Incident_log_event::write_data_header()
-{
- DBUG_ENTER("Incident_log_event::write_data_header");
- DBUG_PRINT("enter", ("m_incident: %d", m_incident));
- uchar buf[sizeof(int16)];
- int2store(buf, (int16) m_incident);
- DBUG_RETURN(write_data(buf, sizeof(buf)));
-}
-
-bool
-Incident_log_event::write_data_body()
-{
- uchar tmp[1];
- DBUG_ENTER("Incident_log_event::write_data_body");
- tmp[0]= (uchar) m_message.length;
- DBUG_RETURN(write_data(tmp, sizeof(tmp)) ||
- write_data(m_message.str, m_message.length));
-}
-#endif
-
Ignorable_log_event::Ignorable_log_event(const char *buf,
const Format_description_log_event
*descr_event,
@@ -14951,154 +3701,8 @@ Ignorable_log_event::~Ignorable_log_event()
{
}
-#ifndef MYSQL_CLIENT
-/* Pack info for its unrecognized ignorable event */
-void Ignorable_log_event::pack_info(Protocol *protocol)
-{
- char buf[256];
- size_t bytes;
- bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
- number, description);
- protocol->store(buf, bytes, &my_charset_bin);
-}
-#endif
-
-#ifdef MYSQL_CLIENT
-/* Print for its unrecognized ignorable event */
-bool Ignorable_log_event::print(FILE *file,
- PRINT_EVENT_INFO *print_event_info)
-{
- if (print_event_info->short_form)
- return 0;
-
- if (print_header(&print_event_info->head_cache, print_event_info, FALSE) ||
- my_b_printf(&print_event_info->head_cache, "\tIgnorable\n") ||
- my_b_printf(&print_event_info->head_cache,
- "# Ignorable event type %d (%s)\n", number, description) ||
- copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
- file))
- return 1;
- return 0;
-}
-#endif
-
-
-#ifdef MYSQL_CLIENT
-/**
- The default values for these variables should be values that are
- *incorrect*, i.e., values that cannot occur in an event. This way,
- they will always be printed for the first event.
-*/
-st_print_event_info::st_print_event_info()
-{
- myf const flags = MYF(MY_WME | MY_NABP);
- /*
- Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
- program's startup, but these explicit bzero() is for the day someone
- creates dynamic instances.
- */
- bzero(db, sizeof(db));
- bzero(charset, sizeof(charset));
- bzero(time_zone_str, sizeof(time_zone_str));
- delimiter[0]= ';';
- delimiter[1]= 0;
- flags2_inited= 0;
- sql_mode_inited= 0;
- row_events= 0;
- sql_mode= 0;
- auto_increment_increment= 0;
- auto_increment_offset= 0;
- charset_inited= 0;
- lc_time_names_number= ~0;
- charset_database_number= ILLEGAL_CHARSET_INFO_NUMBER;
- thread_id= 0;
- server_id= 0;
- domain_id= 0;
- thread_id_printed= false;
- server_id_printed= false;
- domain_id_printed= false;
- allow_parallel= true;
- allow_parallel_printed= false;
- found_row_event= false;
- print_row_count= false;
- short_form= false;
- skip_replication= 0;
- printed_fd_event=FALSE;
- file= 0;
- base64_output_mode=BASE64_OUTPUT_UNSPEC;
- open_cached_file(&head_cache, NULL, NULL, 0, flags);
- open_cached_file(&body_cache, NULL, NULL, 0, flags);
-#ifdef WHEN_FLASHBACK_REVIEW_READY
- open_cached_file(&review_sql_cache, NULL, NULL, 0, flags);
-#endif
-}
-
-
-bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
-{
- reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
- if (cache->end_of_file > SIZE_T_MAX ||
- !(to->str= (char*) my_malloc((to->length= (size_t)cache->end_of_file), MYF(0))))
- {
- perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
- goto err;
- }
- if (my_b_read(cache, (uchar*) to->str, to->length))
- {
- my_free(to->str);
- perror("Can't read data from IO_CACHE");
- return true;
- }
- reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
- return false;
-
-err:
- to->str= 0;
- to->length= 0;
- return true;
-}
-#endif /* MYSQL_CLIENT */
-
bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache, FILE *file)
{
return (my_b_copy_all_to_file(cache, file) ||
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE));
}
-
-#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
-Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
- const Format_description_log_event* description_event)
- :Log_event(buf, description_event)
-{
- uint8 header_size= description_event->common_header_len;
- ident_len = event_len - header_size;
- set_if_smaller(ident_len,FN_REFLEN-1);
- log_ident= buf + header_size;
-}
-#endif
-
-#if defined(MYSQL_SERVER)
-/**
- Check if we should write event to the relay log
-
- This is used to skip events that is only supported by MySQL
-
- Return:
- 0 ok
- 1 Don't write event
-*/
-
-bool event_that_should_be_ignored(const char *buf)
-{
- uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
- if (event_type == GTID_LOG_EVENT ||
- event_type == ANONYMOUS_GTID_LOG_EVENT ||
- event_type == PREVIOUS_GTIDS_LOG_EVENT ||
- event_type == TRANSACTION_CONTEXT_EVENT ||
- event_type == VIEW_CHANGE_EVENT ||
- event_type == XA_PREPARE_LOG_EVENT ||
- (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
- return 1;
- return 0;
-}
-#endif /* MYSQL_SERVER */
diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc
new file mode 100644
index 00000000000..57b217813e2
--- /dev/null
+++ b/sql/log_event_client.cc
@@ -0,0 +1,3424 @@
+/*
+ Copyright (c) 2000, 2018, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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
+*/
+
+
+#ifndef MYSQL_CLIENT
+#error MYSQL_CLIENT must be defined here
+#endif
+
+#ifdef MYSQL_SERVER
+#error MYSQL_SERVER must not be defined here
+#endif
+
+
+static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
+{
+ const char* end = str + len;
+ if (my_b_write_byte(cache, '\''))
+ goto err;
+
+ while (str < end)
+ {
+ char c;
+ int error;
+
+ switch ((c=*str++)) {
+ case '\n': error= my_b_write(cache, (uchar*)"\\n", 2); break;
+ case '\r': error= my_b_write(cache, (uchar*)"\\r", 2); break;
+ case '\\': error= my_b_write(cache, (uchar*)"\\\\", 2); break;
+ case '\b': error= my_b_write(cache, (uchar*)"\\b", 2); break;
+ case '\t': error= my_b_write(cache, (uchar*)"\\t", 2); break;
+ case '\'': error= my_b_write(cache, (uchar*)"\\'", 2); break;
+ case 0 : error= my_b_write(cache, (uchar*)"\\0", 2); break;
+ default:
+ error= my_b_write_byte(cache, c);
+ break;
+ }
+ if (unlikely(error))
+ goto err;
+ }
+ return my_b_write_byte(cache, '\'');
+
+err:
+ return 1;
+}
+
+
+/**
+ Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
+ commands just before it prints a query.
+*/
+
+static bool print_set_option(IO_CACHE* file, uint32 bits_changed,
+ uint32 option, uint32 flags, const char* name,
+ bool* need_comma)
+{
+ if (bits_changed & option)
+ {
+ if (*need_comma)
+ if (my_b_write(file, (uchar*)", ", 2))
+ goto err;
+ if (my_b_printf(file, "%s=%d", name, MY_TEST(flags & option)))
+ goto err;
+ *need_comma= 1;
+ }
+ return 0;
+err:
+ return 1;
+}
+
+
+static bool hexdump_minimal_header_to_io_cache(IO_CACHE *file,
+ my_off_t offset,
+ uchar *ptr)
+{
+ DBUG_ASSERT(LOG_EVENT_MINIMAL_HEADER_LEN == 19);
+
+ /*
+ Pretty-print the first LOG_EVENT_MINIMAL_HEADER_LEN (19) bytes of the
+ common header, which contains the basic information about the log event.
+ Every event will have at least this much header, but events could contain
+ more headers (which must be printed by other methods, if desired).
+ */
+ char emit_buf[120]; // Enough for storing one line
+ size_t emit_buf_written;
+
+ if (my_b_printf(file,
+ "# "
+ "|Timestamp "
+ "|Type "
+ "|Master ID "
+ "|Size "
+ "|Master Pos "
+ "|Flags\n"))
+ goto err;
+ emit_buf_written=
+ my_snprintf(emit_buf, sizeof(emit_buf),
+ "# %8llx " /* Position */
+ "|%02x %02x %02x %02x " /* Timestamp */
+ "|%02x " /* Type */
+ "|%02x %02x %02x %02x " /* Master ID */
+ "|%02x %02x %02x %02x " /* Size */
+ "|%02x %02x %02x %02x " /* Master Pos */
+ "|%02x %02x\n", /* Flags */
+ (ulonglong) offset, /* Position */
+ ptr[0], ptr[1], ptr[2], ptr[3], /* Timestamp */
+ ptr[4], /* Type */
+ ptr[5], ptr[6], ptr[7], ptr[8], /* Master ID */
+ ptr[9], ptr[10], ptr[11], ptr[12], /* Size */
+ ptr[13], ptr[14], ptr[15], ptr[16], /* Master Pos */
+ ptr[17], ptr[18]); /* Flags */
+
+ DBUG_ASSERT(static_cast<size_t>(emit_buf_written) < sizeof(emit_buf));
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buf), emit_buf_written) ||
+ my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
+}
+
+
+/*
+ The number of bytes to print per line. Should be an even number,
+ and "hexdump -C" uses 16, so we'll duplicate that here.
+*/
+#define HEXDUMP_BYTES_PER_LINE 16
+
+static void format_hex_line(char *emit_buff)
+{
+ memset(emit_buff + 1, ' ',
+ 1 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE);
+ emit_buff[0]= '#';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 1]= '|';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE]= '|';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 1]= '\n';
+ emit_buff[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 2]= '\0';
+}
+
+static bool hexdump_data_to_io_cache(IO_CACHE *file,
+ my_off_t offset,
+ uchar *ptr,
+ my_off_t size)
+{
+ /*
+ 2 = '# '
+ 8 = address
+ 2 = ' '
+ (HEXDUMP_BYTES_PER_LINE * 3 + 1) = Each byte prints as two hex digits,
+ plus a space
+ 2 = ' |'
+ HEXDUMP_BYTES_PER_LINE = text representation
+ 2 = '|\n'
+ 1 = '\0'
+ */
+ char emit_buffer[2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2 +
+ HEXDUMP_BYTES_PER_LINE + 2 + 1 ];
+ char *h,*c;
+ my_off_t i;
+
+ if (size == 0)
+ return 0; // ok, nothing to do
+
+ format_hex_line(emit_buffer);
+ /*
+ Print the rest of the event (without common header)
+ */
+ my_off_t starting_offset = offset;
+ for (i= 0,
+ c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2,
+ h= emit_buffer + 2 + 8 + 2;
+ i < size;
+ i++, ptr++)
+ {
+ my_snprintf(h, 4, "%02x ", *ptr);
+ h+= 3;
+
+ *c++= my_isprint(&my_charset_bin, *ptr) ? *ptr : '.';
+
+ /* Print in groups of HEXDUMP_BYTES_PER_LINE characters. */
+ if ((i % HEXDUMP_BYTES_PER_LINE) == (HEXDUMP_BYTES_PER_LINE - 1))
+ {
+ /* remove \0 left after printing hex byte representation */
+ *h= ' ';
+ /* prepare space to print address */
+ memset(emit_buffer + 2, ' ', 8);
+ /* print address */
+ size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
+ (ulonglong) starting_offset);
+ /* remove \0 left after printing address */
+ emit_buffer[2 + emit_buf_written]= ' ';
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ sizeof(emit_buffer) - 1))
+ goto err;
+ c= emit_buffer + 2 + 8 + 2 + (HEXDUMP_BYTES_PER_LINE * 3 + 1) + 2;
+ h= emit_buffer + 2 + 8 + 2;
+ format_hex_line(emit_buffer);
+ starting_offset+= HEXDUMP_BYTES_PER_LINE;
+ }
+ else if ((i % (HEXDUMP_BYTES_PER_LINE / 2))
+ == ((HEXDUMP_BYTES_PER_LINE / 2) - 1))
+ {
+ /*
+ In the middle of the group of HEXDUMP_BYTES_PER_LINE, emit an extra
+ space in the hex string, to make two groups.
+ */
+ *h++= ' ';
+ }
+
+ }
+
+ /*
+ There is still data left in our buffer, which means that the previous
+ line was not perfectly HEXDUMP_BYTES_PER_LINE characters, so write an
+ incomplete line, with spaces to pad out to the same length as a full
+ line would be, to make things more readable.
+ */
+ if (h != emit_buffer + 2 + 8 + 2)
+ {
+ *h= ' ';
+ *c++= '|'; *c++= '\n';
+ memset(emit_buffer + 2, ' ', 8);
+ size_t const emit_buf_written= my_snprintf(emit_buffer + 2, 9, "%8llx",
+ (ulonglong) starting_offset);
+ emit_buffer[2 + emit_buf_written]= ' ';
+ /* pad unprinted area */
+ memset(h, ' ',
+ (HEXDUMP_BYTES_PER_LINE * 3 + 1) - (h - (emit_buffer + 2 + 8 + 2)));
+ if (my_b_write(file, reinterpret_cast<uchar*>(emit_buffer),
+ c - emit_buffer))
+ goto err;
+ }
+ if (my_b_write(file, (uchar*)"#\n", 2))
+ goto err;
+
+ return 0;
+err:
+ return 1;
+}
+
+/*
+ Log_event::print_header()
+*/
+
+bool Log_event::print_header(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool is_more __attribute__((unused)))
+{
+ char llbuff[22];
+ my_off_t hexdump_from= print_event_info->hexdump_from;
+ DBUG_ENTER("Log_event::print_header");
+
+ if (my_b_write_byte(file, '#') ||
+ print_timestamp(file) ||
+ my_b_printf(file, " server id %lu end_log_pos %s ", (ulong) server_id,
+ llstr(log_pos,llbuff)))
+ goto err;
+
+ /* print the checksum */
+
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_OFF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
+ {
+ char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "%p "
+ size_t const bytes_written=
+ my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08x ", crc);
+ if (my_b_printf(file, "%s ", get_type(&binlog_checksum_typelib,
+ checksum_alg)) ||
+ my_b_printf(file, checksum_buf, bytes_written))
+ goto err;
+ }
+
+ /* mysqlbinlog --hexdump */
+ if (print_event_info->hexdump_from)
+ {
+ my_b_write_byte(file, '\n');
+ uchar *ptr= (uchar*)temp_buf;
+ my_off_t size= uint4korr(ptr + EVENT_LEN_OFFSET);
+ my_off_t hdr_len= get_header_len(print_event_info->common_header_len);
+
+ size-= hdr_len;
+
+ if (my_b_printf(file, "# Position\n"))
+ goto err;
+
+ /* Write the header, nicely formatted by field. */
+ if (hexdump_minimal_header_to_io_cache(file, hexdump_from, ptr))
+ goto err;
+
+ ptr+= hdr_len;
+ hexdump_from+= hdr_len;
+
+ /* Print the rest of the data, mimicking "hexdump -C" output. */
+ if (hexdump_data_to_io_cache(file, hexdump_from, ptr, size))
+ goto err;
+
+ /*
+ Prefix the next line so that the output from print_helper()
+ will appear as a comment.
+ */
+ if (my_b_write(file, (uchar*)"# Event: ", 9))
+ goto err;
+ }
+
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/**
+ Prints a quoted string to io cache.
+ Control characters are displayed as hex sequence, e.g. \x00
+ Single-quote and backslash characters are escaped with a \
+
+ @param[in] file IO cache
+ @param[in] prt Pointer to string
+ @param[in] length String length
+*/
+
+static void
+my_b_write_quoted(IO_CACHE *file, const uchar *ptr, uint length)
+{
+ const uchar *s;
+ my_b_write_byte(file, '\'');
+ for (s= ptr; length > 0 ; s++, length--)
+ {
+ if (*s > 0x1F)
+ my_b_write_byte(file, *s);
+ else if (*s == '\'')
+ my_b_write(file, (uchar*)"\\'", 2);
+ else if (*s == '\\')
+ my_b_write(file, (uchar*)"\\\\", 2);
+ else
+ {
+ uchar hex[10];
+ size_t len= my_snprintf((char*) hex, sizeof(hex), "%s%02x", "\\x", *s);
+ my_b_write(file, hex, len);
+ }
+ }
+ my_b_write_byte(file, '\'');
+}
+
+
+/**
+ Prints a bit string to io cache in format b'1010'.
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] nbits Number of bits
+*/
+static void
+my_b_write_bit(IO_CACHE *file, const uchar *ptr, uint nbits)
+{
+ uint bitnum, nbits8= ((nbits + 7) / 8) * 8, skip_bits= nbits8 - nbits;
+ my_b_write(file, (uchar*)"b'", 2);
+ for (bitnum= skip_bits ; bitnum < nbits8; bitnum++)
+ {
+ int is_set= (ptr[(bitnum) / 8] >> (7 - bitnum % 8)) & 0x01;
+ my_b_write_byte(file, (is_set ? '1' : '0'));
+ }
+ my_b_write_byte(file, '\'');
+}
+
+
+/**
+ Prints a packed string to io cache.
+ The string consists of length packed to 1 or 2 bytes,
+ followed by string data itself.
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] length String size
+
+ @retval - number of bytes scanned.
+*/
+static size_t
+my_b_write_quoted_with_length(IO_CACHE *file, const uchar *ptr, uint length)
+{
+ if (length < 256)
+ {
+ length= *ptr;
+ my_b_write_quoted(file, ptr + 1, length);
+ return length + 1;
+ }
+ else
+ {
+ length= uint2korr(ptr);
+ my_b_write_quoted(file, ptr + 2, length);
+ return length + 2;
+ }
+}
+
+
+/**
+ Prints a 32-bit number in both signed and unsigned representation
+
+ @param[in] file IO cache
+ @param[in] sl Signed number
+ @param[in] ul Unsigned number
+*/
+static bool
+my_b_write_sint32_and_uint32(IO_CACHE *file, int32 si, uint32 ui)
+{
+ bool res= my_b_printf(file, "%d", si);
+ if (si < 0)
+ if (my_b_printf(file, " (%u)", ui))
+ res= 1;
+ return res;
+}
+
+
+/**
+ Print a packed value of the given SQL type into IO cache
+
+ @param[in] file IO cache
+ @param[in] ptr Pointer to string
+ @param[in] type Column type
+ @param[in] meta Column meta information
+ @param[out] typestr SQL type string buffer (for verbose output)
+ @param[out] typestr_length Size of typestr
+
+ @retval - number of bytes scanned from ptr.
+ Except in case of NULL, in which case we return 1 to indicate ok
+*/
+
+static size_t
+log_event_print_value(IO_CACHE *file, PRINT_EVENT_INFO *print_event_info,
+ const uchar *ptr, uint type, uint meta,
+ char *typestr, size_t typestr_length)
+{
+ uint32 length= 0;
+
+ if (type == MYSQL_TYPE_STRING)
+ {
+ if (meta >= 256)
+ {
+ uint byte0= meta >> 8;
+ uint byte1= meta & 0xFF;
+
+ if ((byte0 & 0x30) != 0x30)
+ {
+ /* a long CHAR() field: see #37426 */
+ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
+ type= byte0 | 0x30;
+ }
+ else
+ length = meta & 0xFF;
+ }
+ else
+ length= meta;
+ }
+
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ {
+ strmake(typestr, "INT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= sint4korr(ptr);
+ uint32 ui= uint4korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 4;
+ }
+
+ case MYSQL_TYPE_TINY:
+ {
+ strmake(typestr, "TINYINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ my_b_write_sint32_and_uint32(file, (int) (signed char) *ptr,
+ (uint) (unsigned char) *ptr);
+ return 1;
+ }
+
+ case MYSQL_TYPE_SHORT:
+ {
+ strmake(typestr, "SHORTINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= (int32) sint2korr(ptr);
+ uint32 ui= (uint32) uint2korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 2;
+ }
+
+ case MYSQL_TYPE_INT24:
+ {
+ strmake(typestr, "MEDIUMINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 si= sint3korr(ptr);
+ uint32 ui= uint3korr(ptr);
+ my_b_write_sint32_and_uint32(file, si, ui);
+ return 3;
+ }
+
+ case MYSQL_TYPE_LONGLONG:
+ {
+ strmake(typestr, "LONGINT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ char tmp[64];
+ size_t length;
+ longlong si= sint8korr(ptr);
+ length= (longlong10_to_str(si, tmp, -10) - tmp);
+ my_b_write(file, (uchar*)tmp, length);
+ if (si < 0)
+ {
+ ulonglong ui= uint8korr(ptr);
+ longlong10_to_str((longlong) ui, tmp, 10);
+ my_b_printf(file, " (%s)", tmp);
+ }
+ return 8;
+ }
+
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint precision= meta >> 8;
+ uint decimals= meta & 0xFF;
+ my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
+ precision, decimals);
+ if (!ptr)
+ goto return_null;
+
+ uint bin_size= my_decimal_get_binary_size(precision, decimals);
+ my_decimal dec((const uchar *) ptr, precision, decimals);
+ int length= DECIMAL_MAX_STR_LENGTH;
+ char buff[DECIMAL_MAX_STR_LENGTH + 1];
+ decimal2string(&dec, buff, &length, 0, 0, 0);
+ my_b_write(file, (uchar*)buff, length);
+ return bin_size;
+ }
+
+ case MYSQL_TYPE_FLOAT:
+ {
+ strmake(typestr, "FLOAT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ float fl;
+ float4get(fl, ptr);
+ char tmp[320];
+ sprintf(tmp, "%-20g", (double) fl);
+ my_b_printf(file, "%s", tmp); /* my_snprintf doesn't support %-20g */
+ return 4;
+ }
+
+ case MYSQL_TYPE_DOUBLE:
+ {
+ double dbl;
+ strmake(typestr, "DOUBLE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ float8get(dbl, ptr);
+ char tmp[320];
+ sprintf(tmp, "%-.20g", dbl); /* strmake doesn't support %-20g */
+ my_b_printf(file, tmp, "%s");
+ return 8;
+ }
+
+ case MYSQL_TYPE_BIT:
+ {
+ /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
+ uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
+ my_snprintf(typestr, typestr_length, "BIT(%d)", nbits);
+ if (!ptr)
+ goto return_null;
+
+ length= (nbits + 7) / 8;
+ my_b_write_bit(file, ptr, nbits);
+ return length;
+ }
+
+ case MYSQL_TYPE_TIMESTAMP:
+ {
+ strmake(typestr, "TIMESTAMP", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 i32= uint4korr(ptr);
+ my_b_printf(file, "%d", i32);
+ return 4;
+ }
+
+ case MYSQL_TYPE_TIMESTAMP2:
+ {
+ my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ struct timeval tm;
+ my_timestamp_from_binary(&tm, ptr, meta);
+ int buflen= my_timeval_to_str(&tm, buf, meta);
+ my_b_write(file, (uchar*)buf, buflen);
+ return my_timestamp_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_DATETIME:
+ {
+ strmake(typestr, "DATETIME", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ ulong d, t;
+ uint64 i64= uint8korr(ptr); /* YYYYMMDDhhmmss */
+ d= (ulong) (i64 / 1000000);
+ t= (ulong) (i64 % 1000000);
+
+ my_b_printf(file, "'%04d-%02d-%02d %02d:%02d:%02d'",
+ (int) (d / 10000), (int) (d % 10000) / 100, (int) (d % 100),
+ (int) (t / 10000), (int) (t % 10000) / 100, (int) t % 100);
+ return 8;
+ }
+
+ case MYSQL_TYPE_DATETIME2:
+ {
+ my_snprintf(typestr, typestr_length, "DATETIME(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_datetime_packed_from_binary(ptr, meta);
+ TIME_from_longlong_datetime_packed(&ltime, packed);
+ int buflen= my_datetime_to_str(&ltime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ return my_datetime_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_TIME:
+ {
+ strmake(typestr, "TIME", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 tmp= sint3korr(ptr);
+ int32 i32= tmp >= 0 ? tmp : - tmp;
+ const char *sign= tmp < 0 ? "-" : "";
+ my_b_printf(file, "'%s%02d:%02d:%02d'",
+ sign, i32 / 10000, (i32 % 10000) / 100, i32 % 100, i32);
+ return 3;
+ }
+
+ case MYSQL_TYPE_TIME2:
+ {
+ my_snprintf(typestr, typestr_length, "TIME(%d)", meta);
+ if (!ptr)
+ goto return_null;
+
+ char buf[MAX_DATE_STRING_REP_LENGTH];
+ MYSQL_TIME ltime;
+ longlong packed= my_time_packed_from_binary(ptr, meta);
+ TIME_from_longlong_time_packed(&ltime, packed);
+ int buflen= my_time_to_str(&ltime, buf, meta);
+ my_b_write_quoted(file, (uchar *) buf, buflen);
+ return my_time_binary_length(meta);
+ }
+
+ case MYSQL_TYPE_NEWDATE:
+ {
+ strmake(typestr, "DATE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 tmp= uint3korr(ptr);
+ int part;
+ char buf[11];
+ char *pos= &buf[10]; // start from '\0' to the beginning
+
+ /* Copied from field.cc */
+ *pos--=0; // End NULL
+ part=(int) (tmp & 31);
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= ':';
+ part=(int) (tmp >> 5 & 15);
+ *pos--= (char) ('0'+part%10);
+ *pos--= (char) ('0'+part/10);
+ *pos--= ':';
+ part=(int) (tmp >> 9);
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos--= (char) ('0'+part%10); part/=10;
+ *pos= (char) ('0'+part);
+ my_b_printf(file , "'%s'", buf);
+ return 3;
+ }
+
+ case MYSQL_TYPE_DATE:
+ {
+ strmake(typestr, "DATE", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint i32= uint3korr(ptr);
+ my_b_printf(file , "'%04d:%02d:%02d'",
+ (int)(i32 / (16L * 32L)), (int)(i32 / 32L % 16L),
+ (int)(i32 % 32L));
+ return 3;
+ }
+
+ case MYSQL_TYPE_YEAR:
+ {
+ strmake(typestr, "YEAR", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ uint32 i32= *ptr;
+ my_b_printf(file, "%04d", i32+ 1900);
+ return 1;
+ }
+
+ case MYSQL_TYPE_ENUM:
+ switch (meta & 0xFF) {
+ case 1:
+ strmake(typestr, "ENUM(1 byte)", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ my_b_printf(file, "%d", (int) *ptr);
+ return 1;
+ case 2:
+ {
+ strmake(typestr, "ENUM(2 bytes)", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ int32 i32= uint2korr(ptr);
+ my_b_printf(file, "%d", i32);
+ return 2;
+ }
+ default:
+ my_b_printf(file, "!! Unknown ENUM packlen=%d", meta & 0xFF);
+ return 0;
+ }
+ break;
+
+ case MYSQL_TYPE_SET:
+ my_snprintf(typestr, typestr_length, "SET(%d bytes)", meta & 0xFF);
+ if (!ptr)
+ goto return_null;
+
+ my_b_write_bit(file, ptr , (meta & 0xFF) * 8);
+ return meta & 0xFF;
+
+ case MYSQL_TYPE_BLOB:
+ switch (meta) {
+ case 1:
+ strmake(typestr, "TINYBLOB/TINYTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= *ptr;
+ my_b_write_quoted(file, ptr + 1, length);
+ return length + 1;
+ case 2:
+ strmake(typestr, "BLOB/TEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint2korr(ptr);
+ my_b_write_quoted(file, ptr + 2, length);
+ return length + 2;
+ case 3:
+ strmake(typestr, "MEDIUMBLOB/MEDIUMTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint3korr(ptr);
+ my_b_write_quoted(file, ptr + 3, length);
+ return length + 3;
+ case 4:
+ strmake(typestr, "LONGBLOB/LONGTEXT", typestr_length);
+ if (!ptr)
+ goto return_null;
+
+ length= uint4korr(ptr);
+ my_b_write_quoted(file, ptr + 4, length);
+ return length + 4;
+ default:
+ my_b_printf(file, "!! Unknown BLOB packlen=%d", length);
+ return 0;
+ }
+
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ length= meta;
+ my_snprintf(typestr, typestr_length, "VARSTRING(%d)", length);
+ if (!ptr)
+ goto return_null;
+
+ return my_b_write_quoted_with_length(file, ptr, length);
+
+ case MYSQL_TYPE_STRING:
+ my_snprintf(typestr, typestr_length, "STRING(%d)", length);
+ if (!ptr)
+ goto return_null;
+
+ return my_b_write_quoted_with_length(file, ptr, length);
+
+ case MYSQL_TYPE_DECIMAL:
+ print_event_info->flush_for_error();
+ fprintf(stderr, "\nError: Found Old DECIMAL (mysql-4.1 or earlier). "
+ "Not enough metadata to display the value.\n");
+ break;
+ default:
+ print_event_info->flush_for_error();
+ fprintf(stderr,
+ "\nError: Don't know how to handle column type: %d meta: %d (%04x)\n",
+ type, meta, meta);
+ break;
+ }
+ *typestr= 0;
+ return 0;
+
+return_null:
+ return my_b_write(file, (uchar*) "NULL", 4) ? 0 : 1;
+}
+
+
+/**
+ Print a packed row into IO cache
+
+ @param[in] file IO cache
+ @param[in] td Table definition
+ @param[in] print_event_into Print parameters
+ @param[in] cols_bitmap Column bitmaps.
+ @param[in] value Pointer to packed row
+ @param[in] prefix Row's SQL clause ("SET", "WHERE", etc)
+
+ @retval 0 error
+ # number of bytes scanned.
+*/
+
+
+size_t
+Rows_log_event::print_verbose_one_row(IO_CACHE *file, table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value, const uchar *prefix,
+ const my_bool no_fill_output)
+{
+ const uchar *value0= value;
+ const uchar *null_bits= value;
+ uint null_bit_index= 0;
+ char typestr[64]= "";
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ /* Storing the review SQL */
+ IO_CACHE *review_sql= &print_event_info->review_sql_cache;
+ LEX_STRING review_str;
+#endif
+
+ /*
+ Skip metadata bytes which gives the information about nullabity of master
+ columns. Master writes one bit for each affected column.
+ */
+
+ value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
+
+ if (!no_fill_output)
+ if (my_b_printf(file, "%s", prefix))
+ goto err;
+
+ for (uint i= 0; i < (uint)td->size(); i ++)
+ {
+ size_t size;
+ int is_null= (null_bits[null_bit_index / 8]
+ >> (null_bit_index % 8)) & 0x01;
+
+ if (bitmap_is_set(cols_bitmap, i) == 0)
+ continue;
+
+ if (!no_fill_output)
+ if (my_b_printf(file, "### @%d=", static_cast<int>(i + 1)))
+ goto err;
+
+ if (!is_null)
+ {
+ size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
+ if (value + fsize > m_rows_end)
+ {
+ if (!no_fill_output)
+ if (my_b_printf(file, "***Corrupted replication event was detected."
+ " Not printing the value***\n"))
+ goto err;
+ value+= fsize;
+ return 0;
+ }
+ }
+
+ if (!no_fill_output)
+ {
+ size= log_event_print_value(file, print_event_info, is_null? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ {
+ String tmp_str, hex_str;
+ IO_CACHE tmp_cache;
+
+ // Using a tmp IO_CACHE to get the value output
+ open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+ error= copy_event_cache_to_string_and_reinit(&tmp_cache, &review_str);
+ close_cached_file(&tmp_cache);
+ if (unlikely(error))
+ return 0;
+
+ switch (td->type(i)) // Converting a string to HEX format
+ {
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_BLOB:
+ // Avoid write_pos changed to a new area
+ // tmp_str.free();
+ tmp_str.append(review_str.str + 1, review_str.length - 2); // Removing quotation marks
+ if (hex_str.alloc(tmp_str.length()*2+1)) // If out of memory
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not print correct binlog event.\n");
+ exit(1);
+ }
+ octet2hex((char*) hex_str.ptr(), tmp_str.ptr(), tmp_str.length());
+ if (my_b_printf(review_sql, ", UNHEX('%s')", hex_str.ptr()))
+ goto err;
+ break;
+ default:
+ tmp_str.free();
+ if (tmp_str.append(review_str.str, review_str.length) ||
+ my_b_printf(review_sql, ", %s", tmp_str.ptr()))
+ goto err;
+ break;
+ }
+ my_free(revieww_str.str);
+ }
+#endif
+ }
+ else
+ {
+ IO_CACHE tmp_cache;
+ open_cached_file(&tmp_cache, NULL, NULL, 0, MYF(MY_WME | MY_NABP));
+ size= log_event_print_value(&tmp_cache, print_event_info,
+ is_null ? NULL: value,
+ td->type(i), td->field_metadata(i),
+ typestr, sizeof(typestr));
+ close_cached_file(&tmp_cache);
+ }
+
+ if (!size)
+ goto err;
+
+ if (!is_null)
+ value+= size;
+
+ if (print_event_info->verbose > 1 && !no_fill_output)
+ {
+ if (my_b_write(file, (uchar*)" /* ", 4) ||
+ my_b_printf(file, "%s ", typestr) ||
+ my_b_printf(file, "meta=%d nullable=%d is_null=%d ",
+ td->field_metadata(i),
+ td->maybe_null(i), is_null) ||
+ my_b_write(file, (uchar*)"*/", 2))
+ goto err;
+ }
+
+ if (!no_fill_output)
+ if (my_b_write_byte(file, '\n'))
+ goto err;
+
+ null_bit_index++;
+ }
+ return value - value0;
+
+err:
+ return 0;
+}
+
+
+/**
+ Exchange the SET part and WHERE part for the Update events.
+ Revert the operations order for the Write and Delete events.
+ And then revert the events order from the last one to the first one.
+
+ @param[in] print_event_info PRINT_EVENT_INFO
+ @param[in] rows_buff Packed event buff
+*/
+
+void Rows_log_event::change_to_flashback_event(PRINT_EVENT_INFO *print_event_info,
+ uchar *rows_buff, Log_event_type ev_type)
+{
+ Table_map_log_event *map;
+ table_def *td;
+ DYNAMIC_ARRAY rows_arr;
+ uchar *swap_buff1, *swap_buff2;
+ uchar *rows_pos= rows_buff + m_rows_before_size;
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ return;
+
+ /* If the write rows event contained no values for the AI */
+ if (((get_general_type_code() == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
+ goto end;
+
+ (void) my_init_dynamic_array(&rows_arr, sizeof(LEX_STRING), 8, 8, MYF(0));
+
+ for (uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ uchar *start_pos= value;
+ size_t length1= 0;
+ if (!(length1= print_verbose_one_row(NULL, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) "", TRUE)))
+ {
+ fprintf(stderr, "\nError row length: %zu\n", length1);
+ exit(1);
+ }
+ value+= length1;
+
+ swap_buff1= (uchar *) my_malloc(length1, MYF(0));
+ if (!swap_buff1)
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not exchange to flashback event.\n");
+ exit(1);
+ }
+ memcpy(swap_buff1, start_pos, length1);
+
+ // For Update_event, we have the second part
+ size_t length2= 0;
+ if (ev_type == UPDATE_ROWS_EVENT ||
+ ev_type == UPDATE_ROWS_EVENT_V1)
+ {
+ if (!(length2= print_verbose_one_row(NULL, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) "", TRUE)))
+ {
+ fprintf(stderr, "\nError row length: %zu\n", length2);
+ exit(1);
+ }
+ value+= length2;
+
+ swap_buff2= (uchar *) my_malloc(length2, MYF(0));
+ if (!swap_buff2)
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not exchange to flashback event.\n");
+ exit(1);
+ }
+ memcpy(swap_buff2, start_pos + length1, length2); // WHERE part
+ }
+
+ if (ev_type == UPDATE_ROWS_EVENT ||
+ ev_type == UPDATE_ROWS_EVENT_V1)
+ {
+ /* Swap SET and WHERE part */
+ memcpy(start_pos, swap_buff2, length2);
+ memcpy(start_pos + length2, swap_buff1, length1);
+ }
+
+ /* Free tmp buffers */
+ my_free(swap_buff1);
+ if (ev_type == UPDATE_ROWS_EVENT ||
+ ev_type == UPDATE_ROWS_EVENT_V1)
+ my_free(swap_buff2);
+
+ /* Copying one row into a buff, and pushing into the array */
+ LEX_STRING one_row;
+
+ one_row.length= length1 + length2;
+ one_row.str= (char *) my_malloc(one_row.length, MYF(0));
+ memcpy(one_row.str, start_pos, one_row.length);
+ if (one_row.str == NULL || push_dynamic(&rows_arr, (uchar *) &one_row))
+ {
+ fprintf(stderr, "\nError: Out of memory. "
+ "Could not push flashback event into array.\n");
+ exit(1);
+ }
+ }
+
+ /* Copying rows from the end to the begining into event */
+ for (uint i= rows_arr.elements; i > 0; --i)
+ {
+ LEX_STRING *one_row= dynamic_element(&rows_arr, i - 1, LEX_STRING*);
+
+ memcpy(rows_pos, (uchar *)one_row->str, one_row->length);
+ rows_pos+= one_row->length;
+ my_free(one_row->str);
+ }
+ delete_dynamic(&rows_arr);
+
+end:
+ delete td;
+}
+
+/**
+ Calc length of a packed value of the given SQL type
+
+ @param[in] ptr Pointer to string
+ @param[in] type Column type
+ @param[in] meta Column meta information
+
+ @retval - number of bytes scanned from ptr.
+ Except in case of NULL, in which case we return 1 to indicate ok
+*/
+
+static size_t calc_field_event_length(const uchar *ptr, uint type, uint meta)
+{
+ uint32 length= 0;
+
+ if (type == MYSQL_TYPE_STRING)
+ {
+ if (meta >= 256)
+ {
+ uint byte0= meta >> 8;
+ uint byte1= meta & 0xFF;
+
+ if ((byte0 & 0x30) != 0x30)
+ {
+ /* a long CHAR() field: see #37426 */
+ length= byte1 | (((byte0 & 0x30) ^ 0x30) << 4);
+ type= byte0 | 0x30;
+ }
+ else
+ length = meta & 0xFF;
+ }
+ else
+ length= meta;
+ }
+
+ switch (type) {
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_TIMESTAMP:
+ return 4;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_YEAR:
+ return 1;
+ case MYSQL_TYPE_SHORT:
+ return 2;
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_DATE:
+ return 3;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_DATETIME:
+ return 8;
+ case MYSQL_TYPE_NEWDECIMAL:
+ {
+ uint precision= meta >> 8;
+ uint decimals= meta & 0xFF;
+ uint bin_size= my_decimal_get_binary_size(precision, decimals);
+ return bin_size;
+ }
+ case MYSQL_TYPE_FLOAT:
+ return 4;
+ case MYSQL_TYPE_DOUBLE:
+ return 8;
+ case MYSQL_TYPE_BIT:
+ {
+ /* Meta-data: bit_len, bytes_in_rec, 2 bytes */
+ uint nbits= ((meta >> 8) * 8) + (meta & 0xFF);
+ length= (nbits + 7) / 8;
+ return length;
+ }
+ case MYSQL_TYPE_TIMESTAMP2:
+ return my_timestamp_binary_length(meta);
+ case MYSQL_TYPE_DATETIME2:
+ return my_datetime_binary_length(meta);
+ case MYSQL_TYPE_TIME2:
+ return my_time_binary_length(meta);
+ case MYSQL_TYPE_ENUM:
+ switch (meta & 0xFF) {
+ case 1:
+ case 2:
+ return (meta & 0xFF);
+ default:
+ /* Unknown ENUM packlen=%d", meta & 0xFF */
+ return 0;
+ }
+ break;
+ case MYSQL_TYPE_SET:
+ return meta & 0xFF;
+ case MYSQL_TYPE_BLOB:
+ return (meta <= 4 ? meta : 0);
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_VAR_STRING:
+ length= meta;
+ /* fall through */
+ case MYSQL_TYPE_STRING:
+ if (length < 256)
+ return (uint) *ptr + 1;
+ return uint2korr(ptr) + 2;
+ case MYSQL_TYPE_DECIMAL:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+size_t
+Rows_log_event::calc_row_event_length(table_def *td,
+ PRINT_EVENT_INFO *print_event_info,
+ MY_BITMAP *cols_bitmap,
+ const uchar *value)
+{
+ const uchar *value0= value;
+ const uchar *null_bits= value;
+ uint null_bit_index= 0;
+
+ /*
+ Skip metadata bytes which gives the information about nullabity of master
+ columns. Master writes one bit for each affected column.
+ */
+
+ value+= (bitmap_bits_set(cols_bitmap) + 7) / 8;
+
+ for (uint i= 0; i < (uint)td->size(); i ++)
+ {
+ int is_null;
+ is_null= (null_bits[null_bit_index / 8] >> (null_bit_index % 8)) & 0x01;
+
+ if (bitmap_is_set(cols_bitmap, i) == 0)
+ continue;
+
+ if (!is_null)
+ {
+ size_t size;
+ size_t fsize= td->calc_field_size((uint)i, (uchar*) value);
+ if (value + fsize > m_rows_end)
+ {
+ /* Corrupted replication event was detected, skipping entry */
+ return 0;
+ }
+ if (!(size= calc_field_event_length(value, td->type(i),
+ td->field_metadata(i))))
+ return 0;
+ value+= size;
+ }
+ null_bit_index++;
+ }
+ return value - value0;
+}
+
+
+/**
+ Calculate how many rows there are in the event
+
+ @param[in] file IO cache
+ @param[in] print_event_into Print parameters
+*/
+
+void Rows_log_event::count_row_events(PRINT_EVENT_INFO *print_event_info)
+{
+ Table_map_log_event *map;
+ table_def *td;
+ uint row_events;
+ Log_event_type general_type_code= get_general_type_code();
+
+ switch (general_type_code) {
+ case WRITE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT:
+ row_events= 1;
+ break;
+ case UPDATE_ROWS_EVENT:
+ row_events= 2;
+ break;
+ default:
+ DBUG_ASSERT(0); /* Not possible */
+ return;
+ }
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ {
+ /* Row event for unknown table */
+ return;
+ }
+
+ for (const uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ size_t length;
+ print_event_info->row_events++;
+
+ /* Print the first image */
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+
+ /* Print the second image (for UPDATE only) */
+ if (row_events == 2)
+ {
+ if (!(length= calc_row_event_length(td, print_event_info,
+ &m_cols_ai, value)))
+ break;
+ value+= length;
+ DBUG_ASSERT(value <= m_rows_end);
+ }
+ }
+ delete td;
+}
+
+
+/**
+ Print a row event into IO cache in human readable form (in SQL format)
+
+ @param[in] file IO cache
+ @param[in] print_event_into Print parameters
+*/
+
+bool Rows_log_event::print_verbose(IO_CACHE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ Table_map_log_event *map;
+ table_def *td= 0;
+ const char *sql_command, *sql_clause1, *sql_clause2;
+ const char *sql_command_short __attribute__((unused));
+ Log_event_type general_type_code= get_general_type_code();
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ IO_CACHE *review_sql= &print_event_info->review_sql_cache;
+#endif
+
+ if (m_extra_row_data)
+ {
+ uint8 extra_data_len= m_extra_row_data[EXTRA_ROW_INFO_LEN_OFFSET];
+ uint8 extra_payload_len= extra_data_len - EXTRA_ROW_INFO_HDR_BYTES;
+ assert(extra_data_len >= EXTRA_ROW_INFO_HDR_BYTES);
+
+ if (my_b_printf(file, "### Extra row data format: %u, len: %u :",
+ m_extra_row_data[EXTRA_ROW_INFO_FORMAT_OFFSET],
+ extra_payload_len))
+ goto err;
+ if (extra_payload_len)
+ {
+ /*
+ Buffer for hex view of string, including '0x' prefix,
+ 2 hex chars / byte and trailing 0
+ */
+ const int buff_len= 2 + (256 * 2) + 1;
+ char buff[buff_len];
+ str_to_hex(buff, (const char*) &m_extra_row_data[EXTRA_ROW_INFO_HDR_BYTES],
+ extra_payload_len);
+ if (my_b_printf(file, "%s", buff))
+ goto err;
+ }
+ if (my_b_printf(file, "\n"))
+ goto err;
+ }
+
+ switch (general_type_code) {
+ case WRITE_ROWS_EVENT:
+ sql_command= "INSERT INTO";
+ sql_clause1= "### SET\n";
+ sql_clause2= NULL;
+ sql_command_short= "I";
+ break;
+ case DELETE_ROWS_EVENT:
+ sql_command= "DELETE FROM";
+ sql_clause1= "### WHERE\n";
+ sql_clause2= NULL;
+ sql_command_short= "D";
+ break;
+ case UPDATE_ROWS_EVENT:
+ sql_command= "UPDATE";
+ sql_clause1= "### WHERE\n";
+ sql_clause2= "### SET\n";
+ sql_command_short= "U";
+ break;
+ default:
+ sql_command= sql_clause1= sql_clause2= NULL;
+ sql_command_short= "";
+ DBUG_ASSERT(0); /* Not possible */
+ }
+
+ if (!(map= print_event_info->m_table_map.get_table(m_table_id)) ||
+ !(td= map->create_table_def()))
+ {
+ return (my_b_printf(file, "### Row event for unknown table #%lu",
+ (ulong) m_table_id));
+ }
+
+ /* If the write rows event contained no values for the AI */
+ if (((general_type_code == WRITE_ROWS_EVENT) && (m_rows_buf==m_rows_end)))
+ {
+ if (my_b_printf(file, "### INSERT INTO %`s.%`s VALUES ()\n",
+ map->get_db_name(), map->get_table_name()))
+ goto err;
+ goto end;
+ }
+
+ for (const uchar *value= m_rows_buf; value < m_rows_end; )
+ {
+ size_t length;
+ print_event_info->row_events++;
+
+ if (my_b_printf(file, "### %s %`s.%`s\n",
+ sql_command,
+ map->get_db_name(), map->get_table_name()))
+ goto err;
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ if (my_b_printf(review_sql, "\nINSERT INTO `%s`.`%s` VALUES ('%s'",
+ map->get_review_dbname(), map->get_review_tablename(),
+ sql_command_short))
+ goto err;
+#endif
+
+ /* Print the first image */
+ if (!(length= print_verbose_one_row(file, td, print_event_info,
+ &m_cols, value,
+ (const uchar*) sql_clause1)))
+ goto err;
+ value+= length;
+
+ /* Print the second image (for UPDATE only) */
+ if (sql_clause2)
+ {
+ if (!(length= print_verbose_one_row(file, td, print_event_info,
+ &m_cols_ai, value,
+ (const uchar*) sql_clause2)))
+ goto err;
+ value+= length;
+ }
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ else
+ {
+ if (need_flashback_review)
+ for (size_t i= 0; i < td->size(); i ++)
+ if (my_b_printf(review_sql, ", NULL"))
+ goto err;
+ }
+
+ if (need_flashback_review)
+ if (my_b_printf(review_sql, ")%s\n", print_event_info->delimiter))
+ goto err;
+#endif
+ }
+
+end:
+ delete td;
+ return 0;
+err:
+ delete td;
+ return 1;
+}
+
+void free_table_map_log_event(Table_map_log_event *event)
+{
+ delete event;
+}
+
+/**
+ Encode the event, optionally per 'do_print_encoded' arg store the
+ result into the argument cache; optionally per event_info's
+ 'verbose' print into the cache a verbose representation of the event.
+ Note, no extra wrapping is done to the being io-cached data, like
+ to producing a BINLOG query. It's left for a routine that extracts from
+ the cache.
+
+ @param file pointer to IO_CACHE
+ @param print_event_info pointer to print_event_info specializing
+ what out of and how to print the event
+ @param do_print_encoded whether to store base64-encoded event
+ into @file.
+*/
+bool Log_event::print_base64(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool do_print_encoded)
+{
+ uchar *ptr= (uchar *)temp_buf;
+ uint32 size= uint4korr(ptr + EVENT_LEN_OFFSET);
+ DBUG_ENTER("Log_event::print_base64");
+
+ if (is_flashback)
+ {
+ uint tmp_size= size;
+ Rows_log_event *ev= NULL;
+ Log_event_type ev_type = (enum Log_event_type) ptr[EVENT_TYPE_OFFSET];
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
+ tmp_size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
+ switch (ev_type) {
+ case WRITE_ROWS_EVENT:
+ ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT;
+ ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case WRITE_ROWS_EVENT_V1:
+ ptr[EVENT_TYPE_OFFSET]= DELETE_ROWS_EVENT_V1;
+ ev= new Delete_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case DELETE_ROWS_EVENT:
+ ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT;
+ ev= new Write_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case DELETE_ROWS_EVENT_V1:
+ ptr[EVENT_TYPE_OFFSET]= WRITE_ROWS_EVENT_V1;
+ ev= new Write_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ ev= new Update_rows_log_event((const char*) ptr, tmp_size,
+ glob_description_event);
+ ev->change_to_flashback_event(print_event_info, ptr, ev_type);
+ break;
+ default:
+ break;
+ }
+ delete ev;
+ }
+
+ if (do_print_encoded)
+ {
+ size_t const tmp_str_sz= my_base64_needed_encoded_length((int) size);
+ char *tmp_str;
+ if (!(tmp_str= (char *) my_malloc(tmp_str_sz, MYF(MY_WME))))
+ goto err;
+
+ if (my_base64_encode(ptr, (size_t) size, tmp_str))
+ {
+ DBUG_ASSERT(0);
+ }
+
+ my_b_printf(file, "%s\n", tmp_str);
+ my_free(tmp_str);
+ }
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ need_flashback_review)
+#else
+ // Flashback need the table_map to parse the event
+ if (print_event_info->verbose || print_event_info->print_row_count ||
+ is_flashback)
+#endif
+ {
+ Rows_log_event *ev= NULL;
+ Log_event_type et= (Log_event_type) ptr[EVENT_TYPE_OFFSET];
+
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF)
+ size-= BINLOG_CHECKSUM_LEN; // checksum is displayed through the header
+
+ switch (et)
+ {
+ case TABLE_MAP_EVENT:
+ {
+ Table_map_log_event *map;
+ map= new Table_map_log_event((const char*) ptr, size,
+ glob_description_event);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (need_flashback_review)
+ {
+ map->set_review_dbname(m_review_dbname.ptr());
+ map->set_review_tablename(m_review_tablename.ptr());
+ }
+#endif
+ print_event_info->m_table_map.set_table(map->get_table_id(), map);
+ break;
+ }
+ case WRITE_ROWS_EVENT:
+ case WRITE_ROWS_EVENT_V1:
+ {
+ ev= new Write_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case DELETE_ROWS_EVENT:
+ case DELETE_ROWS_EVENT_V1:
+ {
+ ev= new Delete_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case UPDATE_ROWS_EVENT:
+ case UPDATE_ROWS_EVENT_V1:
+ {
+ ev= new Update_rows_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case WRITE_ROWS_COMPRESSED_EVENT:
+ case WRITE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Write_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case UPDATE_ROWS_COMPRESSED_EVENT:
+ case UPDATE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Update_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ case DELETE_ROWS_COMPRESSED_EVENT:
+ case DELETE_ROWS_COMPRESSED_EVENT_V1:
+ {
+ ev= new Delete_rows_compressed_log_event((const char*) ptr, size,
+ glob_description_event);
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (ev)
+ {
+ bool error= 0;
+
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ ev->need_flashback_review= need_flashback_review;
+ if (print_event_info->verbose)
+ {
+ if (ev->print_verbose(file, print_event_info))
+ goto err;
+ }
+ else
+ {
+ IO_CACHE tmp_cache;
+
+ if (open_cached_file(&tmp_cache, NULL, NULL, 0,
+ MYF(MY_WME | MY_NABP)))
+ {
+ delete ev;
+ goto err;
+ }
+
+ error= ev->print_verbose(&tmp_cache, print_event_info);
+ close_cached_file(&tmp_cache);
+ if (unlikely(error))
+ {
+ delete ev;
+ goto err;
+ }
+ }
+#else
+ if (print_event_info->verbose)
+ {
+ /*
+ Verbose event printout can't start before encoded data
+ got enquoted. This is done at this point though multi-row
+ statement remain vulnerable.
+ TODO: fix MDEV-10362 to remove this workaround.
+ */
+ if (print_event_info->base64_output_mode !=
+ BASE64_OUTPUT_DECODE_ROWS)
+ my_b_printf(file, "'%s\n", print_event_info->delimiter);
+ error= ev->print_verbose(file, print_event_info);
+ }
+ else
+ {
+ ev->count_row_events(print_event_info);
+ }
+#endif
+ delete ev;
+ if (unlikely(error))
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Log_event::print_timestamp()
+*/
+
+bool Log_event::print_timestamp(IO_CACHE* file, time_t* ts)
+{
+ struct tm *res;
+ time_t my_when= when;
+ DBUG_ENTER("Log_event::print_timestamp");
+ if (!ts)
+ ts = &my_when;
+ res=localtime(ts);
+
+ DBUG_RETURN(my_b_printf(file,"%02d%02d%02d %2d:%02d:%02d",
+ res->tm_year % 100,
+ res->tm_mon+1,
+ res->tm_mday,
+ res->tm_hour,
+ res->tm_min,
+ res->tm_sec));
+}
+
+
+/**
+ Query_log_event::print().
+
+ @todo
+ print the catalog ??
+*/
+bool Query_log_event::print_query_header(IO_CACHE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ // TODO: print the catalog ??
+ char buff[64], *end; // Enough for SET TIMESTAMP
+ bool different_db= 1;
+ uint32 tmp;
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(file, print_event_info, FALSE) ||
+ my_b_printf(file,
+ "\t%s\tthread_id=%lu\texec_time=%lu\terror_code=%d\n",
+ get_type_str(), (ulong) thread_id, (ulong) exec_time,
+ error_code))
+ goto err;
+ }
+
+ if ((flags & LOG_EVENT_SUPPRESS_USE_F))
+ {
+ if (!is_trans_keyword())
+ print_event_info->db[0]= '\0';
+ }
+ else if (db)
+ {
+ different_db= memcmp(print_event_info->db, db, db_len + 1);
+ if (different_db)
+ memcpy(print_event_info->db, db, db_len + 1);
+ if (db[0] && different_db)
+ if (my_b_printf(file, "use %`s%s\n", db, print_event_info->delimiter))
+ goto err;
+ }
+
+ end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
+ if (when_sec_part && when_sec_part <= TIME_MAX_SECOND_PART)
+ {
+ *end++= '.';
+ end=int10_to_str(when_sec_part, end, 10);
+ }
+ end= strmov(end, print_event_info->delimiter);
+ *end++='\n';
+ if (my_b_write(file, (uchar*) buff, (uint) (end-buff)))
+ goto err;
+ if ((!print_event_info->thread_id_printed ||
+ ((flags & LOG_EVENT_THREAD_SPECIFIC_F) &&
+ thread_id != print_event_info->thread_id)))
+ {
+ // If --short-form, print deterministic value instead of pseudo_thread_id.
+ if (my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n",
+ short_form ? 999999999 : (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->thread_id= thread_id;
+ print_event_info->thread_id_printed= 1;
+ }
+
+ /*
+ If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to
+ print (remember we don't produce mixed relay logs so there cannot be
+ 5.0 events before that one so there is nothing to reset).
+ */
+ if (likely(flags2_inited)) /* likely as this will mainly read 5.0 logs */
+ {
+ /* tmp is a bitmask of bits which have changed. */
+ if (likely(print_event_info->flags2_inited))
+ /* All bits which have changed */
+ tmp= (print_event_info->flags2) ^ flags2;
+ else /* that's the first Query event we read */
+ {
+ print_event_info->flags2_inited= 1;
+ tmp= ~((uint32)0); /* all bits have changed */
+ }
+
+ if (unlikely(tmp)) /* some bits have changed */
+ {
+ bool need_comma= 0;
+ if (my_b_write_string(file, "SET ") ||
+ print_set_option(file, tmp, OPTION_NO_FOREIGN_KEY_CHECKS, ~flags2,
+ "@@session.foreign_key_checks", &need_comma)||
+ print_set_option(file, tmp, OPTION_AUTO_IS_NULL, flags2,
+ "@@session.sql_auto_is_null", &need_comma) ||
+ print_set_option(file, tmp, OPTION_RELAXED_UNIQUE_CHECKS, ~flags2,
+ "@@session.unique_checks", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NOT_AUTOCOMMIT, ~flags2,
+ "@@session.autocommit", &need_comma) ||
+ print_set_option(file, tmp, OPTION_NO_CHECK_CONSTRAINT_CHECKS,
+ ~flags2,
+ "@@session.check_constraint_checks", &need_comma) ||
+ my_b_printf(file,"%s\n", print_event_info->delimiter))
+ goto err;
+ print_event_info->flags2= flags2;
+ }
+ }
+
+ /*
+ Now the session variables;
+ it's more efficient to pass SQL_MODE as a number instead of a
+ comma-separated list.
+ FOREIGN_KEY_CHECKS, SQL_AUTO_IS_NULL, UNIQUE_CHECKS are session-only
+ variables (they have no global version; they're not listed in
+ sql_class.h), The tests below work for pure binlogs or pure relay
+ logs. Won't work for mixed relay logs but we don't create mixed
+ relay logs (that is, there is no relay log with a format change
+ except within the 3 first events, which mysqlbinlog handles
+ gracefully). So this code should always be good.
+ */
+
+ if (likely(sql_mode_inited) &&
+ (unlikely(print_event_info->sql_mode != sql_mode ||
+ !print_event_info->sql_mode_inited)))
+ {
+ char llbuff[22];
+ if (my_b_printf(file,"SET @@session.sql_mode=%s%s\n",
+ ullstr(sql_mode, llbuff), print_event_info->delimiter))
+ goto err;
+ print_event_info->sql_mode= sql_mode;
+ print_event_info->sql_mode_inited= 1;
+ }
+ if (print_event_info->auto_increment_increment != auto_increment_increment ||
+ print_event_info->auto_increment_offset != auto_increment_offset)
+ {
+ if (my_b_printf(file,"SET @@session.auto_increment_increment=%lu, @@session.auto_increment_offset=%lu%s\n",
+ auto_increment_increment,auto_increment_offset,
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->auto_increment_increment= auto_increment_increment;
+ print_event_info->auto_increment_offset= auto_increment_offset;
+ }
+
+ /* TODO: print the catalog when we feature SET CATALOG */
+
+ if (likely(charset_inited) &&
+ (unlikely(!print_event_info->charset_inited ||
+ memcmp(print_event_info->charset, charset, 6))))
+ {
+ CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME));
+ if (cs_info)
+ {
+ /* for mysql client */
+ if (my_b_printf(file, "/*!\\C %s */%s\n",
+ cs_info->csname, print_event_info->delimiter))
+ goto err;
+ }
+ if (my_b_printf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ "%s\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4),
+ print_event_info->delimiter))
+ goto err;
+ memcpy(print_event_info->charset, charset, 6);
+ print_event_info->charset_inited= 1;
+ }
+ if (time_zone_len)
+ {
+ if (memcmp(print_event_info->time_zone_str,
+ time_zone_str, time_zone_len+1))
+ {
+ if (my_b_printf(file,"SET @@session.time_zone='%s'%s\n",
+ time_zone_str, print_event_info->delimiter))
+ goto err;
+ memcpy(print_event_info->time_zone_str, time_zone_str, time_zone_len+1);
+ }
+ }
+ if (lc_time_names_number != print_event_info->lc_time_names_number)
+ {
+ if (my_b_printf(file, "SET @@session.lc_time_names=%d%s\n",
+ lc_time_names_number, print_event_info->delimiter))
+ goto err;
+ print_event_info->lc_time_names_number= lc_time_names_number;
+ }
+ if (charset_database_number != print_event_info->charset_database_number)
+ {
+ if (charset_database_number)
+ {
+ if (my_b_printf(file, "SET @@session.collation_database=%d%s\n",
+ charset_database_number, print_event_info->delimiter))
+ goto err;
+ }
+ else if (my_b_printf(file, "SET @@session.collation_database=DEFAULT%s\n",
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->charset_database_number= charset_database_number;
+ }
+ return 0;
+
+err:
+ return 1;
+}
+
+
+bool Query_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file, 0, this);
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_write().
+ */
+ DBUG_EXECUTE_IF ("simulate_file_write_error",
+ {(&cache)->write_pos= (&cache)->write_end- 500;});
+ if (print_query_header(&cache, print_event_info))
+ goto err;
+ if (!is_flashback)
+ {
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else // is_flashback == 1
+ {
+ if (strcmp("BEGIN", query) == 0)
+ {
+ if (my_b_write(&cache, (uchar*) "COMMIT", 6) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else if (strcmp("COMMIT", query) == 0)
+ {
+ if (my_b_write(&cache, (uchar*) "BEGIN", 5) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ }
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ DBUG_ENTER("Start_log_event_v3::print");
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tStart: binlog v %d, server v %s created ",
+ binlog_version, server_version) ||
+ print_timestamp(&cache))
+ goto err;
+ if (created)
+ if (my_b_printf(&cache," at startup"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
+ if (flags & LOG_EVENT_BINLOG_IN_USE_F)
+ if (my_b_printf(&cache,
+ "# Warning: this binlog is either in use or was not "
+ "closed properly.\n"))
+ goto err;
+ }
+ if (!is_artificial_event() && created)
+ {
+#ifdef WHEN_WE_HAVE_THE_RESET_CONNECTION_SQL_COMMAND
+ /*
+ This is for mysqlbinlog: like in replication, we want to delete the stale
+ tmp files left by an unclean shutdown of mysqld (temporary tables)
+ and rollback unfinished transaction.
+ Probably this can be done with RESET CONNECTION (syntax to be defined).
+ */
+ if (my_b_printf(&cache,"RESET CONNECTION%s\n",
+ print_event_info->delimiter))
+ goto err;
+#else
+ if (my_b_printf(&cache,"ROLLBACK%s\n", print_event_info->delimiter))
+ goto err;
+#endif
+ }
+ if (temp_buf &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ !print_event_info->short_form)
+ {
+ /* BINLOG is matched with the delimiter below on the same level */
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS;
+ if (do_print_encoded)
+ my_b_printf(&cache, "BINLOG '\n");
+
+ if (print_base64(&cache, print_event_info, do_print_encoded))
+ goto err;
+
+ if (do_print_encoded)
+ my_b_printf(&cache, "'%s\n", print_event_info->delimiter);
+
+ print_event_info->printed_fd_event= TRUE;
+ }
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
+}
+
+
+bool Start_encryption_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+ StringBuffer<1024> buf;
+ buf.append(STRING_WITH_LEN("# Encryption scheme: "));
+ buf.append_ulonglong(crypto_scheme);
+ buf.append(STRING_WITH_LEN(", key_version: "));
+ buf.append_ulonglong(key_version);
+ buf.append(STRING_WITH_LEN(", nonce: "));
+ buf.append_hex(nonce, BINLOG_NONCE_LENGTH);
+ buf.append(STRING_WITH_LEN("\n# The rest of the binlog is encrypted!\n"));
+ if (my_b_write(&cache, (uchar*)buf.ptr(), buf.length()))
+ return 1;
+ return (cache.flush_data());
+}
+
+
+bool Load_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+
+bool Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
+ bool commented)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
+ bool different_db= 1;
+ DBUG_ENTER("Load_log_event::print");
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tQuery\tthread_id=%ld\texec_time=%ld\n",
+ thread_id, exec_time))
+ goto err;
+ }
+
+ if (db)
+ {
+ /*
+ If the database is different from the one of the previous statement, we
+ need to print the "use" command, and we update the last_db.
+ But if commented, the "use" is going to be commented so we should not
+ update the last_db.
+ */
+ if ((different_db= memcmp(print_event_info->db, db, db_len + 1)) &&
+ !commented)
+ memcpy(print_event_info->db, db, db_len + 1);
+ }
+
+ if (db && db[0] && different_db)
+ if (my_b_printf(&cache, "%suse %`s%s\n",
+ commented ? "# " : "",
+ db, print_event_info->delimiter))
+ goto err;
+
+ if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
+ if (my_b_printf(&cache,"%sSET @@session.pseudo_thread_id=%lu%s\n",
+ commented ? "# " : "", (ulong)thread_id,
+ print_event_info->delimiter))
+ goto err;
+ if (my_b_printf(&cache, "%sLOAD DATA ",
+ commented ? "# " : ""))
+ goto err;
+ if (check_fname_outside_temp_buf())
+ if (my_b_write_string(&cache, "LOCAL "))
+ goto err;
+ if (my_b_printf(&cache, "INFILE '%-*s' ", fname_len, fname))
+ goto err;
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ {
+ if (my_b_write_string(&cache, "REPLACE "))
+ goto err;
+ }
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ if (my_b_write_string(&cache, "IGNORE "))
+ goto err;
+
+ if (my_b_printf(&cache, "INTO TABLE `%s`", table_name) ||
+ my_b_write_string(&cache, " FIELDS TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.field_term, sql_ex.field_term_len))
+ goto err;
+
+ if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
+ if (my_b_write_string(&cache, " OPTIONALLY "))
+ goto err;
+ if (my_b_write_string(&cache, " ENCLOSED BY ") ||
+ pretty_print_str(&cache, sql_ex.enclosed, sql_ex.enclosed_len) ||
+ my_b_write_string(&cache, " ESCAPED BY ") ||
+ pretty_print_str(&cache, sql_ex.escaped, sql_ex.escaped_len) ||
+ my_b_write_string(&cache, " LINES TERMINATED BY ") ||
+ pretty_print_str(&cache, sql_ex.line_term, sql_ex.line_term_len))
+ goto err;
+
+ if (sql_ex.line_start)
+ {
+ if (my_b_write_string(&cache," STARTING BY ") ||
+ pretty_print_str(&cache, sql_ex.line_start, sql_ex.line_start_len))
+ goto err;
+ }
+ if ((long) skip_lines > 0)
+ if (my_b_printf(&cache, " IGNORE %ld LINES", (long) skip_lines))
+ goto err;
+
+ if (num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ if (my_b_write_string(&cache, " ("))
+ goto err;
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ if (my_b_write_byte(&cache, ','))
+ goto err;
+ if (my_b_printf(&cache, "%`s", field))
+ goto err;
+ field += field_lens[i] + 1;
+ }
+ if (my_b_write_byte(&cache, ')'))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, "%s\n", print_event_info->delimiter))
+ goto err;
+ DBUG_RETURN(cache.flush_data());
+err:
+ DBUG_RETURN(1);
+}
+
+
+bool Rotate_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ char buf[22];
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRotate to "))
+ goto err;
+ if (new_log_ident)
+ if (my_b_write(&cache, (uchar*) new_log_ident, (uint)ident_len))
+ goto err;
+ if (my_b_printf(&cache, " pos: %s\n", llstr(pos, buf)))
+ goto err;
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Binlog_checkpoint_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tBinlog checkpoint ") ||
+ my_b_write(&cache, (uchar*)binlog_file_name, binlog_file_len) ||
+ my_b_write_byte(&cache, '\n'))
+ return 1;
+ return cache.flush_data();
+}
+
+
+bool
+Gtid_list_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+ char buf[21];
+ uint32 i;
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tGtid list ["))
+ goto err;
+
+ for (i= 0; i < count; ++i)
+ {
+ longlong10_to_str(list[i].seq_no, buf, 10);
+ if (my_b_printf(&cache, "%u-%u-%s", list[i].domain_id,
+ list[i].server_id, buf))
+ goto err;
+ if (i < count-1)
+ if (my_b_printf(&cache, ",\n# "))
+ goto err;
+ }
+ if (my_b_printf(&cache, "]\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ char llbuff[22];
+ const char *UNINIT_VAR(msg);
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tIntvar\n"))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, "SET "))
+ goto err;
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ msg="LAST_INSERT_ID";
+ break;
+ case INSERT_ID_EVENT:
+ msg="INSERT_ID";
+ break;
+ case INVALID_INT_EVENT:
+ default: // cannot happen
+ msg="INVALID_INT";
+ break;
+ }
+ if (my_b_printf(&cache, "%s=%s%s\n",
+ msg, llstr(val,llbuff), print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Rand_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ char llbuff[22],llbuff2[22];
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tRand\n"))
+ goto err;
+ }
+ if (my_b_printf(&cache, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s%s\n",
+ llstr(seed1, llbuff),llstr(seed2, llbuff2),
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Xid_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+
+ if (!print_event_info->short_form)
+ {
+ char buf[64];
+ longlong10_to_str(xid, buf, 10);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\tXid = %s\n", buf))
+ goto err;
+ }
+ if (my_b_printf(&cache, is_flashback ? "BEGIN%s\n" : "COMMIT%s\n",
+ print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool User_var_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F);
+
+ if (!print_event_info->short_form)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tUser_var\n"))
+ goto err;
+ }
+
+ if (my_b_write_string(&cache, "SET @") ||
+ my_b_write_backtick_quote(&cache, name, name_len))
+ goto err;
+
+ if (is_null)
+ {
+ if (my_b_printf(&cache, ":=NULL%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ double real_val;
+ char real_buf[FMT_G_BUFSIZE(14)];
+ float8get(real_val, val);
+ sprintf(real_buf, "%.14g", real_val);
+ if (my_b_printf(&cache, ":=%s%s\n", real_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ case INT_RESULT:
+ char int_buf[22];
+ longlong10_to_str(uint8korr(val), int_buf,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10));
+ if (my_b_printf(&cache, ":=%s%s\n", int_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ case DECIMAL_RESULT:
+ {
+ char str_buf[200];
+ int str_len= sizeof(str_buf) - 1;
+ int precision= (int)val[0];
+ int scale= (int)val[1];
+ decimal_digit_t dec_buf[10];
+ decimal_t dec;
+ dec.len= 10;
+ dec.buf= dec_buf;
+
+ bin2decimal((uchar*) val+2, &dec, precision, scale);
+ decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
+ str_buf[str_len]= 0;
+ if (my_b_printf(&cache, ":=%s%s\n", str_buf,
+ print_event_info->delimiter))
+ goto err;
+ break;
+ }
+ case STRING_RESULT:
+ {
+ /*
+ Let's express the string in hex. That's the most robust way. If we
+ print it in character form instead, we need to escape it with
+ character_set_client which we don't know (we will know it in 5.0, but
+ in 4.1 we don't know it easily when we are printing
+ User_var_log_event). Explanation why we would need to bother with
+ character_set_client (quoting Bar):
+ > Note, the parser doesn't switch to another unescaping mode after
+ > it has met a character set introducer.
+ > For example, if an SJIS client says something like:
+ > SET @a= _ucs2 \0a\0b'
+ > the string constant is still unescaped according to SJIS, not
+ > according to UCS2.
+ */
+ char *hex_str;
+ CHARSET_INFO *cs;
+ bool error;
+
+ // 2 hex digits / byte
+ hex_str= (char *) my_malloc(2 * val_len + 1 + 3, MYF(MY_WME));
+ if (!hex_str)
+ goto err;
+ str_to_hex(hex_str, val, val_len);
+ /*
+ For proper behaviour when mysqlbinlog|mysql, we need to explicitly
+ specify the variable's collation. It will however cause problems when
+ people want to mysqlbinlog|mysql into another server not supporting the
+ character set. But there's not much to do about this and it's unlikely.
+ */
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ { /*
+ Generate an unusable command (=> syntax error) is probably the best
+ thing we can do here.
+ */
+ error= my_b_printf(&cache, ":=???%s\n", print_event_info->delimiter);
+ }
+ else
+ error= my_b_printf(&cache, ":=_%s %s COLLATE `%s`%s\n",
+ cs->csname, hex_str, cs->name,
+ print_event_info->delimiter);
+ my_free(hex_str);
+ if (unlikely(error))
+ goto err;
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ }
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+#ifdef HAVE_REPLICATION
+
+bool Unknown_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file_arg);
+
+ if (what != ENCRYPTED)
+ {
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Unknown event\n"))
+ goto err;
+ }
+ else if (my_b_printf(&cache, "# Encrypted event\n"))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+bool Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_write_string(&cache, "\tStop\n"))
+ return 1;
+ return cache.flush_data();
+}
+
+#endif
+
+
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ bool enable_local)
+{
+ if (print_event_info->short_form)
+ {
+ if (enable_local && check_fname_outside_temp_buf())
+ return Load_log_event::print(file, print_event_info);
+ return 0;
+ }
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (enable_local)
+ {
+ if (Load_log_event::print(file, print_event_info,
+ !check_fname_outside_temp_buf()))
+ goto err;
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_create_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
+ /*
+ That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
+ SHOW BINLOG EVENTS we don't.
+ */
+ if (my_b_write_byte(&cache, '#'))
+ goto err;
+ }
+
+ if (my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+
+}
+
+
+bool Create_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+
+/*
+ Append_block_log_event::print()
+*/
+
+bool Append_block_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#%s: file_id: %d block_len: %d\n",
+ get_type_str(), file_id, block_len))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+/*
+ Delete_file_log_event::print()
+*/
+
+bool Delete_file_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Delete_file: file_id=%u\n", file_id))
+ return 1;
+
+ return cache.flush_data();
+}
+
+/*
+ Execute_load_log_event::print()
+*/
+
+bool Execute_load_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n#Exec_load: file_id=%d\n",
+ file_id))
+ return 1;
+
+ return cache.flush_data();
+}
+
+bool Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return print(file, print_event_info, 0);
+}
+
+/**
+ Prints the query as LOAD DATA LOCAL and with rewritten filename.
+*/
+bool Execute_load_query_log_event::print(FILE* file,
+ PRINT_EVENT_INFO* print_event_info,
+ const char *local_fname)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_query_header(&cache, print_event_info))
+ goto err;
+
+ /**
+ reduce the size of io cache so that the write function is called
+ for every call to my_b_printf().
+ */
+ DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
+ {(&cache)->write_pos= (&cache)->write_end;
+ DBUG_SET("+d,simulate_file_write_error");});
+
+ if (local_fname)
+ {
+ if (my_b_write(&cache, (uchar*) query, fn_pos_start) ||
+ my_b_write_string(&cache, " LOCAL INFILE ") ||
+ pretty_print_str(&cache, local_fname, (int)strlen(local_fname)))
+ goto err;
+
+ if (dup_handling == LOAD_DUP_REPLACE)
+ if (my_b_write_string(&cache, " REPLACE"))
+ goto err;
+
+ if (my_b_write_string(&cache, " INTO") ||
+ my_b_write(&cache, (uchar*) query + fn_pos_end, q_len-fn_pos_end) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+ else
+ {
+ if (my_b_write(&cache, (uchar*) query, q_len) ||
+ my_b_printf(&cache, "\n%s\n", print_event_info->delimiter))
+ goto err;
+ }
+
+ if (!print_event_info->short_form)
+ my_b_printf(&cache, "# file_id: %d \n", file_id);
+
+ return cache.flush_data();
+err:
+ return 1;
+}
+
+
+
+const char str_binlog[]= "\nBINLOG '\n";
+const char fmt_delim[]= "'%s\n";
+const char fmt_n_delim[]= "\n'%s";
+const char fmt_frag[]= "\nSET @binlog_fragment_%d ='\n";
+const char fmt_binlog2[]= "BINLOG @binlog_fragment_0, @binlog_fragment_1%s\n";
+
+/**
+ Print an event "body" cache to @c file possibly in two fragments.
+ Each fragement is optionally per @c do_wrap to produce an SQL statement.
+
+ @param file a file to print to
+ @param body the "body" IO_CACHE of event
+ @param do_wrap whether to wrap base64-encoded strings with
+ SQL cover.
+ @param delimiter delimiter string
+
+ @param is_verbose MDEV-10362 workraround parameter to pass
+ info on presence of verbose printout in cache encoded data
+
+ The function signals on any error through setting @c body->error to -1.
+*/
+bool copy_cache_to_file_wrapped(IO_CACHE *body,
+ FILE *file,
+ bool do_wrap,
+ const char *delimiter,
+ bool is_verbose)
+{
+ const my_off_t cache_size= my_b_tell(body);
+
+ if (reinit_io_cache(body, READ_CACHE, 0L, FALSE, FALSE))
+ goto err;
+
+ if (!do_wrap)
+ {
+ my_b_copy_to_file(body, file, SIZE_T_MAX);
+ }
+ else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
+ opt_binlog_rows_event_max_encoded_size)
+ {
+ /*
+ 2 fragments can always represent near 1GB row-based
+ base64-encoded event as two strings each of size less than
+ max(max_allowed_packet). Greater number of fragments does not
+ save from potential need to tweak (increase) @@max_allowed_packet
+ before to process the fragments. So 2 is safe and enough.
+
+ Split the big query when its packet size's estimation exceeds a
+ limit. The estimate includes the maximum packet header
+ contribution of non-compressed packet.
+ */
+ my_fprintf(file, fmt_frag, 0);
+ if (my_b_copy_to_file(body, file, (size_t) cache_size/2 + 1))
+ goto err;
+ my_fprintf(file, fmt_n_delim, delimiter);
+
+ my_fprintf(file, fmt_frag, 1);
+ if (my_b_copy_to_file(body, file, SIZE_T_MAX))
+ goto err;
+ if (!is_verbose)
+ my_fprintf(file, fmt_delim, delimiter);
+
+ my_fprintf(file, fmt_binlog2, delimiter);
+ }
+ else
+ {
+ my_fprintf(file, str_binlog);
+ if (my_b_copy_to_file(body, file, SIZE_T_MAX))
+ goto err;
+ if (!is_verbose)
+ my_fprintf(file, fmt_delim, delimiter);
+ }
+ reinit_io_cache(body, WRITE_CACHE, 0, FALSE, TRUE);
+
+ return false;
+
+err:
+ body->error = -1;
+ return true;
+}
+
+
+/**
+ Print an event "body" cache to @c file possibly in two fragments.
+ Each fragement is optionally per @c do_wrap to produce an SQL statement.
+
+ @param file a file to print to
+ @param body the "body" IO_CACHE of event
+ @param do_wrap whether to wrap base64-encoded strings with
+ SQL cover.
+ @param delimiter delimiter string
+
+ The function signals on any error through setting @c body->error to -1.
+*/
+bool copy_cache_to_string_wrapped(IO_CACHE *cache,
+ LEX_STRING *to,
+ bool do_wrap,
+ const char *delimiter,
+ bool is_verbose)
+{
+ const my_off_t cache_size= my_b_tell(cache);
+ // contribution to total size estimate of formating
+ const size_t fmt_size=
+ sizeof(str_binlog) + 2*(sizeof(fmt_frag) + 2 /* %d */) +
+ sizeof(fmt_delim) + sizeof(fmt_n_delim) +
+ sizeof(fmt_binlog2) +
+ 3*PRINT_EVENT_INFO::max_delimiter_size;
+
+ if (reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE))
+ goto err;
+
+ if (!(to->str= (char*) my_malloc((size_t)cache->end_of_file + fmt_size,
+ MYF(0))))
+ {
+ perror("Out of memory: can't allocate memory in "
+ "copy_cache_to_string_wrapped().");
+ goto err;
+ }
+
+ if (!do_wrap)
+ {
+ if (my_b_read(cache, (uchar*) to->str,
+ (to->length= (size_t)cache->end_of_file)))
+ goto err;
+ }
+ else if (4 + sizeof(str_binlog) + cache_size + sizeof(fmt_delim) >
+ opt_binlog_rows_event_max_encoded_size)
+ {
+ /*
+ 2 fragments can always represent near 1GB row-based
+ base64-encoded event as two strings each of size less than
+ max(max_allowed_packet). Greater number of fragments does not
+ save from potential need to tweak (increase) @@max_allowed_packet
+ before to process the fragments. So 2 is safe and enough.
+
+ Split the big query when its packet size's estimation exceeds a
+ limit. The estimate includes the maximum packet header
+ contribution of non-compressed packet.
+ */
+ char *str= to->str;
+ size_t add_to_len;
+
+ str += (to->length= sprintf(str, fmt_frag, 0));
+ if (my_b_read(cache, (uchar*) str, (uint32) (cache_size/2 + 1)))
+ goto err;
+ str += (add_to_len = (uint32) (cache_size/2 + 1));
+ to->length += add_to_len;
+ str += (add_to_len= sprintf(str, fmt_n_delim, delimiter));
+ to->length += add_to_len;
+
+ str += (add_to_len= sprintf(str, fmt_frag, 1));
+ to->length += add_to_len;
+ if (my_b_read(cache, (uchar*) str, uint32(cache->end_of_file - (cache_size/2 + 1))))
+ goto err;
+ str += (add_to_len= uint32(cache->end_of_file - (cache_size/2 + 1)));
+ to->length += add_to_len;
+ if (!is_verbose)
+ {
+ str += (add_to_len= sprintf(str , fmt_delim, delimiter));
+ to->length += add_to_len;
+ }
+ to->length += sprintf(str, fmt_binlog2, delimiter);
+ }
+ else
+ {
+ char *str= to->str;
+
+ str += (to->length= sprintf(str, str_binlog));
+ if (my_b_read(cache, (uchar*) str, (size_t)cache->end_of_file))
+ goto err;
+ str += cache->end_of_file;
+ to->length += (size_t)cache->end_of_file;
+ if (!is_verbose)
+ to->length += sprintf(str , fmt_delim, delimiter);
+ }
+
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+
+ return false;
+
+err:
+ cache->error= -1;
+ return true;
+}
+
+/**
+ The function invokes base64 encoder to run on the current
+ event string and store the result into two caches.
+ When the event ends the current statement the caches are is copied into
+ the argument file.
+ Copying is also concerned how to wrap the event, specifically to produce
+ a valid SQL syntax.
+ When the encoded data size is within max(MAX_ALLOWED_PACKET)
+ a regular BINLOG query is composed. Otherwise it is build as fragmented
+
+ SET @binlog_fragment_0='...';
+ SET @binlog_fragment_1='...';
+ BINLOG @binlog_fragment_0, @binlog_fragment_1;
+
+ where fragments are represented by a pair of indexed user
+ "one shot" variables.
+
+ @note
+ If any changes made don't forget to duplicate them to
+ Old_rows_log_event as long as it's supported.
+
+ @param file pointer to IO_CACHE
+ @param print_event_info pointer to print_event_info specializing
+ what out of and how to print the event
+ @param name the name of a table that the event operates on
+
+ The function signals on any error of cache access through setting
+ that cache's @c error to -1.
+*/
+bool Rows_log_event::print_helper(FILE *file,
+ PRINT_EVENT_INFO *print_event_info,
+ char const *const name)
+{
+ IO_CACHE *const head= &print_event_info->head_cache;
+ IO_CACHE *const body= &print_event_info->body_cache;
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ IO_CACHE *const sql= &print_event_info->review_sql_cache;
+#endif
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
+ !print_event_info->short_form;
+ bool const last_stmt_event= get_flags(STMT_END_F);
+
+ if (!print_event_info->short_form)
+ {
+ char llbuff[22];
+
+ print_header(head, print_event_info, !last_stmt_event);
+ if (my_b_printf(head, "\t%s: table id %s%s\n",
+ name, ullstr(m_table_id, llbuff),
+ last_stmt_event ? " flags: STMT_END_F" : ""))
+ goto err;
+ }
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ if (print_base64(body, print_event_info, do_print_encoded))
+ goto err;
+
+ if (last_stmt_event)
+ {
+ if (!is_flashback)
+ {
+ if (copy_event_cache_to_file_and_reinit(head, file) ||
+ copy_cache_to_file_wrapped(body, file, do_print_encoded,
+ print_event_info->delimiter,
+ print_event_info->verbose))
+ goto err;
+ }
+ else
+ {
+ LEX_STRING tmp_str;
+
+ if (copy_event_cache_to_string_and_reinit(head, &tmp_str))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length); // Not \0 terminated);
+ my_free(tmp_str.str);
+
+ if (copy_cache_to_string_wrapped(body, &tmp_str, do_print_encoded,
+ print_event_info->delimiter,
+ print_event_info->verbose))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length);
+ my_free(tmp_str.str);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ if (copy_event_cache_to_string_and_reinit(sql, &tmp_str))
+ return 1;
+ output_buf.append(tmp_str.str, tmp_str.length);
+ my_free(tmp_str.str);
+#endif
+ }
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
+{
+ char *pbeg; // beginning of the next line
+ char *pend; // end of the next line
+ uint cnt= 0; // characters counter
+
+ if (!pinfo->short_form)
+ {
+ if (print_header(&pinfo->head_cache, pinfo, TRUE) ||
+ my_b_printf(&pinfo->head_cache, "\tAnnotate_rows:\n"))
+ goto err;
+ }
+ else if (my_b_printf(&pinfo->head_cache, "# Annotate_rows:\n"))
+ goto err;
+
+ for (pbeg= m_query_txt; ; pbeg= pend)
+ {
+ // skip all \r's and \n's at the beginning of the next line
+ for (;; pbeg++)
+ {
+ if (++cnt > m_query_len)
+ return 0;
+
+ if (*pbeg != '\r' && *pbeg != '\n')
+ break;
+ }
+
+ // find end of the next line
+ for (pend= pbeg + 1;
+ ++cnt <= m_query_len && *pend != '\r' && *pend != '\n';
+ pend++)
+ ;
+
+ // print next line
+ if (my_b_write(&pinfo->head_cache, (const uchar*) "#Q> ", 4) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) pbeg, pend - pbeg) ||
+ my_b_write(&pinfo->head_cache, (const uchar*) "\n", 1))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+/*
+ Rewrite database name for the event to name specified by new_db
+ SYNOPSIS
+ new_db Database name to change to
+ new_len Length
+ desc Event describing binlog that we're writing to.
+
+ DESCRIPTION
+ Reset db name. This function assumes that temp_buf member contains event
+ representation taken from a binary log. It resets m_dbnam and m_dblen and
+ rewrites temp_buf with new db name.
+
+ RETURN
+ 0 - Success
+ other - Error
+*/
+
+int Table_map_log_event::rewrite_db(const char* new_db, size_t new_len,
+ const Format_description_log_event* desc)
+{
+ DBUG_ENTER("Table_map_log_event::rewrite_db");
+ DBUG_ASSERT(temp_buf);
+
+ uint header_len= MY_MIN(desc->common_header_len,
+ LOG_EVENT_MINIMAL_HEADER_LEN) + TABLE_MAP_HEADER_LEN;
+ int len_diff;
+
+ if (!(len_diff= (int)(new_len - m_dblen)))
+ {
+ memcpy((void*) (temp_buf + header_len + 1), new_db, m_dblen + 1);
+ memcpy((void*) m_dbnam, new_db, m_dblen + 1);
+ DBUG_RETURN(0);
+ }
+
+ // Create new temp_buf
+ ulong event_cur_len= uint4korr(temp_buf + EVENT_LEN_OFFSET);
+ ulong event_new_len= event_cur_len + len_diff;
+ char* new_temp_buf= (char*) my_malloc(event_new_len, MYF(MY_WME));
+
+ if (!new_temp_buf)
+ {
+ sql_print_error("Table_map_log_event::rewrite_db: "
+ "failed to allocate new temp_buf (%d bytes required)",
+ event_new_len);
+ DBUG_RETURN(-1);
+ }
+
+ // Rewrite temp_buf
+ char* ptr= new_temp_buf;
+ size_t cnt= 0;
+
+ // Copy header and change event length
+ memcpy(ptr, temp_buf, header_len);
+ int4store(ptr + EVENT_LEN_OFFSET, event_new_len);
+ ptr += header_len;
+ cnt += header_len;
+
+ // Write new db name length and new name
+ DBUG_ASSERT(new_len < 0xff);
+ *ptr++ = (char)new_len;
+ memcpy(ptr, new_db, new_len + 1);
+ ptr += new_len + 1;
+ cnt += m_dblen + 2;
+
+ // Copy rest part
+ memcpy(ptr, temp_buf + cnt, event_cur_len - cnt);
+
+ // Reregister temp buf
+ free_temp_buf();
+ register_temp_buf(new_temp_buf, TRUE);
+
+ // Reset m_dbnam and m_dblen members
+ m_dblen= new_len;
+
+ // m_dbnam resides in m_memory together with m_tblnam and m_coltype
+ uchar* memory= m_memory;
+ char const* tblnam= m_tblnam;
+ uchar* coltype= m_coltype;
+
+ m_memory= (uchar*) my_multi_malloc(MYF(MY_WME),
+ &m_dbnam, (uint) m_dblen + 1,
+ &m_tblnam, (uint) m_tbllen + 1,
+ &m_coltype, (uint) m_colcnt,
+ NullS);
+
+ if (!m_memory)
+ {
+ sql_print_error("Table_map_log_event::rewrite_db: "
+ "failed to allocate new m_memory (%d + %d + %d bytes required)",
+ m_dblen + 1, m_tbllen + 1, m_colcnt);
+ DBUG_RETURN(-1);
+ }
+
+ memcpy((void*)m_dbnam, new_db, m_dblen + 1);
+ memcpy((void*)m_tblnam, tblnam, m_tbllen + 1);
+ memcpy(m_coltype, coltype, m_colcnt);
+
+ my_free(memory);
+ DBUG_RETURN(0);
+}
+
+
+bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ if (!print_event_info->short_form)
+ {
+ char llbuff[22];
+
+ print_header(&print_event_info->head_cache, print_event_info, TRUE);
+ if (my_b_printf(&print_event_info->head_cache,
+ "\tTable_map: %`s.%`s mapped to number %s%s\n",
+ m_dbnam, m_tblnam, ullstr(m_table_id, llbuff),
+ ((m_flags & TM_BIT_HAS_TRIGGERS_F) ?
+ " (has triggers)" : "")))
+ goto err;
+ }
+ if (!print_event_info->short_form || print_event_info->print_row_count)
+ {
+ bool do_print_encoded=
+ print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
+ print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
+ !print_event_info->short_form;
+
+ if (print_base64(&print_event_info->body_cache, print_event_info,
+ do_print_encoded) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
+{
+ DBUG_EXECUTE_IF("simulate_cache_read_error",
+ {DBUG_SET("+d,simulate_my_b_fill_error");});
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Delete_rows" : "Write_rows");
+}
+
+bool Write_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc = false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Write_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress write_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Delete_rows_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return Rows_log_event::print_helper(file, print_event_info, is_flashback ? "Write_rows" : "Delete_rows");
+}
+
+
+bool Delete_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc = false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Delete_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress delete_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Update_rows_log_event::print(FILE *file,
+ PRINT_EVENT_INFO* print_event_info)
+{
+ return Rows_log_event::print_helper(file, print_event_info, "Update_rows");
+}
+
+bool
+Update_rows_compressed_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ char *new_buf;
+ ulong len;
+ bool is_malloc= false;
+ if(!row_log_event_uncompress(glob_description_event,
+ checksum_alg == BINLOG_CHECKSUM_ALG_CRC32,
+ temp_buf, UINT_MAX32, NULL, 0, &is_malloc, &new_buf, &len))
+ {
+ free_temp_buf();
+ register_temp_buf(new_buf, true);
+ if (Rows_log_event::print_helper(file, print_event_info,
+ "Update_compressed_rows"))
+ goto err;
+ }
+ else
+ {
+ if (my_b_printf(&print_event_info->head_cache,
+ "ERROR: uncompress update_compressed_rows failed\n"))
+ goto err;
+ }
+
+ return 0;
+err:
+ return 1;
+}
+
+
+bool Incident_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ Write_on_release_cache cache(&print_event_info->head_cache, file);
+
+ if (print_header(&cache, print_event_info, FALSE) ||
+ my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description()))
+ return 1;
+ return cache.flush_data();
+}
+
+
+/* Print for its unrecognized ignorable event */
+bool Ignorable_log_event::print(FILE *file,
+ PRINT_EVENT_INFO *print_event_info)
+{
+ if (print_event_info->short_form)
+ return 0;
+
+ if (print_header(&print_event_info->head_cache, print_event_info, FALSE) ||
+ my_b_printf(&print_event_info->head_cache, "\tIgnorable\n") ||
+ my_b_printf(&print_event_info->head_cache,
+ "# Ignorable event type %d (%s)\n", number, description) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->head_cache,
+ file))
+ return 1;
+ return 0;
+}
+
+
+/**
+ The default values for these variables should be values that are
+ *incorrect*, i.e., values that cannot occur in an event. This way,
+ they will always be printed for the first event.
+*/
+st_print_event_info::st_print_event_info()
+{
+ myf const flags = MYF(MY_WME | MY_NABP);
+ /*
+ Currently we only use static PRINT_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
+ bzero(time_zone_str, sizeof(time_zone_str));
+ delimiter[0]= ';';
+ delimiter[1]= 0;
+ flags2_inited= 0;
+ sql_mode_inited= 0;
+ row_events= 0;
+ sql_mode= 0;
+ auto_increment_increment= 0;
+ auto_increment_offset= 0;
+ charset_inited= 0;
+ lc_time_names_number= ~0;
+ charset_database_number= ILLEGAL_CHARSET_INFO_NUMBER;
+ thread_id= 0;
+ server_id= 0;
+ domain_id= 0;
+ thread_id_printed= false;
+ server_id_printed= false;
+ domain_id_printed= false;
+ allow_parallel= true;
+ allow_parallel_printed= false;
+ found_row_event= false;
+ print_row_count= false;
+ short_form= false;
+ skip_replication= 0;
+ printed_fd_event=FALSE;
+ file= 0;
+ base64_output_mode=BASE64_OUTPUT_UNSPEC;
+ open_cached_file(&head_cache, NULL, NULL, 0, flags);
+ open_cached_file(&body_cache, NULL, NULL, 0, flags);
+#ifdef WHEN_FLASHBACK_REVIEW_READY
+ open_cached_file(&review_sql_cache, NULL, NULL, 0, flags);
+#endif
+}
+
+
+bool copy_event_cache_to_string_and_reinit(IO_CACHE *cache, LEX_STRING *to)
+{
+ reinit_io_cache(cache, READ_CACHE, 0L, FALSE, FALSE);
+ if (cache->end_of_file > SIZE_T_MAX ||
+ !(to->str= (char*) my_malloc((to->length= (size_t)cache->end_of_file), MYF(0))))
+ {
+ perror("Out of memory: can't allocate memory in copy_event_cache_to_string_and_reinit().");
+ goto err;
+ }
+ if (my_b_read(cache, (uchar*) to->str, to->length))
+ {
+ my_free(to->str);
+ perror("Can't read data from IO_CACHE");
+ return true;
+ }
+ reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
+ return false;
+
+err:
+ to->str= 0;
+ to->length= 0;
+ return true;
+}
+
+
+bool
+Gtid_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
+{
+ Write_on_release_cache cache(&print_event_info->head_cache, file,
+ Write_on_release_cache::FLUSH_F, this);
+ char buf[21];
+ char buf2[21];
+
+ if (!print_event_info->short_form && !is_flashback)
+ {
+ print_header(&cache, print_event_info, FALSE);
+ longlong10_to_str(seq_no, buf, 10);
+ if (my_b_printf(&cache, "\tGTID %u-%u-%s", domain_id, server_id, buf))
+ goto err;
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ longlong10_to_str(commit_id, buf2, 10);
+ if (my_b_printf(&cache, " cid=%s", buf2))
+ goto err;
+ }
+ if (flags2 & FL_DDL)
+ if (my_b_write_string(&cache, " ddl"))
+ goto err;
+ if (flags2 & FL_TRANSACTIONAL)
+ if (my_b_write_string(&cache, " trans"))
+ goto err;
+ if (flags2 & FL_WAITED)
+ if (my_b_write_string(&cache, " waited"))
+ goto err;
+ if (my_b_printf(&cache, "\n"))
+ goto err;
+
+ if (!print_event_info->allow_parallel_printed ||
+ print_event_info->allow_parallel != !!(flags2 & FL_ALLOW_PARALLEL))
+ {
+ if (my_b_printf(&cache,
+ "/*!100101 SET @@session.skip_parallel_replication=%u*/%s\n",
+ !(flags2 & FL_ALLOW_PARALLEL),
+ print_event_info->delimiter))
+ goto err;
+ print_event_info->allow_parallel= !!(flags2 & FL_ALLOW_PARALLEL);
+ print_event_info->allow_parallel_printed= true;
+ }
+
+ if (!print_event_info->domain_id_printed ||
+ print_event_info->domain_id != domain_id)
+ {
+ if (my_b_printf(&cache,
+ "/*!100001 SET @@session.gtid_domain_id=%u*/%s\n",
+ domain_id, print_event_info->delimiter))
+ goto err;
+ print_event_info->domain_id= domain_id;
+ print_event_info->domain_id_printed= true;
+ }
+
+ if (!print_event_info->server_id_printed ||
+ print_event_info->server_id != server_id)
+ {
+ if (my_b_printf(&cache, "/*!100001 SET @@session.server_id=%u*/%s\n",
+ server_id, print_event_info->delimiter))
+ goto err;
+ print_event_info->server_id= server_id;
+ print_event_info->server_id_printed= true;
+ }
+
+ if (!is_flashback)
+ if (my_b_printf(&cache, "/*!100001 SET @@session.gtid_seq_no=%s*/%s\n",
+ buf, print_event_info->delimiter))
+ goto err;
+ }
+ if (!(flags2 & FL_STANDALONE))
+ if (my_b_printf(&cache, is_flashback ? "COMMIT\n%s\n" : "BEGIN\n%s\n", print_event_info->delimiter))
+ goto err;
+
+ return cache.flush_data();
+err:
+ return 1;
+}
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
new file mode 100644
index 00000000000..ba7fb9b8267
--- /dev/null
+++ b/sql/log_event_server.cc
@@ -0,0 +1,7903 @@
+/*
+ Copyright (c) 2000, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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-1335 USA */
+
+
+#include "mariadb.h"
+#include "sql_priv.h"
+
+#ifdef MYSQL_CLIENT
+#error MYSQL_CLIENT must not be defined here
+#endif
+
+#ifndef MYSQL_SERVER
+#error MYSQL_SERVER must be defined here
+#endif
+
+#include "unireg.h"
+#include "log_event.h"
+#include "sql_base.h" // close_thread_tables
+#include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE
+#include "sql_locale.h" // MY_LOCALE, my_locale_by_number, my_locale_en_US
+#include "key.h" // key_copy
+#include "lock.h" // mysql_unlock_tables
+#include "sql_parse.h" // mysql_test_parse_for_slave
+#include "tztime.h" // struct Time_zone
+#include "sql_load.h" // mysql_load
+#include "sql_db.h" // load_db_opt_by_name
+#include "slave.h"
+#include "rpl_rli.h"
+#include "rpl_mi.h"
+#include "rpl_filter.h"
+#include "rpl_record.h"
+#include "transaction.h"
+#include <my_dir.h>
+#include "sql_show.h" // append_identifier
+#include "debug_sync.h" // debug_sync
+#include <mysql/psi/mysql_statement.h>
+#include <strfunc.h>
+#include "compat56.h"
+#include "wsrep_mysqld.h"
+#include "sql_insert.h"
+
+#include <my_bitmap.h>
+#include "rpl_utility.h"
+#include "rpl_constants.h"
+#include "sql_digest.h"
+#include "zlib.h"
+
+
+#define log_cs &my_charset_latin1
+
+
+#if defined(HAVE_REPLICATION)
+static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD* thd);
+
+static const char *HA_ERR(int i)
+{
+ /*
+ This function should only be called in case of an error
+ was detected
+ */
+ DBUG_ASSERT(i != 0);
+ switch (i) {
+ case HA_ERR_KEY_NOT_FOUND: return "HA_ERR_KEY_NOT_FOUND";
+ case HA_ERR_FOUND_DUPP_KEY: return "HA_ERR_FOUND_DUPP_KEY";
+ case HA_ERR_RECORD_CHANGED: return "HA_ERR_RECORD_CHANGED";
+ case HA_ERR_WRONG_INDEX: return "HA_ERR_WRONG_INDEX";
+ case HA_ERR_CRASHED: return "HA_ERR_CRASHED";
+ case HA_ERR_WRONG_IN_RECORD: return "HA_ERR_WRONG_IN_RECORD";
+ case HA_ERR_OUT_OF_MEM: return "HA_ERR_OUT_OF_MEM";
+ case HA_ERR_NOT_A_TABLE: return "HA_ERR_NOT_A_TABLE";
+ case HA_ERR_WRONG_COMMAND: return "HA_ERR_WRONG_COMMAND";
+ case HA_ERR_OLD_FILE: return "HA_ERR_OLD_FILE";
+ case HA_ERR_NO_ACTIVE_RECORD: return "HA_ERR_NO_ACTIVE_RECORD";
+ case HA_ERR_RECORD_DELETED: return "HA_ERR_RECORD_DELETED";
+ case HA_ERR_RECORD_FILE_FULL: return "HA_ERR_RECORD_FILE_FULL";
+ case HA_ERR_INDEX_FILE_FULL: return "HA_ERR_INDEX_FILE_FULL";
+ case HA_ERR_END_OF_FILE: return "HA_ERR_END_OF_FILE";
+ case HA_ERR_UNSUPPORTED: return "HA_ERR_UNSUPPORTED";
+ case HA_ERR_TO_BIG_ROW: return "HA_ERR_TO_BIG_ROW";
+ case HA_WRONG_CREATE_OPTION: return "HA_WRONG_CREATE_OPTION";
+ case HA_ERR_FOUND_DUPP_UNIQUE: return "HA_ERR_FOUND_DUPP_UNIQUE";
+ case HA_ERR_UNKNOWN_CHARSET: return "HA_ERR_UNKNOWN_CHARSET";
+ case HA_ERR_WRONG_MRG_TABLE_DEF: return "HA_ERR_WRONG_MRG_TABLE_DEF";
+ case HA_ERR_CRASHED_ON_REPAIR: return "HA_ERR_CRASHED_ON_REPAIR";
+ case HA_ERR_CRASHED_ON_USAGE: return "HA_ERR_CRASHED_ON_USAGE";
+ case HA_ERR_LOCK_WAIT_TIMEOUT: return "HA_ERR_LOCK_WAIT_TIMEOUT";
+ case HA_ERR_LOCK_TABLE_FULL: return "HA_ERR_LOCK_TABLE_FULL";
+ case HA_ERR_READ_ONLY_TRANSACTION: return "HA_ERR_READ_ONLY_TRANSACTION";
+ case HA_ERR_LOCK_DEADLOCK: return "HA_ERR_LOCK_DEADLOCK";
+ case HA_ERR_CANNOT_ADD_FOREIGN: return "HA_ERR_CANNOT_ADD_FOREIGN";
+ case HA_ERR_NO_REFERENCED_ROW: return "HA_ERR_NO_REFERENCED_ROW";
+ case HA_ERR_ROW_IS_REFERENCED: return "HA_ERR_ROW_IS_REFERENCED";
+ case HA_ERR_NO_SAVEPOINT: return "HA_ERR_NO_SAVEPOINT";
+ case HA_ERR_NON_UNIQUE_BLOCK_SIZE: return "HA_ERR_NON_UNIQUE_BLOCK_SIZE";
+ case HA_ERR_NO_SUCH_TABLE: return "HA_ERR_NO_SUCH_TABLE";
+ case HA_ERR_TABLE_EXIST: return "HA_ERR_TABLE_EXIST";
+ case HA_ERR_NO_CONNECTION: return "HA_ERR_NO_CONNECTION";
+ case HA_ERR_NULL_IN_SPATIAL: return "HA_ERR_NULL_IN_SPATIAL";
+ case HA_ERR_TABLE_DEF_CHANGED: return "HA_ERR_TABLE_DEF_CHANGED";
+ case HA_ERR_NO_PARTITION_FOUND: return "HA_ERR_NO_PARTITION_FOUND";
+ case HA_ERR_RBR_LOGGING_FAILED: return "HA_ERR_RBR_LOGGING_FAILED";
+ case HA_ERR_DROP_INDEX_FK: return "HA_ERR_DROP_INDEX_FK";
+ case HA_ERR_FOREIGN_DUPLICATE_KEY: return "HA_ERR_FOREIGN_DUPLICATE_KEY";
+ case HA_ERR_TABLE_NEEDS_UPGRADE: return "HA_ERR_TABLE_NEEDS_UPGRADE";
+ case HA_ERR_TABLE_READONLY: return "HA_ERR_TABLE_READONLY";
+ case HA_ERR_AUTOINC_READ_FAILED: return "HA_ERR_AUTOINC_READ_FAILED";
+ case HA_ERR_AUTOINC_ERANGE: return "HA_ERR_AUTOINC_ERANGE";
+ case HA_ERR_GENERIC: return "HA_ERR_GENERIC";
+ case HA_ERR_RECORD_IS_THE_SAME: return "HA_ERR_RECORD_IS_THE_SAME";
+ case HA_ERR_LOGGING_IMPOSSIBLE: return "HA_ERR_LOGGING_IMPOSSIBLE";
+ case HA_ERR_CORRUPT_EVENT: return "HA_ERR_CORRUPT_EVENT";
+ case HA_ERR_ROWS_EVENT_APPLY : return "HA_ERR_ROWS_EVENT_APPLY";
+ }
+ return "No Error!";
+}
+
+
+/*
+ Return true if an error caught during event execution is a temporary error
+ that will cause automatic retry of the event group during parallel
+ replication, false otherwise.
+
+ In parallel replication, conflicting transactions can occasionally cause
+ deadlocks; such errors are handled automatically by rolling back re-trying
+ the transactions, so should not pollute the error log.
+*/
+static bool
+is_parallel_retry_error(rpl_group_info *rgi, int err)
+{
+ if (!rgi->is_parallel_exec)
+ return false;
+ if (rgi->speculation == rpl_group_info::SPECULATE_OPTIMISTIC)
+ return true;
+ if (rgi->killed_for_retry &&
+ (err == ER_QUERY_INTERRUPTED || err == ER_CONNECTION_KILLED))
+ return true;
+ return has_temporary_error(rgi->thd);
+}
+
+
+/**
+ Error reporting facility for Rows_log_event::do_apply_event
+
+ @param level error, warning or info
+ @param ha_error HA_ERR_ code
+ @param rli pointer to the active Relay_log_info instance
+ @param thd pointer to the slave thread's thd
+ @param table pointer to the event's table object
+ @param type the type of the event
+ @param log_name the master binlog file name
+ @param pos the master binlog file pos (the next after the event)
+
+*/
+static void inline slave_rows_error_report(enum loglevel level, int ha_error,
+ rpl_group_info *rgi, THD *thd,
+ TABLE *table, const char * type,
+ const char *log_name, my_off_t pos)
+{
+ const char *handler_error= (ha_error ? HA_ERR(ha_error) : NULL);
+ char buff[MAX_SLAVE_ERRMSG], *slider;
+ const char *buff_end= buff + sizeof(buff);
+ size_t len;
+ Diagnostics_area::Sql_condition_iterator it=
+ thd->get_stmt_da()->sql_conditions();
+ Relay_log_info const *rli= rgi->rli;
+ const Sql_condition *err;
+ buff[0]= 0;
+ int errcode= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
+
+ /*
+ In parallel replication, deadlocks or other temporary errors can happen
+ occasionally in normal operation, they will be handled correctly and
+ automatically by re-trying the transactions. So do not pollute the error
+ log with messages about them.
+ */
+ if (is_parallel_retry_error(rgi, errcode))
+ return;
+
+ for (err= it++, slider= buff; err && slider < buff_end - 1;
+ slider += len, err= it++)
+ {
+ len= my_snprintf(slider, buff_end - slider,
+ " %s, Error_code: %d;", err->get_message_text(),
+ err->get_sql_errno());
+ }
+
+ if (ha_error != 0)
+ rli->report(level, errcode, rgi->gtid_info(),
+ "Could not execute %s event on table %s.%s;"
+ "%s handler error %s; "
+ "the event's master log %s, end_log_pos %llu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, handler_error == NULL ? "<unknown>" : handler_error,
+ log_name, pos);
+ else
+ rli->report(level, errcode, rgi->gtid_info(),
+ "Could not execute %s event on table %s.%s;"
+ "%s the event's master log %s, end_log_pos %llu",
+ type, table->s->db.str, table->s->table_name.str,
+ buff, log_name, pos);
+}
+#endif
+
+#if defined(HAVE_REPLICATION)
+static void set_thd_db(THD *thd, Rpl_filter *rpl_filter,
+ const char *db, uint32 db_len)
+{
+ char lcase_db_buf[NAME_LEN +1];
+ LEX_CSTRING new_db;
+ new_db.length= db_len;
+ if (lower_case_table_names == 1)
+ {
+ strmov(lcase_db_buf, db);
+ my_casedn_str(system_charset_info, lcase_db_buf);
+ new_db.str= lcase_db_buf;
+ }
+ else
+ new_db.str= db;
+ /* TODO WARNING this makes rewrite_db respect lower_case_table_names values
+ * for more info look MDEV-17446 */
+ new_db.str= rpl_filter->get_rewrite_db(new_db.str, &new_db.length);
+ thd->set_db(&new_db);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+
+inline int idempotent_error_code(int err_code)
+{
+ int ret= 0;
+
+ switch (err_code)
+ {
+ case 0:
+ ret= 1;
+ break;
+ /*
+ The following list of "idempotent" errors
+ means that an error from the list might happen
+ because of idempotent (more than once)
+ applying of a binlog file.
+ Notice, that binlog has a ddl operation its
+ second applying may cause
+
+ case HA_ERR_TABLE_DEF_CHANGED:
+ case HA_ERR_CANNOT_ADD_FOREIGN:
+
+ which are not included into to the list.
+
+ Note that HA_ERR_RECORD_DELETED is not in the list since
+ do_exec_row() should not return that error code.
+ */
+ case HA_ERR_RECORD_CHANGED:
+ case HA_ERR_KEY_NOT_FOUND:
+ case HA_ERR_END_OF_FILE:
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ case HA_ERR_FOREIGN_DUPLICATE_KEY:
+ case HA_ERR_NO_REFERENCED_ROW:
+ case HA_ERR_ROW_IS_REFERENCED:
+ ret= 1;
+ break;
+ default:
+ ret= 0;
+ break;
+ }
+ return (ret);
+}
+
+/**
+ Ignore error code specified on command line.
+*/
+
+inline int ignored_error_code(int err_code)
+{
+ if (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code))
+ {
+ statistic_increment(slave_skipped_errors, LOCK_status);
+ return 1;
+ }
+ return err_code == ER_SLAVE_IGNORED_TABLE;
+}
+
+/*
+ This function converts an engine's error to a server error.
+
+ If the thread does not have an error already reported, it tries to
+ define it by calling the engine's method print_error. However, if a
+ mapping is not found, it uses the ER_UNKNOWN_ERROR and prints out a
+ warning message.
+*/
+int convert_handler_error(int error, THD* thd, TABLE *table)
+{
+ uint actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
+ 0);
+
+ if (actual_error == 0)
+ {
+ table->file->print_error(error, MYF(0));
+ actual_error= (thd->is_error() ? thd->get_stmt_da()->sql_errno() :
+ ER_UNKNOWN_ERROR);
+ if (actual_error == ER_UNKNOWN_ERROR)
+ if (global_system_variables.log_warnings)
+ sql_print_warning("Unknown error detected %d in handler", error);
+ }
+
+ return (actual_error);
+}
+
+inline bool concurrency_error_code(int error)
+{
+ switch (error)
+ {
+ case ER_LOCK_WAIT_TIMEOUT:
+ case ER_LOCK_DEADLOCK:
+ case ER_XA_RBDEADLOCK:
+ return TRUE;
+ default:
+ return (FALSE);
+ }
+}
+
+inline bool unexpected_error_code(int unexpected_error)
+{
+ switch (unexpected_error)
+ {
+ case ER_NET_READ_ERROR:
+ case ER_NET_ERROR_ON_WRITE:
+ case ER_QUERY_INTERRUPTED:
+ case ER_STATEMENT_TIMEOUT:
+ case ER_CONNECTION_KILLED:
+ case ER_SERVER_SHUTDOWN:
+ case ER_NEW_ABORTING_CONNECTION:
+ return(TRUE);
+ default:
+ return(FALSE);
+ }
+}
+
+/*
+ pretty_print_str()
+*/
+
+static void
+pretty_print_str(String *packet, const char *str, int len)
+{
+ const char *end= str + len;
+ packet->append(STRING_WITH_LEN("'"));
+ while (str < end)
+ {
+ char c;
+ switch ((c=*str++)) {
+ case '\n': packet->append(STRING_WITH_LEN("\\n")); break;
+ case '\r': packet->append(STRING_WITH_LEN("\\r")); break;
+ case '\\': packet->append(STRING_WITH_LEN("\\\\")); break;
+ case '\b': packet->append(STRING_WITH_LEN("\\b")); break;
+ case '\t': packet->append(STRING_WITH_LEN("\\t")); break;
+ case '\'': packet->append(STRING_WITH_LEN("\\'")); break;
+ case 0 : packet->append(STRING_WITH_LEN("\\0")); break;
+ default:
+ packet->append(&c, 1);
+ break;
+ }
+ }
+ packet->append(STRING_WITH_LEN("'"));
+}
+#endif /* HAVE_REPLICATION */
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Create a prefix for the temporary files that is to be used for
+ load data file name for this master
+
+ @param name Store prefix of name here
+ @param connection_name Connection name
+
+ @return pointer to end of name
+
+ @description
+ We assume that FN_REFLEN is big enough to hold
+ MAX_CONNECTION_NAME * MAX_FILENAME_MBWIDTH characters + 2 numbers +
+ a short extension.
+
+ The resulting file name has the following parts, each separated with a '-'
+ - PREFIX_SQL_LOAD (SQL_LOAD-)
+ - If a connection name is given (multi-master setup):
+ - Add an extra '-' to mark that this is a multi-master file
+ - connection name in lower case, converted to safe file characters.
+ (see create_logfile_name_with_suffix()).
+ - server_id
+ - A last '-' (after server_id).
+*/
+
+static char *load_data_tmp_prefix(char *name,
+ LEX_CSTRING *connection_name)
+{
+ name= strmov(name, PREFIX_SQL_LOAD);
+ if (connection_name->length)
+ {
+ uint buf_length;
+ uint errors;
+ /* Add marker that this is a multi-master-file */
+ *name++='-';
+ /* Convert connection_name to a safe filename */
+ buf_length= strconvert(system_charset_info, connection_name->str, FN_REFLEN,
+ &my_charset_filename, name, FN_REFLEN, &errors);
+ name+= buf_length;
+ *name++= '-';
+ }
+ name= int10_to_str(global_system_variables.server_id, name, 10);
+ *name++ = '-';
+ *name= '\0'; // For testing prefixes
+ return name;
+}
+
+
+/**
+ Creates a temporary name for LOAD DATA INFILE
+
+ @param buf Store new filename here
+ @param file_id File_id (part of file name)
+ @param event_server_id Event_id (part of file name)
+ @param ext Extension for file name
+
+ @return
+ Pointer to start of extension
+*/
+
+static char *slave_load_file_stem(char *buf, uint file_id,
+ int event_server_id, const char *ext,
+ LEX_CSTRING *connection_name)
+{
+ char *res;
+ res= buf+ unpack_dirname(buf, slave_load_tmpdir);
+ to_unix_path(buf);
+ buf= load_data_tmp_prefix(res, connection_name);
+ buf= int10_to_str(event_server_id, buf, 10);
+ *buf++ = '-';
+ res= int10_to_str(file_id, buf, 10);
+ strmov(res, ext); // Add extension last
+ return res; // Pointer to extension
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Delete all temporary files used for SQL_LOAD.
+*/
+
+static void cleanup_load_tmpdir(LEX_CSTRING *connection_name)
+{
+ MY_DIR *dirp;
+ FILEINFO *file;
+ uint i;
+ char dir[FN_REFLEN], fname[FN_REFLEN];
+ char prefbuf[31 + MAX_CONNECTION_NAME* MAX_FILENAME_MBWIDTH + 1];
+ DBUG_ENTER("cleanup_load_tmpdir");
+
+ unpack_dirname(dir, slave_load_tmpdir);
+ if (!(dirp=my_dir(dir, MYF(MY_WME))))
+ return;
+
+ /*
+ When we are deleting temporary files, we should only remove
+ the files associated with the server id of our server.
+ We don't use event_server_id here because since we've disabled
+ direct binlogging of Create_file/Append_file/Exec_load events
+ we cannot meet Start_log event in the middle of events from one
+ LOAD DATA.
+ */
+
+ load_data_tmp_prefix(prefbuf, connection_name);
+ DBUG_PRINT("enter", ("dir: '%s' prefix: '%s'", dir, prefbuf));
+
+ for (i=0 ; i < (uint)dirp->number_of_files; i++)
+ {
+ file=dirp->dir_entry+i;
+ if (is_prefix(file->name, prefbuf))
+ {
+ fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
+ mysql_file_delete(key_file_misc, fname, MYF(0));
+ }
+ }
+
+ my_dirend(dirp);
+ DBUG_VOID_RETURN;
+}
+#endif
+
+
+/**
+ Append a version of the 'str' string suitable for use in a query to
+ the 'to' string. To generate a correct escaping, the character set
+ information in 'csinfo' is used.
+*/
+
+int append_query_string(CHARSET_INFO *csinfo, String *to,
+ const char *str, size_t len, bool no_backslash)
+{
+ char *beg, *ptr;
+ uint32 const orig_len= to->length();
+ if (to->reserve(orig_len + len * 2 + 4))
+ return 1;
+
+ beg= (char*) to->ptr() + to->length();
+ ptr= beg;
+ if (csinfo->escape_with_backslash_is_dangerous)
+ ptr= str_to_hex(ptr, str, len);
+ else
+ {
+ *ptr++= '\'';
+ if (!no_backslash)
+ {
+ ptr+= escape_string_for_mysql(csinfo, ptr, 0, str, len);
+ }
+ else
+ {
+ const char *frm_str= str;
+
+ for (; frm_str < (str + len); frm_str++)
+ {
+ /* Using '' way to represent "'" */
+ if (*frm_str == '\'')
+ *ptr++= *frm_str;
+
+ *ptr++= *frm_str;
+ }
+ }
+
+ *ptr++= '\'';
+ }
+ to->length((uint32)(orig_len + ptr - beg));
+ return 0;
+}
+
+
+/**************************************************************************
+ Log_event methods (= the parent class of all events)
+**************************************************************************/
+
+Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
+ :log_pos(0), temp_buf(0), exec_time(0), thd(thd_arg),
+ checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
+{
+ server_id= thd->variables.server_id;
+ when= thd->start_time;
+ when_sec_part=thd->start_time_sec_part;
+
+ if (using_trans)
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+ flags= flags_arg |
+ (thd->variables.option_bits & OPTION_SKIP_REPLICATION ?
+ LOG_EVENT_SKIP_REPLICATION_F : 0);
+}
+
+/**
+ This minimal constructor is for when you are not even sure that there
+ is a valid THD. For example in the server when we are shutting down or
+ flushing logs after receiving a SIGHUP (then we must write a Rotate to
+ the binlog but we have no THD, so we need this minimal constructor).
+*/
+
+Log_event::Log_event()
+ :temp_buf(0), exec_time(0), flags(0), cache_type(EVENT_INVALID_CACHE),
+ thd(0), checksum_alg(BINLOG_CHECKSUM_ALG_UNDEF)
+{
+ server_id= global_system_variables.server_id;
+ /*
+ We can't call my_time() here as this would cause a call before
+ my_init() is called
+ */
+ when= 0;
+ when_sec_part=0;
+ log_pos= 0;
+}
+
+
+
+#ifdef HAVE_REPLICATION
+
+int Log_event::do_update_pos(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Log_event::do_update_pos");
+
+ DBUG_ASSERT(!rli->belongs_to_client());
+ /*
+ rli is null when (as far as I (Guilhem) know) the caller is
+ Load_log_event::do_apply_event *and* that one is called from
+ Execute_load_log_event::do_apply_event. In this case, we don't
+ do anything here ; Execute_load_log_event::do_apply_event will
+ call Log_event::do_apply_event again later with the proper rli.
+ Strictly speaking, if we were sure that rli is null only in the
+ case discussed above, 'if (rli)' is useless here. But as we are
+ not 100% sure, keep it for now.
+
+ Matz: I don't think we will need this check with this refactoring.
+ */
+ if (rli)
+ {
+ /*
+ In parallel execution, delay position update for the events that are
+ not part of event groups (format description, rotate, and such) until
+ the actual event execution reaches that point.
+ */
+ if (!rgi->is_parallel_exec || is_group_event(get_type_code()))
+ rli->stmt_done(log_pos, thd, rgi);
+ }
+ DBUG_RETURN(0); // Cannot fail currently
+}
+
+
+Log_event::enum_skip_reason
+Log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_PRINT("info", ("ev->server_id: %lu, ::server_id: %lu,"
+ " rli->replicate_same_server_id: %d,"
+ " rli->slave_skip_counter: %llu",
+ (ulong) server_id,
+ (ulong) global_system_variables.server_id,
+ rli->replicate_same_server_id,
+ rli->slave_skip_counter));
+ if ((server_id == global_system_variables.server_id &&
+ !rli->replicate_same_server_id) ||
+ (rli->slave_skip_counter == 1 && rli->is_in_group()) ||
+ (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
+ return EVENT_SKIP_IGNORE;
+ if (rli->slave_skip_counter > 0)
+ return EVENT_SKIP_COUNT;
+ return EVENT_SKIP_NOT;
+}
+
+
+/*
+ Log_event::pack_info()
+*/
+
+void Log_event::pack_info(Protocol *protocol)
+{
+ protocol->store("", &my_charset_bin);
+}
+
+
+/**
+ Only called by SHOW BINLOG EVENTS
+*/
+int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
+{
+ const char *p= strrchr(log_name, FN_LIBCHAR);
+ const char *event_type;
+ if (p)
+ log_name = p + 1;
+
+ protocol->prepare_for_resend();
+ protocol->store(log_name, &my_charset_bin);
+ protocol->store((ulonglong) pos);
+ event_type = get_type_str();
+ protocol->store(event_type, strlen(event_type), &my_charset_bin);
+ protocol->store((uint32) server_id);
+ protocol->store((ulonglong) log_pos);
+ pack_info(protocol);
+ return protocol->write();
+}
+#endif /* HAVE_REPLICATION */
+
+
+/**
+ init_show_field_list() prepares the column names and types for the
+ output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
+ EVENTS.
+*/
+
+void Log_event::init_show_field_list(THD *thd, List<Item>* field_list)
+{
+ MEM_ROOT *mem_root= thd->mem_root;
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Log_name", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Pos",
+ MY_INT64_NUM_DECIMAL_DIGITS,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_empty_string(thd, "Event_type", 20),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "Server_id", 10,
+ MYSQL_TYPE_LONG),
+ mem_root);
+ field_list->push_back(new (mem_root)
+ Item_return_int(thd, "End_log_pos",
+ MY_INT64_NUM_DECIMAL_DIGITS,
+ MYSQL_TYPE_LONGLONG),
+ mem_root);
+ field_list->push_back(new (mem_root) Item_empty_string(thd, "Info", 20),
+ mem_root);
+}
+
+/**
+ A decider of whether to trigger checksum computation or not.
+ To be invoked in Log_event::write() stack.
+ The decision is positive
+
+ S,M) if it's been marked for checksumming with @c checksum_alg
+
+ M) otherwise, if @@global.binlog_checksum is not NONE and the event is
+ directly written to the binlog file.
+ The to-be-cached event decides at @c write_cache() time.
+
+ Otherwise the decision is negative.
+
+ @note A side effect of the method is altering Log_event::checksum_alg
+ it the latter was undefined at calling.
+
+ @return true (positive) or false (negative)
+*/
+my_bool Log_event::need_checksum()
+{
+ DBUG_ENTER("Log_event::need_checksum");
+ my_bool ret;
+ /*
+ few callers of Log_event::write
+ (incl FD::write, FD constructing code on the slave side, Rotate relay log
+ and Stop event)
+ provides their checksum alg preference through Log_event::checksum_alg.
+ */
+ if (checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF)
+ ret= checksum_alg != BINLOG_CHECKSUM_ALG_OFF;
+ else
+ {
+ ret= binlog_checksum_options && cache_type == Log_event::EVENT_NO_CACHE;
+ checksum_alg= ret ? (enum_binlog_checksum_alg)binlog_checksum_options
+ : BINLOG_CHECKSUM_ALG_OFF;
+ }
+ /*
+ FD calls the methods before data_written has been calculated.
+ The following invariant claims if the current is not the first
+ call (and therefore data_written is not zero) then `ret' must be
+ TRUE. It may not be null because FD is always checksummed.
+ */
+
+ DBUG_ASSERT(get_type_code() != FORMAT_DESCRIPTION_EVENT || ret ||
+ data_written == 0);
+
+ DBUG_ASSERT(!ret ||
+ ((checksum_alg == binlog_checksum_options ||
+ /*
+ Stop event closes the relay-log and its checksum alg
+ preference is set by the caller can be different
+ from the server's binlog_checksum_options.
+ */
+ get_type_code() == STOP_EVENT ||
+ /*
+ Rotate:s can be checksummed regardless of the server's
+ binlog_checksum_options. That applies to both
+ the local RL's Rotate and the master's Rotate
+ which IO thread instantiates via queue_binlog_ver_3_event.
+ */
+ get_type_code() == ROTATE_EVENT ||
+ get_type_code() == START_ENCRYPTION_EVENT ||
+ /* FD is always checksummed */
+ get_type_code() == FORMAT_DESCRIPTION_EVENT) &&
+ checksum_alg != BINLOG_CHECKSUM_ALG_OFF));
+
+ DBUG_ASSERT(checksum_alg != BINLOG_CHECKSUM_ALG_UNDEF);
+
+ DBUG_ASSERT(((get_type_code() != ROTATE_EVENT &&
+ get_type_code() != STOP_EVENT) ||
+ get_type_code() != FORMAT_DESCRIPTION_EVENT) ||
+ cache_type == Log_event::EVENT_NO_CACHE);
+
+ DBUG_RETURN(ret);
+}
+
+int Log_event_writer::write_internal(const uchar *pos, size_t len)
+{
+ if (my_b_safe_write(file, pos, len))
+ return 1;
+ bytes_written+= len;
+ return 0;
+}
+
+/*
+ as soon as encryption produces the first output block, write event_len
+ where it should be in a valid event header
+*/
+int Log_event_writer::maybe_write_event_len(uchar *pos, size_t len)
+{
+ if (len && event_len)
+ {
+ DBUG_ASSERT(len >= EVENT_LEN_OFFSET);
+ if (write_internal(pos + EVENT_LEN_OFFSET - 4, 4))
+ return 1;
+ int4store(pos + EVENT_LEN_OFFSET - 4, event_len);
+ event_len= 0;
+ }
+ return 0;
+}
+
+int Log_event_writer::encrypt_and_write(const uchar *pos, size_t len)
+{
+ uchar *dst= 0;
+ size_t dstsize= 0;
+
+ if (ctx)
+ {
+ dstsize= encryption_encrypted_length((uint)len, ENCRYPTION_KEY_SYSTEM_DATA,
+ crypto->key_version);
+ if (!(dst= (uchar*)my_safe_alloca(dstsize)))
+ return 1;
+
+ uint dstlen;
+ if (len == 0)
+ dstlen= 0;
+ else if (encryption_ctx_update(ctx, pos, (uint)len, dst, &dstlen))
+ goto err;
+
+ if (maybe_write_event_len(dst, dstlen))
+ return 1;
+ pos= dst;
+ len= dstlen;
+ }
+ if (write_internal(pos, len))
+ goto err;
+
+ my_safe_afree(dst, dstsize);
+ return 0;
+err:
+ my_safe_afree(dst, dstsize);
+ return 1;
+}
+
+int Log_event_writer::write_header(uchar *pos, size_t len)
+{
+ DBUG_ENTER("Log_event_writer::write_header");
+ /*
+ recording checksum of FD event computed with dropped
+ possibly active LOG_EVENT_BINLOG_IN_USE_F flag.
+ Similar step at verication: the active flag is dropped before
+ checksum computing.
+ */
+ if (checksum_len)
+ {
+ uchar save=pos[FLAGS_OFFSET];
+ pos[FLAGS_OFFSET]&= ~LOG_EVENT_BINLOG_IN_USE_F;
+ crc= my_checksum(0, pos, len);
+ pos[FLAGS_OFFSET]= save;
+ }
+
+ if (ctx)
+ {
+ uchar iv[BINLOG_IV_LENGTH];
+ crypto->set_iv(iv, (uint32)my_b_safe_tell(file));
+ if (encryption_ctx_init(ctx, crypto->key, crypto->key_length,
+ iv, sizeof(iv), ENCRYPTION_FLAG_ENCRYPT | ENCRYPTION_FLAG_NOPAD,
+ ENCRYPTION_KEY_SYSTEM_DATA, crypto->key_version))
+ DBUG_RETURN(1);
+
+ DBUG_ASSERT(len >= LOG_EVENT_HEADER_LEN);
+ event_len= uint4korr(pos + EVENT_LEN_OFFSET);
+ DBUG_ASSERT(event_len >= len);
+ memcpy(pos + EVENT_LEN_OFFSET, pos, 4);
+ pos+= 4;
+ len-= 4;
+ }
+ DBUG_RETURN(encrypt_and_write(pos, len));
+}
+
+int Log_event_writer::write_data(const uchar *pos, size_t len)
+{
+ DBUG_ENTER("Log_event_writer::write_data");
+ if (checksum_len)
+ crc= my_checksum(crc, pos, len);
+
+ DBUG_RETURN(encrypt_and_write(pos, len));
+}
+
+int Log_event_writer::write_footer()
+{
+ DBUG_ENTER("Log_event_writer::write_footer");
+ if (checksum_len)
+ {
+ uchar checksum_buf[BINLOG_CHECKSUM_LEN];
+ int4store(checksum_buf, crc);
+ if (encrypt_and_write(checksum_buf, BINLOG_CHECKSUM_LEN))
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ if (ctx)
+ {
+ uint dstlen;
+ uchar dst[MY_AES_BLOCK_SIZE*2];
+ if (encryption_ctx_finish(ctx, dst, &dstlen))
+ DBUG_RETURN(1);
+ if (maybe_write_event_len(dst, dstlen) || write_internal(dst, dstlen))
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ DBUG_RETURN(0);
+}
+
+/*
+ Log_event::write_header()
+*/
+
+bool Log_event::write_header(size_t event_data_length)
+{
+ uchar header[LOG_EVENT_HEADER_LEN];
+ ulong now;
+ DBUG_ENTER("Log_event::write_header");
+ DBUG_PRINT("enter", ("filepos: %lld length: %zu type: %d",
+ (longlong) writer->pos(), event_data_length,
+ (int) get_type_code()));
+
+ writer->checksum_len= need_checksum() ? BINLOG_CHECKSUM_LEN : 0;
+
+ /* Store number of bytes that will be written by this event */
+ data_written= event_data_length + sizeof(header) + writer->checksum_len;
+
+ /*
+ log_pos != 0 if this is relay-log event. In this case we should not
+ change the position
+ */
+
+ if (is_artificial_event())
+ {
+ /*
+ Artificial events are automatically generated and do not exist
+ in master's binary log, so log_pos should be set to 0.
+ */
+ log_pos= 0;
+ }
+ else if (!log_pos)
+ {
+ /*
+ Calculate the position of where the next event will start
+ (end of this event, that is).
+ */
+
+ log_pos= writer->pos() + data_written;
+
+ DBUG_EXECUTE_IF("dbug_master_binlog_over_2GB", log_pos += (1ULL <<31););
+ }
+
+ now= get_time(); // Query start time
+
+ /*
+ Header will be of size LOG_EVENT_HEADER_LEN for all events, except for
+ FORMAT_DESCRIPTION_EVENT and ROTATE_EVENT, where it will be
+ LOG_EVENT_MINIMAL_HEADER_LEN (remember these 2 have a frozen header,
+ because we read them before knowing the format).
+ */
+
+ int4store(header, now); // timestamp
+ header[EVENT_TYPE_OFFSET]= get_type_code();
+ int4store(header+ SERVER_ID_OFFSET, server_id);
+ int4store(header+ EVENT_LEN_OFFSET, data_written);
+ int4store(header+ LOG_POS_OFFSET, log_pos);
+ int2store(header + FLAGS_OFFSET, flags);
+
+ bool ret= writer->write_header(header, sizeof(header));
+ DBUG_RETURN(ret);
+}
+
+
+
+#if defined(HAVE_REPLICATION)
+inline Log_event::enum_skip_reason
+Log_event::continue_group(rpl_group_info *rgi)
+{
+ if (rgi->rli->slave_skip_counter == 1)
+ return Log_event::EVENT_SKIP_IGNORE;
+ return Log_event::do_shall_skip(rgi);
+}
+#endif
+
+/**************************************************************************
+ Query_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ This (which is used only for SHOW BINLOG EVENTS) could be updated to
+ print SET @@session_var=. But this is not urgent, as SHOW BINLOG EVENTS is
+ only an information, it does not produce suitable queries to replay (for
+ example it does not print LOAD DATA INFILE).
+ @todo
+ show the catalog ??
+*/
+
+void Query_log_event::pack_info(Protocol *protocol)
+{
+ // TODO: show the catalog ??
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.real_alloc(9 + db_len + q_len);
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
+ && db && db_len)
+ {
+ buf.append(STRING_WITH_LEN("use "));
+ append_identifier(protocol->thd, &buf, db, db_len);
+ buf.append(STRING_WITH_LEN("; "));
+ }
+ if (query && q_len)
+ buf.append(query, q_len);
+ protocol->store(&buf);
+}
+#endif
+
+
+/**
+ Utility function for the next method (Query_log_event::write()) .
+*/
+static void store_str_with_code_and_len(uchar **dst, const char *src,
+ uint len, uint code)
+{
+ /*
+ only 1 byte to store the length of catalog, so it should not
+ surpass 255
+ */
+ DBUG_ASSERT(len <= 255);
+ DBUG_ASSERT(src);
+ *((*dst)++)= (uchar) code;
+ *((*dst)++)= (uchar) len;
+ bmove(*dst, src, len);
+ (*dst)+= len;
+}
+
+
+/**
+ Query_log_event::write().
+
+ @note
+ In this event we have to modify the header to have the correct
+ EVENT_LEN_OFFSET as we don't yet know how many status variables we
+ will print!
+*/
+
+bool Query_log_event::write()
+{
+ uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
+ uchar *start, *start_of_status;
+ ulong event_length;
+
+ if (!query)
+ return 1; // Something wrong with event
+
+ /*
+ We want to store the thread id:
+ (- as an information for the user when he reads the binlog)
+ - if the query uses temporary table: for the slave SQL thread to know to
+ which master connection the temp table belongs.
+ Now imagine we (write()) are called by the slave SQL thread (we are
+ logging a query executed by this thread; the slave runs with
+ --log-slave-updates). Then this query will be logged with
+ thread_id=the_thread_id_of_the_SQL_thread. Imagine that 2 temp tables of
+ the same name were created simultaneously on the master (in the master
+ binlog you have
+ CREATE TEMPORARY TABLE t; (thread 1)
+ CREATE TEMPORARY TABLE t; (thread 2)
+ ...)
+ then in the slave's binlog there will be
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ CREATE TEMPORARY TABLE t; (thread_id_of_the_slave_SQL_thread)
+ which is bad (same thread id!).
+
+ To avoid this, we log the thread's thread id EXCEPT for the SQL
+ slave thread for which we log the original (master's) thread id.
+ Now this moves the bug: what happens if the thread id on the
+ master was 10 and when the slave replicates the query, a
+ connection number 10 is opened by a normal client on the slave,
+ and updates a temp table of the same name? We get a problem
+ again. To avoid this, in the handling of temp tables (sql_base.cc)
+ we use thread_id AND server_id. TODO when this is merged into
+ 4.1: in 4.1, slave_proxy_id has been renamed to pseudo_thread_id
+ and is a session variable: that's to make mysqlbinlog work with
+ temp tables. We probably need to introduce
+
+ SET PSEUDO_SERVER_ID
+ for mysqlbinlog in 4.1. mysqlbinlog would print:
+ SET PSEUDO_SERVER_ID=
+ SET PSEUDO_THREAD_ID=
+ for each query using temp tables.
+ */
+ int4store(buf + Q_THREAD_ID_OFFSET, slave_proxy_id);
+ int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
+ buf[Q_DB_LEN_OFFSET] = (char) db_len;
+ int2store(buf + Q_ERR_CODE_OFFSET, error_code);
+
+ /*
+ You MUST always write status vars in increasing order of code. This
+ guarantees that a slightly older slave will be able to parse those he
+ knows.
+ */
+ start_of_status= start= buf+QUERY_HEADER_LEN;
+ if (flags2_inited)
+ {
+ *start++= Q_FLAGS2_CODE;
+ int4store(start, flags2);
+ start+= 4;
+ }
+ if (sql_mode_inited)
+ {
+ *start++= Q_SQL_MODE_CODE;
+ int8store(start, (ulonglong)sql_mode);
+ start+= 8;
+ }
+ if (catalog_len) // i.e. this var is inited (false for 4.0 events)
+ {
+ store_str_with_code_and_len(&start,
+ catalog, catalog_len, Q_CATALOG_NZ_CODE);
+ /*
+ In 5.0.x where x<4 masters we used to store the end zero here. This was
+ a waste of one byte so we don't do it in x>=4 masters. We change code to
+ Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
+ of this x>=4 master segfault (expecting a zero when there is
+ none). Remaining compatibility problems are: the older slave will not
+ find the catalog; but it is will not crash, and it's not an issue
+ that it does not find the catalog as catalogs were not used in these
+ older MySQL versions (we store it in binlog and read it from relay log
+ but do nothing useful with it). What is an issue is that the older slave
+ will stop processing the Q_* blocks (and jumps to the db/query) as soon
+ as it sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
+ Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
+ various ways. Documented that you should not mix alpha/beta versions if
+ they are not exactly the same version, with example of 5.0.3->5.0.2 and
+ 5.0.4->5.0.3. If replication is from older to new, the new will
+ recognize Q_CATALOG_CODE and have no problem.
+ */
+ }
+ if (auto_increment_increment != 1 || auto_increment_offset != 1)
+ {
+ *start++= Q_AUTO_INCREMENT;
+ int2store(start, auto_increment_increment);
+ int2store(start+2, auto_increment_offset);
+ start+= 4;
+ }
+ if (charset_inited)
+ {
+ *start++= Q_CHARSET_CODE;
+ memcpy(start, charset, 6);
+ start+= 6;
+ }
+ if (time_zone_len)
+ {
+ /* In the TZ sys table, column Name is of length 64 so this should be ok */
+ DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
+ store_str_with_code_and_len(&start,
+ time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
+ }
+ if (lc_time_names_number)
+ {
+ DBUG_ASSERT(lc_time_names_number <= 0xFFFF);
+ *start++= Q_LC_TIME_NAMES_CODE;
+ int2store(start, lc_time_names_number);
+ start+= 2;
+ }
+ if (charset_database_number)
+ {
+ DBUG_ASSERT(charset_database_number <= 0xFFFF);
+ *start++= Q_CHARSET_DATABASE_CODE;
+ int2store(start, charset_database_number);
+ start+= 2;
+ }
+ if (table_map_for_update)
+ {
+ *start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
+ int8store(start, table_map_for_update);
+ start+= 8;
+ }
+ if (master_data_written != 0)
+ {
+ /*
+ Q_MASTER_DATA_WRITTEN_CODE only exists in relay logs where the master
+ has binlog_version<4 and the slave has binlog_version=4. See comment
+ for master_data_written in log_event.h for details.
+ */
+ *start++= Q_MASTER_DATA_WRITTEN_CODE;
+ int4store(start, master_data_written);
+ start+= 4;
+ }
+
+ if (thd && thd->need_binlog_invoker())
+ {
+ LEX_CSTRING user;
+ LEX_CSTRING host;
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+
+ if (thd->slave_thread && thd->has_invoker())
+ {
+ /* user will be null, if master is older than this patch */
+ user= thd->get_invoker_user();
+ host= thd->get_invoker_host();
+ }
+ else
+ {
+ Security_context *ctx= thd->security_ctx;
+
+ if (thd->need_binlog_invoker() == THD::INVOKER_USER)
+ {
+ user.str= ctx->priv_user;
+ host.str= ctx->priv_host;
+ host.length= strlen(host.str);
+ }
+ else
+ {
+ user.str= ctx->priv_role;
+ host= empty_clex_str;
+ }
+ user.length= strlen(user.str);
+ }
+
+ if (user.length > 0)
+ {
+ *start++= Q_INVOKER;
+
+ /*
+ Store user length and user. The max length of use is 16, so 1 byte is
+ enough to store the user's length.
+ */
+ *start++= (uchar)user.length;
+ memcpy(start, user.str, user.length);
+ start+= user.length;
+
+ /*
+ Store host length and host. The max length of host is 60, so 1 byte is
+ enough to store the host's length.
+ */
+ *start++= (uchar)host.length;
+ memcpy(start, host.str, host.length);
+ start+= host.length;
+ }
+ }
+
+ if (thd && thd->query_start_sec_part_used)
+ {
+ *start++= Q_HRNOW;
+ get_time();
+ int3store(start, when_sec_part);
+ start+= 3;
+ }
+ /*
+ NOTE: When adding new status vars, please don't forget to update
+ the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
+ code_name() in this file.
+
+ Here there could be code like
+ if (command-line-option-which-says-"log_this_variable" && inited)
+ {
+ *start++= Q_THIS_VARIABLE_CODE;
+ int4store(start, this_variable);
+ start+= 4;
+ }
+ */
+
+ /* Store length of status variables */
+ status_vars_len= (uint) (start-start_of_status);
+ DBUG_ASSERT(status_vars_len <= MAX_SIZE_LOG_EVENT_STATUS);
+ int2store(buf + Q_STATUS_VARS_LEN_OFFSET, status_vars_len);
+
+ /*
+ Calculate length of whole event
+ The "1" below is the \0 in the db's length
+ */
+ event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
+
+ return write_header(event_length) ||
+ write_data(buf, QUERY_HEADER_LEN) ||
+ write_post_header_for_derived() ||
+ write_data(start_of_status, (uint) (start-start_of_status)) ||
+ write_data(safe_str(db), db_len + 1) ||
+ write_data(query, q_len) ||
+ write_footer();
+}
+
+bool Query_compressed_log_event::write()
+{
+ const char *query_tmp = query;
+ uint32 q_len_tmp = q_len;
+ uint32 alloc_size;
+ bool ret = true;
+ q_len = alloc_size = binlog_get_compress_len(q_len);
+ query = (char *)my_safe_alloca(alloc_size);
+ if(query && !binlog_buf_compress(query_tmp, (char *)query, q_len_tmp, &q_len))
+ {
+ ret = Query_log_event::write();
+ }
+ my_safe_afree((void *)query, alloc_size);
+ query = query_tmp;
+ q_len = q_len_tmp;
+ return ret;
+}
+
+/**
+ The simplest constructor that could possibly work. This is used for
+ creating static objects that have a special meaning and are invisible
+ to the log.
+*/
+Query_log_event::Query_log_event()
+ :Log_event(), data_buf(0)
+{
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+}
+
+
+/*
+ SYNOPSIS
+ Query_log_event::Query_log_event()
+ thd_arg - thread handle
+ query_arg - array of char representing the query
+ query_length - size of the `query_arg' array
+ using_trans - there is a modified transactional table
+ direct - Don't cache statement
+ suppress_use - suppress the generation of 'USE' statements
+ errcode - the error code of the query
+
+ DESCRIPTION
+ Creates an event for binlogging
+ The value for `errcode' should be supplied by caller.
+*/
+Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, size_t query_length, bool using_trans,
+ bool direct, bool suppress_use, int errcode)
+
+ :Log_event(thd_arg,
+ (thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
+ 0) |
+ (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0),
+ using_trans),
+ data_buf(0), query(query_arg), catalog(thd_arg->catalog),
+ db(thd_arg->db.str), q_len((uint32) query_length),
+ thread_id(thd_arg->thread_id),
+ /* save the original thread id; we already know the server id */
+ slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
+ flags2_inited(1), sql_mode_inited(1), charset_inited(1),
+ sql_mode(thd_arg->variables.sql_mode),
+ auto_increment_increment(thd_arg->variables.auto_increment_increment),
+ auto_increment_offset(thd_arg->variables.auto_increment_offset),
+ lc_time_names_number(thd_arg->variables.lc_time_names->number),
+ charset_database_number(0),
+ table_map_for_update((ulonglong)thd_arg->table_map_for_update),
+ master_data_written(0)
+{
+ time_t end_time;
+
+#ifdef WITH_WSREP
+ /*
+ If Query_log_event will contain non trans keyword (not BEGIN, COMMIT,
+ SAVEPOINT or ROLLBACK) we disable PA for this transaction.
+ */
+ if (WSREP_ON && !is_trans_keyword())
+ thd->wsrep_PA_safe= false;
+#endif /* WITH_WSREP */
+
+ memset(&user, 0, sizeof(user));
+ memset(&host, 0, sizeof(host));
+
+ error_code= errcode;
+
+ end_time= my_time(0);
+ exec_time = (ulong) (end_time - thd_arg->start_time);
+ /**
+ @todo this means that if we have no catalog, then it is replicated
+ as an existing catalog of length zero. is that safe? /sven
+ */
+ catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
+ /* status_vars_len is set just before writing the event */
+ db_len = (db) ? (uint32) strlen(db) : 0;
+ if (thd_arg->variables.collation_database != thd_arg->db_charset)
+ charset_database_number= thd_arg->variables.collation_database->number;
+
+ /*
+ We only replicate over the bits of flags2 that we need: the rest
+ are masked out by "& OPTIONS_WRITTEN_TO_BINLOG".
+
+ We also force AUTOCOMMIT=1. Rationale (cf. BUG#29288): After
+ fixing BUG#26395, we always write BEGIN and COMMIT around all
+ transactions (even single statements in autocommit mode). This is
+ so that replication from non-transactional to transactional table
+ and error recovery from XA to non-XA table should work as
+ expected. The BEGIN/COMMIT are added in log.cc. However, there is
+ one exception: MyISAM bypasses log.cc and writes directly to the
+ binlog. So if autocommit is off, master has MyISAM, and slave has
+ a transactional engine, then the slave will just see one long
+ never-ending transaction. The only way to bypass explicit
+ BEGIN/COMMIT in the binlog is by using a non-transactional table.
+ So setting AUTOCOMMIT=1 will make this work as expected.
+
+ Note: explicitly replicate AUTOCOMMIT=1 from master. We do not
+ assume AUTOCOMMIT=1 on slave; the slave still reads the state of
+ the autocommit flag as written by the master to the binlog. This
+ behavior may change after WL#4162 has been implemented.
+ */
+ flags2= (uint32) (thd_arg->variables.option_bits &
+ (OPTIONS_WRITTEN_TO_BIN_LOG & ~OPTION_NOT_AUTOCOMMIT));
+ DBUG_ASSERT(thd_arg->variables.character_set_client->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.collation_connection->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.collation_server->number < 256*256);
+ DBUG_ASSERT(thd_arg->variables.character_set_client->mbminlen == 1);
+ int2store(charset, thd_arg->variables.character_set_client->number);
+ int2store(charset+2, thd_arg->variables.collation_connection->number);
+ int2store(charset+4, thd_arg->variables.collation_server->number);
+ if (thd_arg->time_zone_used)
+ {
+ /*
+ Note that our event becomes dependent on the Time_zone object
+ representing the time zone. Fortunately such objects are never deleted
+ or changed during mysqld's lifetime.
+ */
+ time_zone_len= thd_arg->variables.time_zone->get_name()->length();
+ time_zone_str= thd_arg->variables.time_zone->get_name()->ptr();
+ }
+ else
+ time_zone_len= 0;
+
+ LEX *lex= thd->lex;
+ /*
+ Defines that the statement will be written directly to the binary log
+ without being wrapped by a BEGIN...COMMIT. Otherwise, the statement
+ will be written to either the trx-cache or stmt-cache.
+
+ Note that a cache will not be used if the parameter direct is TRUE.
+ */
+ bool use_cache= FALSE;
+ /*
+ TRUE defines that the trx-cache must be used and by consequence the
+ use_cache is TRUE.
+
+ Note that a cache will not be used if the parameter direct is TRUE.
+ */
+ bool trx_cache= FALSE;
+ cache_type= Log_event::EVENT_INVALID_CACHE;
+
+ if (!direct)
+ {
+ switch (lex->sql_command)
+ {
+ case SQLCOM_DROP_TABLE:
+ case SQLCOM_DROP_SEQUENCE:
+ use_cache= (lex->tmp_table() && thd->in_multi_stmt_transaction_mode());
+ break;
+
+ case SQLCOM_CREATE_TABLE:
+ case SQLCOM_CREATE_SEQUENCE:
+ /*
+ If we are using CREATE ... SELECT or if we are a slave
+ executing BEGIN...COMMIT (generated by CREATE...SELECT) we
+ have to use the transactional cache to ensure we don't
+ calculate any checksum for the CREATE part.
+ */
+ trx_cache= (lex->first_select_lex()->item_list.elements &&
+ thd->is_current_stmt_binlog_format_row()) ||
+ (thd->variables.option_bits & OPTION_GTID_BEGIN);
+ use_cache= (lex->tmp_table() &&
+ thd->in_multi_stmt_transaction_mode()) || trx_cache;
+ break;
+ case SQLCOM_SET_OPTION:
+ if (lex->autocommit)
+ use_cache= trx_cache= FALSE;
+ else
+ use_cache= TRUE;
+ break;
+ case SQLCOM_RELEASE_SAVEPOINT:
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ case SQLCOM_SAVEPOINT:
+ use_cache= trx_cache= TRUE;
+ break;
+ default:
+ use_cache= sqlcom_can_generate_row_events(thd);
+ break;
+ }
+ }
+
+ if (!use_cache || direct)
+ {
+ cache_type= Log_event::EVENT_NO_CACHE;
+ }
+ else if (using_trans || trx_cache || stmt_has_updated_trans_table(thd) ||
+ thd->lex->is_mixed_stmt_unsafe(thd->in_multi_stmt_transaction_mode(),
+ thd->variables.binlog_direct_non_trans_update,
+ trans_has_updated_trans_table(thd),
+ thd->tx_isolation))
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+ DBUG_ASSERT(cache_type != Log_event::EVENT_INVALID_CACHE);
+ DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %llu cache_tye: %d",
+ (ulong) flags2, sql_mode, cache_type));
+}
+
+Query_compressed_log_event::Query_compressed_log_event(THD* thd_arg, const char* query_arg,
+ ulong query_length, bool using_trans,
+ bool direct, bool suppress_use, int errcode)
+ :Query_log_event(thd_arg, query_arg, query_length, using_trans, direct,
+ suppress_use, errcode),
+ query_buf(0)
+{
+
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int Query_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ return do_apply_event(rgi, query, q_len);
+}
+
+/**
+ Compare if two errors should be regarded as equal.
+ This is to handle the case when you can get slightly different errors
+ on master and slave for the same thing.
+ @param
+ expected_error Error we got on master
+ actual_error Error we got on slave
+
+ @return
+ 1 Errors are equal
+ 0 Errors are different
+*/
+
+bool test_if_equal_repl_errors(int expected_error, int actual_error)
+{
+ if (expected_error == actual_error)
+ return 1;
+ switch (expected_error) {
+ case ER_DUP_ENTRY:
+ case ER_DUP_ENTRY_WITH_KEY_NAME:
+ case ER_DUP_KEY:
+ case ER_AUTOINC_READ_FAILED:
+ return (actual_error == ER_DUP_ENTRY ||
+ actual_error == ER_DUP_ENTRY_WITH_KEY_NAME ||
+ actual_error == ER_DUP_KEY ||
+ actual_error == ER_AUTOINC_READ_FAILED ||
+ actual_error == HA_ERR_AUTOINC_ERANGE);
+ case ER_UNKNOWN_TABLE:
+ return actual_error == ER_IT_IS_A_VIEW;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+/**
+ @todo
+ Compare the values of "affected rows" around here. Something
+ like:
+ @code
+ if ((uint32) affected_in_event != (uint32) affected_on_slave)
+ {
+ sql_print_error("Slave: did not get the expected number of affected \
+ rows running query from master - expected %d, got %d (this numbers \
+ should have matched modulo 4294967296).", 0, ...);
+ thd->query_error = 1;
+ }
+ @endcode
+ We may also want an option to tell the slave to ignore "affected"
+ mismatch. This mismatch could be implemented with a new ER_ code, and
+ to ignore it you would use --slave-skip-errors...
+*/
+int Query_log_event::do_apply_event(rpl_group_info *rgi,
+ const char *query_arg, uint32 q_len_arg)
+{
+ int expected_error,actual_error= 0;
+ Schema_specification_st db_options;
+ uint64 sub_id= 0;
+ void *hton= NULL;
+ rpl_gtid gtid;
+ Relay_log_info const *rli= rgi->rli;
+ Rpl_filter *rpl_filter= rli->mi->rpl_filter;
+ bool current_stmt_is_commit;
+ DBUG_ENTER("Query_log_event::do_apply_event");
+
+ /*
+ Colleagues: please never free(thd->catalog) in MySQL. This would
+ lead to bugs as here thd->catalog is a part of an alloced block,
+ not an entire alloced block (see
+ Query_log_event::do_apply_event()). Same for thd->db. Thank
+ you.
+ */
+ thd->catalog= catalog_len ? (char *) catalog : (char *)"";
+
+ size_t valid_len= Well_formed_prefix(system_charset_info,
+ db, db_len, NAME_LEN).length();
+
+ if (valid_len != db_len)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid database name in Query event.");
+ thd->is_slave_error= true;
+ goto end;
+ }
+
+ set_thd_db(thd, rpl_filter, db, db_len);
+
+ /*
+ Setting the character set and collation of the current database thd->db.
+ */
+ load_db_opt_by_name(thd, thd->db.str, &db_options);
+ if (db_options.default_table_charset)
+ thd->db_charset= db_options.default_table_charset;
+ thd->variables.auto_increment_increment= auto_increment_increment;
+ thd->variables.auto_increment_offset= auto_increment_offset;
+
+ DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos));
+
+ thd->clear_error(1);
+ current_stmt_is_commit= is_commit();
+
+ DBUG_ASSERT(!current_stmt_is_commit || !rgi->tables_to_lock);
+ rgi->slave_close_thread_tables(thd);
+
+ /*
+ Note: We do not need to execute reset_one_shot_variables() if this
+ db_ok() test fails.
+ Reason: The db stored in binlog events is the same for SET and for
+ its companion query. If the SET is ignored because of
+ db_ok(), the companion query will also be ignored, and if
+ the companion query is ignored in the db_ok() test of
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
+ */
+ if (is_trans_keyword() || rpl_filter->db_ok(thd->db.str))
+ {
+ thd->set_time(when, when_sec_part);
+ thd->set_query_and_id((char*)query_arg, q_len_arg,
+ thd->charset(), next_query_id());
+ thd->variables.pseudo_thread_id= thread_id; // for temp tables
+ DBUG_PRINT("query",("%s", thd->query()));
+
+ if (unlikely(!(expected_error= error_code)) ||
+ ignored_error_code(expected_error) ||
+ !unexpected_error_code(expected_error))
+ {
+ thd->slave_expected_error= expected_error;
+ if (flags2_inited)
+ /*
+ all bits of thd->variables.option_bits which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG
+ must take their value from flags2.
+ */
+ thd->variables.option_bits= flags2|(thd->variables.option_bits & ~OPTIONS_WRITTEN_TO_BIN_LOG);
+ /*
+ else, we are in a 3.23/4.0 binlog; we previously received a
+ Rotate_log_event which reset thd->variables.option_bits and sql_mode etc, so
+ nothing to do.
+ */
+ /*
+ We do not replicate MODE_NO_DIR_IN_CREATE. That is, if the master is a
+ slave which runs with SQL_MODE=MODE_NO_DIR_IN_CREATE, this should not
+ force us to ignore the dir too. Imagine you are a ring of machines, and
+ one has a disk problem so that you temporarily need
+ MODE_NO_DIR_IN_CREATE on this machine; you don't want it to propagate
+ elsewhere (you don't want all slaves to start ignoring the dirs).
+ */
+ if (sql_mode_inited)
+ thd->variables.sql_mode=
+ (sql_mode_t) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
+ (sql_mode & ~(sql_mode_t) MODE_NO_DIR_IN_CREATE));
+ if (charset_inited)
+ {
+ rpl_sql_thread_info *sql_info= thd->system_thread_info.rpl_sql_info;
+ if (sql_info->cached_charset_compare(charset))
+ {
+ /* Verify that we support the charsets found in the event. */
+ if (!(thd->variables.character_set_client=
+ get_charset(uint2korr(charset), MYF(MY_WME))) ||
+ !(thd->variables.collation_connection=
+ get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
+ !(thd->variables.collation_server=
+ get_charset(uint2korr(charset+4), MYF(MY_WME))))
+ {
+ /*
+ We updated the thd->variables with nonsensical values (0). Let's
+ set them to something safe (i.e. which avoids crash), and we'll
+ stop with EE_UNKNOWN_CHARSET in compare_errors (unless set to
+ ignore this error).
+ */
+ set_slave_thread_default_charset(thd, rgi);
+ goto compare_errors;
+ }
+ thd->update_charset(); // for the charset change to take effect
+ /*
+ Reset thd->query_string.cs to the newly set value.
+ Note, there is a small flaw here. For a very short time frame
+ if the new charset is different from the old charset and
+ if another thread executes "SHOW PROCESSLIST" after
+ the above thd->set_query_and_id() and before this thd->set_query(),
+ and if the current query has some non-ASCII characters,
+ the another thread may see some '?' marks in the PROCESSLIST
+ result. This should be acceptable now. This is a reminder
+ to fix this if any refactoring happens here sometime.
+ */
+ thd->set_query((char*) query_arg, q_len_arg, thd->charset());
+ }
+ }
+ if (time_zone_len)
+ {
+ String tmp(time_zone_str, time_zone_len, &my_charset_bin);
+ if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
+ {
+ my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
+ thd->variables.time_zone= global_system_variables.time_zone;
+ goto compare_errors;
+ }
+ }
+ if (lc_time_names_number)
+ {
+ if (!(thd->variables.lc_time_names=
+ my_locale_by_number(lc_time_names_number)))
+ {
+ my_printf_error(ER_UNKNOWN_ERROR,
+ "Unknown locale: '%d'", MYF(0), lc_time_names_number);
+ thd->variables.lc_time_names= &my_locale_en_US;
+ goto compare_errors;
+ }
+ }
+ else
+ thd->variables.lc_time_names= &my_locale_en_US;
+ if (charset_database_number)
+ {
+ CHARSET_INFO *cs;
+ if (!(cs= get_charset(charset_database_number, MYF(0))))
+ {
+ char buf[20];
+ int10_to_str((int) charset_database_number, buf, -10);
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), buf);
+ goto compare_errors;
+ }
+ thd->variables.collation_database= cs;
+ }
+ else
+ thd->variables.collation_database= thd->db_charset;
+
+ {
+ const CHARSET_INFO *cs= thd->charset();
+ /*
+ We cannot ask for parsing a statement using a character set
+ without state_maps (parser internal data).
+ */
+ if (!cs->state_map)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "character_set cannot be parsed");
+ thd->is_slave_error= true;
+ goto end;
+ }
+ }
+
+ /*
+ Record any GTID in the same transaction, so slave state is
+ transactionally consistent.
+ */
+ if (current_stmt_is_commit)
+ {
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ if (rgi->gtid_pending)
+ {
+ sub_id= rgi->gtid_sub_id;
+ rgi->gtid_pending= false;
+
+ gtid= rgi->current_gtid;
+ if (unlikely(rpl_global_gtid_slave_state->record_gtid(thd, &gtid,
+ sub_id,
+ true, false,
+ &hton)))
+ {
+ int errcode= thd->get_stmt_da()->sql_errno();
+ if (!is_parallel_retry_error(rgi, errcode))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE,
+ rgi->gtid_info(),
+ "Error during COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str,
+ errcode,
+ thd->get_stmt_da()->message());
+ sub_id= 0;
+ thd->is_slave_error= 1;
+ goto end;
+ }
+ }
+ }
+
+ thd->table_map_for_update= (table_map)table_map_for_update;
+ thd->set_invoker(&user, &host);
+ /*
+ Flag if we need to rollback the statement transaction on
+ slave if it by chance succeeds.
+ If we expected a non-zero error code and get nothing and,
+ it is a concurrency issue or ignorable issue, effects
+ of the statement should be rolled back.
+ */
+ if (unlikely(expected_error) &&
+ (ignored_error_code(expected_error) ||
+ concurrency_error_code(expected_error)))
+ {
+ thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR;
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ }
+ /* Execute the query (note that we bypass dispatch_command()) */
+ Parser_state parser_state;
+ if (!parser_state.init(thd, thd->query(), thd->query_length()))
+ {
+ DBUG_ASSERT(thd->m_digest == NULL);
+ thd->m_digest= & thd->m_digest_state;
+ DBUG_ASSERT(thd->m_statement_psi == NULL);
+ thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state,
+ stmt_info_rpl.m_key,
+ thd->db.str, thd->db.length,
+ thd->charset());
+ THD_STAGE_INFO(thd, stage_init);
+ MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), thd->query_length());
+ if (thd->m_digest != NULL)
+ thd->m_digest->reset(thd->m_token_array, max_digest_length);
+
+ if (thd->slave_thread)
+ {
+ /*
+ To be compatible with previous releases, the slave thread uses the global
+ log_slow_disabled_statements value, wich can be changed dynamically, so we
+ have to set the sql_log_slow respectively.
+ */
+ thd->variables.sql_log_slow= !MY_TEST(global_system_variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_SLAVE);
+ }
+
+ mysql_parse(thd, thd->query(), thd->query_length(), &parser_state,
+ FALSE, FALSE);
+ /* Finalize server status flags after executing a statement. */
+ thd->update_server_status();
+ log_slow_statement(thd);
+ thd->lex->restore_set_statement_var();
+ }
+
+ thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR;
+ }
+ else
+ {
+ /*
+ The query got a really bad error on the master (thread killed etc),
+ which could be inconsistent. Parse it to test the table names: if the
+ replicate-*-do|ignore-table rules say "this query must be ignored" then
+ we exit gracefully; otherwise we warn about the bad error and tell DBA
+ to check/fix it.
+ */
+ if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length()))
+ thd->clear_error(1);
+ else
+ {
+ rli->report(ERROR_LEVEL, expected_error, rgi->gtid_info(),
+ "\
+Query partially completed on the master (error on master: %d) \
+and was aborted. There is a chance that your master is inconsistent at this \
+point. If you are sure that your master is ok, run this query manually on the \
+slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \
+START SLAVE; . Query: '%s'", expected_error, thd->query());
+ thd->is_slave_error= 1;
+ }
+ goto end;
+ }
+
+ /* If the query was not ignored, it is printed to the general log */
+ if (likely(!thd->is_error()) ||
+ thd->get_stmt_da()->sql_errno() != ER_SLAVE_IGNORED_TABLE)
+ general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+ else
+ {
+ /*
+ Bug#54201: If we skip an INSERT query that uses auto_increment, then we
+ should reset any @@INSERT_ID set by an Intvar_log_event associated with
+ the query; otherwise the @@INSERT_ID will linger until the next INSERT
+ that uses auto_increment and may affect extra triggers on the slave etc.
+
+ We reset INSERT_ID unconditionally; it is probably cheaper than
+ checking if it is necessary.
+ */
+ thd->auto_inc_intervals_forced.empty();
+ }
+
+compare_errors:
+ /*
+ In the slave thread, we may sometimes execute some DROP / * 40005
+ TEMPORARY * / TABLE that come from parts of binlogs (likely if we
+ use RESET SLAVE or CHANGE MASTER TO), while the temporary table
+ has already been dropped. To ignore such irrelevant "table does
+ not exist errors", we silently clear the error if TEMPORARY was used.
+ */
+ if ((thd->lex->sql_command == SQLCOM_DROP_TABLE ||
+ thd->lex->sql_command == SQLCOM_DROP_SEQUENCE) &&
+ thd->lex->tmp_table() &&
+ thd->is_error() && thd->get_stmt_da()->sql_errno() == ER_BAD_TABLE_ERROR &&
+ !expected_error)
+ thd->get_stmt_da()->reset_diagnostics_area();
+ /*
+ If we expected a non-zero error code, and we don't get the same error
+ code, and it should be ignored or is related to a concurrency issue.
+ */
+ actual_error= thd->is_error() ? thd->get_stmt_da()->sql_errno() : 0;
+ DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
+ expected_error, actual_error));
+
+ if ((unlikely(expected_error) &&
+ !test_if_equal_repl_errors(expected_error, actual_error) &&
+ !concurrency_error_code(expected_error)) &&
+ !ignored_error_code(actual_error) &&
+ !ignored_error_code(expected_error))
+ {
+ rli->report(ERROR_LEVEL, 0, rgi->gtid_info(),
+ "Query caused different errors on master and slave. "
+ "Error on master: message (format)='%s' error code=%d ; "
+ "Error on slave: actual message='%s', error code=%d. "
+ "Default database: '%s'. Query: '%s'",
+ ER_THD(thd, expected_error),
+ expected_error,
+ actual_error ? thd->get_stmt_da()->message() : "no error",
+ actual_error,
+ print_slave_db_safe(db), query_arg);
+ thd->is_slave_error= 1;
+ }
+ /*
+ If we get the same error code as expected and it is not a concurrency
+ issue, or should be ignored.
+ */
+ else if ((test_if_equal_repl_errors(expected_error, actual_error) &&
+ !concurrency_error_code(expected_error)) ||
+ ignored_error_code(actual_error))
+ {
+ DBUG_PRINT("info",("error ignored"));
+ thd->clear_error(1);
+ if (actual_error == ER_QUERY_INTERRUPTED ||
+ actual_error == ER_CONNECTION_KILLED)
+ thd->reset_killed();
+ }
+ /*
+ Other cases: mostly we expected no error and get one.
+ */
+ else if (unlikely(thd->is_slave_error || thd->is_fatal_error))
+ {
+ if (!is_parallel_retry_error(rgi, actual_error))
+ rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(),
+ "Error '%s' on query. Default database: '%s'. Query: '%s'",
+ (actual_error ? thd->get_stmt_da()->message() :
+ "unexpected success or fatal error"),
+ thd->get_db(), query_arg);
+ thd->is_slave_error= 1;
+#ifdef WITH_WSREP
+ if (wsrep_thd_is_toi(thd) && wsrep_must_ignore_error(thd))
+ {
+ thd->clear_error(1);
+ thd->killed= NOT_KILLED;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
+ }
+
+ /*
+ TODO: compare the values of "affected rows" around here. Something
+ like:
+ if ((uint32) affected_in_event != (uint32) affected_on_slave)
+ {
+ sql_print_error("Slave: did not get the expected number of affected \
+ rows running query from master - expected %d, got %d (this numbers \
+ should have matched modulo 4294967296).", 0, ...);
+ thd->is_slave_error = 1;
+ }
+ We may also want an option to tell the slave to ignore "affected"
+ mismatch. This mismatch could be implemented with a new ER_ code, and
+ to ignore it you would use --slave-skip-errors...
+
+ To do the comparison we need to know the value of "affected" which the
+ above mysql_parse() computed. And we need to know the value of
+ "affected" in the master's binlog. Both will be implemented later. The
+ important thing is that we now have the format ready to log the values
+ of "affected" in the binlog. So we can release 5.0.0 before effectively
+ logging "affected" and effectively comparing it.
+ */
+ } /* End of if (db_ok(... */
+
+ {
+ /**
+ The following failure injecion works in cooperation with tests
+ setting @@global.debug= 'd,stop_slave_middle_group'.
+ The sql thread receives the killed status and will proceed
+ to shutdown trying to finish incomplete events group.
+ */
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
+ if (!current_stmt_is_commit && is_begin() == 0)
+ {
+ if (thd->transaction.all.modified_non_trans_table)
+ const_cast<Relay_log_info*>(rli)->abort_slave= 1;
+ };);
+ }
+
+end:
+ if (unlikely(sub_id && !thd->is_slave_error))
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
+
+ /*
+ Probably we have set thd->query, thd->db, thd->catalog to point to places
+ in the data_buf of this event. Now the event is going to be deleted
+ probably, so data_buf will be freed, so the thd->... listed above will be
+ pointers to freed memory.
+ So we must set them to 0, so that those bad pointers values are not later
+ used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
+ don't suffer from these assignments to 0 as DROP TEMPORARY
+ TABLE uses the db.table syntax.
+ */
+ thd->catalog= 0;
+ thd->set_db(&null_clex_str); /* will free the current database */
+ thd->reset_query();
+ DBUG_PRINT("info", ("end: query= 0"));
+
+ /* Mark the statement completed. */
+ MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
+ thd->m_statement_psi= NULL;
+ thd->m_digest= NULL;
+
+ /*
+ As a disk space optimization, future masters will not log an event for
+ LAST_INSERT_ID() if that function returned 0 (and thus they will be able
+ to replace the THD::stmt_depends_on_first_successful_insert_id_in_prev_stmt
+ variable by (THD->first_successful_insert_id_in_prev_stmt > 0) ; with the
+ resetting below we are ready to support that.
+ */
+ thd->first_successful_insert_id_in_prev_stmt_for_binlog= 0;
+ thd->first_successful_insert_id_in_prev_stmt= 0;
+ thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ DBUG_RETURN(thd->is_slave_error);
+}
+
+Log_event::enum_skip_reason
+Query_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Query_log_event::do_shall_skip");
+ DBUG_PRINT("debug", ("query: '%s' q_len: %d", query, q_len));
+ DBUG_ASSERT(query && q_len > 0);
+ DBUG_ASSERT(thd == rgi->thd);
+
+ /*
+ An event skipped due to @@skip_replication must not be counted towards the
+ number of events to be skipped due to @@sql_slave_skip_counter.
+ */
+ if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+
+ if (rli->slave_skip_counter > 0)
+ {
+ if (is_begin())
+ {
+ thd->variables.option_bits|= OPTION_BEGIN | OPTION_GTID_BEGIN;
+ DBUG_RETURN(Log_event::continue_group(rgi));
+ }
+
+ if (is_commit() || is_rollback())
+ {
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+ }
+#ifdef WITH_WSREP
+ else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 &&
+ thd->wsrep_mysql_replicated > 0 &&
+ (is_begin() || is_commit()))
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+
+
+bool
+Query_log_event::peek_is_commit_rollback(const char *event_start,
+ size_t event_len,
+ enum enum_binlog_checksum_alg checksum_alg)
+{
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
+ if (event_len < LOG_EVENT_HEADER_LEN + QUERY_HEADER_LEN || event_len < 9)
+ return false;
+ return !memcmp(event_start + (event_len-7), "\0COMMIT", 7) ||
+ !memcmp(event_start + (event_len-9), "\0ROLLBACK", 9);
+}
+
+#endif
+
+
+/**************************************************************************
+ Start_log_event_v3 methods
+**************************************************************************/
+
+Start_log_event_v3::Start_log_event_v3()
+ :Log_event(), created(0), binlog_version(BINLOG_VERSION),
+ dont_set_created(0)
+{
+ memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Start_log_event_v3::pack_info(Protocol *protocol)
+{
+ char buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
+ pos= strmov(buf, "Server ver: ");
+ pos= strmov(pos, server_version);
+ pos= strmov(pos, ", Binlog ver: ");
+ pos= int10_to_str(binlog_version, pos, 10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+
+bool Start_log_event_v3::write()
+{
+ char buff[START_V3_HEADER_LEN];
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ if (!dont_set_created)
+ created= get_time(); // this sets when and when_sec_part as a side effect
+ int4store(buff + ST_CREATED_OFFSET,created);
+ return write_header(sizeof(buff)) ||
+ write_data(buff, sizeof(buff)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Start_log_event_v3::do_apply_event() .
+ The master started
+
+ IMPLEMENTATION
+ - To handle the case where the master died without having time to write
+ DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is
+ TODO), we clean up all temporary tables that we got, if we are sure we
+ can (see below).
+
+ @todo
+ - Remove all active user locks.
+ Guilhem 2003-06: this is true but not urgent: the worst it can cause is
+ the use of a bit of memory for a user lock which will not be used
+ anymore. If the user lock is later used, the old one will be released. In
+ other words, no deadlock problem.
+*/
+
+int Start_log_event_v3::do_apply_event(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Start_log_event_v3::do_apply_event");
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+
+ switch (binlog_version)
+ {
+ case 3:
+ case 4:
+ /*
+ This can either be 4.x (then a Start_log_event_v3 is only at master
+ startup so we are sure the master has restarted and cleared his temp
+ tables; the event always has 'created'>0) or 5.0 (then we have to test
+ 'created').
+ */
+ if (created)
+ {
+ rli->close_temporary_tables();
+
+ /*
+ The following is only false if we get here with a BINLOG statement
+ */
+ if (rli->mi)
+ cleanup_load_tmpdir(&rli->mi->cmp_connection_name);
+ }
+ break;
+
+ /*
+ Now the older formats; in that case load_tmpdir is cleaned up by the I/O
+ thread.
+ */
+ case 1:
+ if (strncmp(rli->relay_log.description_event_for_exec->server_version,
+ "3.23.57",7) >= 0 && created)
+ {
+ /*
+ Can distinguish, based on the value of 'created': this event was
+ generated at master startup.
+ */
+ rli->close_temporary_tables();
+ }
+ /*
+ Otherwise, can't distinguish a Start_log_event generated at
+ master startup and one generated by master FLUSH LOGS, so cannot
+ be sure temp tables have to be dropped. So do nothing.
+ */
+ break;
+ default:
+ /*
+ This case is not expected. It can be either an event corruption or an
+ unsupported binary log version.
+ */
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Binlog version not supported");
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(error);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+/***************************************************************************
+ Format_description_log_event methods
+****************************************************************************/
+
+bool Format_description_log_event::write()
+{
+ bool ret;
+ bool no_checksum;
+ /*
+ We don't call Start_log_event_v3::write() because this would make 2
+ my_b_safe_write().
+ */
+ uchar buff[START_V3_HEADER_LEN+1];
+ size_t rec_size= sizeof(buff) + BINLOG_CHECKSUM_ALG_DESC_LEN +
+ number_of_event_types;
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ if (!dont_set_created)
+ created= get_time();
+ int4store(buff + ST_CREATED_OFFSET,created);
+ buff[ST_COMMON_HEADER_LEN_OFFSET]= common_header_len;
+ /*
+ if checksum is requested
+ record the checksum-algorithm descriptor next to
+ post_header_len vector which will be followed by the checksum value.
+ Master is supposed to trigger checksum computing by binlog_checksum_options,
+ slave does it via marking the event according to
+ FD_queue checksum_alg value.
+ */
+ compile_time_assert(BINLOG_CHECKSUM_ALG_DESC_LEN == 1);
+#ifdef DBUG_ASSERT_EXISTS
+ data_written= 0; // to prepare for need_checksum assert
+#endif
+ uint8 checksum_byte= (uint8)
+ (need_checksum() ? checksum_alg : BINLOG_CHECKSUM_ALG_OFF);
+ /*
+ FD of checksum-aware server is always checksum-equipped, (V) is in,
+ regardless of @@global.binlog_checksum policy.
+ Thereby a combination of (A) == 0, (V) != 0 means
+ it's the checksum-aware server's FD event that heads checksum-free binlog
+ file.
+ Here 0 stands for checksumming OFF to evaluate (V) as 0 is that case.
+ A combination of (A) != 0, (V) != 0 denotes FD of the checksum-aware server
+ heading the checksummed binlog.
+ (A), (V) presence in FD of the checksum-aware server makes the event
+ 1 + 4 bytes bigger comparing to the former FD.
+ */
+
+ if ((no_checksum= (checksum_alg == BINLOG_CHECKSUM_ALG_OFF)))
+ {
+ checksum_alg= BINLOG_CHECKSUM_ALG_CRC32; // Forcing (V) room to fill anyway
+ }
+ ret= write_header(rec_size) ||
+ write_data(buff, sizeof(buff)) ||
+ write_data(post_header_len, number_of_event_types) ||
+ write_data(&checksum_byte, sizeof(checksum_byte)) ||
+ write_footer();
+ if (no_checksum)
+ checksum_alg= BINLOG_CHECKSUM_ALG_OFF;
+ return ret;
+}
+
+#if defined(HAVE_REPLICATION)
+int Format_description_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ int ret= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Format_description_log_event::do_apply_event");
+
+ /*
+ As a transaction NEVER spans on 2 or more binlogs:
+ if we have an active transaction at this point, the master died
+ while writing the transaction to the binary log, i.e. while
+ flushing the binlog cache to the binlog. XA guarantees that master has
+ rolled back. So we roll back.
+ Note: this event could be sent by the master to inform us of the
+ format of its binlog; in other words maybe it is not at its
+ original place when it comes to us; we'll know this by checking
+ log_pos ("artificial" events have log_pos == 0).
+ */
+ if (!is_artificial_event() && created && thd->transaction.all.ha_list)
+ {
+ /* This is not an error (XA is safe), just an information */
+ rli->report(INFORMATION_LEVEL, 0, NULL,
+ "Rolling back unfinished transaction (no COMMIT "
+ "or ROLLBACK in relay log). A probable cause is that "
+ "the master died while writing the transaction to "
+ "its binary log, thus rolled back too.");
+ rgi->cleanup_context(thd, 1);
+ }
+
+ /*
+ If this event comes from ourselves, there is no cleaning task to
+ perform, we don't call Start_log_event_v3::do_apply_event()
+ (this was just to update the log's description event).
+ */
+ if (server_id != (uint32) global_system_variables.server_id)
+ {
+ /*
+ If the event was not requested by the slave i.e. the master sent
+ it while the slave asked for a position >4, the event will make
+ rli->group_master_log_pos advance. Say that the slave asked for
+ position 1000, and the Format_desc event's end is 96. Then in
+ the beginning of replication rli->group_master_log_pos will be
+ 0, then 96, then jump to first really asked event (which is
+ >96). So this is ok.
+ */
+ ret= Start_log_event_v3::do_apply_event(rgi);
+ }
+
+ if (!ret)
+ {
+ /* Save the information describing this binlog */
+ copy_crypto_data(rli->relay_log.description_event_for_exec);
+ delete rli->relay_log.description_event_for_exec;
+ rli->relay_log.description_event_for_exec= this;
+ }
+
+ DBUG_RETURN(ret);
+}
+
+int Format_description_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ if (server_id == (uint32) global_system_variables.server_id)
+ {
+ /*
+ We only increase the relay log position if we are skipping
+ events and do not touch any group_* variables, nor flush the
+ relay log info. If there is a crash, we will have to re-skip
+ the events again, but that is a minor issue.
+
+ If we do not skip stepping the group log position (and the
+ server id was changed when restarting the server), it might well
+ be that we start executing at a position that is invalid, e.g.,
+ at a Rows_log_event or a Query_log_event preceeded by a
+ Intvar_log_event instead of starting at a Table_map_log_event or
+ the Intvar_log_event respectively.
+ */
+ rgi->inc_event_relay_log_pos();
+ return 0;
+ }
+ else
+ {
+ return Log_event::do_update_pos(rgi);
+ }
+}
+
+Log_event::enum_skip_reason
+Format_description_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ return Log_event::EVENT_SKIP_NOT;
+}
+
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Start_encryption_log_event::do_apply_event(rpl_group_info* rgi)
+{
+ return rgi->rli->relay_log.description_event_for_exec->start_decryption(this);
+}
+
+int Start_encryption_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ /*
+ master never sends Start_encryption_log_event, any SELE that a slave
+ might see was created locally in MYSQL_BIN_LOG::open() on the slave
+ */
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+#endif
+
+
+/**************************************************************************
+ Load_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+bool Load_log_event::print_query(THD *thd, bool need_db, const char *cs,
+ String *buf, my_off_t *fn_start,
+ my_off_t *fn_end, const char *qualify_db)
+{
+ if (need_db && db && db_len)
+ {
+ buf->append(STRING_WITH_LEN("use "));
+ append_identifier(thd, buf, db, db_len);
+ buf->append(STRING_WITH_LEN("; "));
+ }
+
+ buf->append(STRING_WITH_LEN("LOAD DATA "));
+
+ if (is_concurrent)
+ buf->append(STRING_WITH_LEN("CONCURRENT "));
+
+ if (fn_start)
+ *fn_start= buf->length();
+
+ if (check_fname_outside_temp_buf())
+ buf->append(STRING_WITH_LEN("LOCAL "));
+ buf->append(STRING_WITH_LEN("INFILE '"));
+ buf->append_for_single_quote(fname, fname_len);
+ buf->append(STRING_WITH_LEN("' "));
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ buf->append(STRING_WITH_LEN("REPLACE "));
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ buf->append(STRING_WITH_LEN("IGNORE "));
+
+ buf->append(STRING_WITH_LEN("INTO"));
+
+ if (fn_end)
+ *fn_end= buf->length();
+
+ buf->append(STRING_WITH_LEN(" TABLE "));
+ if (qualify_db)
+ {
+ append_identifier(thd, buf, qualify_db, strlen(qualify_db));
+ buf->append(STRING_WITH_LEN("."));
+ }
+ append_identifier(thd, buf, table_name, table_name_len);
+
+ if (cs != NULL)
+ {
+ buf->append(STRING_WITH_LEN(" CHARACTER SET "));
+ buf->append(cs, strlen(cs));
+ }
+
+ /* We have to create all optional fields as the default is not empty */
+ buf->append(STRING_WITH_LEN(" FIELDS TERMINATED BY "));
+ pretty_print_str(buf, sql_ex.field_term, sql_ex.field_term_len);
+ if (sql_ex.opt_flags & OPT_ENCLOSED_FLAG)
+ buf->append(STRING_WITH_LEN(" OPTIONALLY "));
+ buf->append(STRING_WITH_LEN(" ENCLOSED BY "));
+ pretty_print_str(buf, sql_ex.enclosed, sql_ex.enclosed_len);
+
+ buf->append(STRING_WITH_LEN(" ESCAPED BY "));
+ pretty_print_str(buf, sql_ex.escaped, sql_ex.escaped_len);
+
+ buf->append(STRING_WITH_LEN(" LINES TERMINATED BY "));
+ pretty_print_str(buf, sql_ex.line_term, sql_ex.line_term_len);
+ if (sql_ex.line_start_len)
+ {
+ buf->append(STRING_WITH_LEN(" STARTING BY "));
+ pretty_print_str(buf, sql_ex.line_start, sql_ex.line_start_len);
+ }
+
+ if ((long) skip_lines > 0)
+ {
+ buf->append(STRING_WITH_LEN(" IGNORE "));
+ buf->append_ulonglong(skip_lines);
+ buf->append(STRING_WITH_LEN(" LINES "));
+ }
+
+ if (num_fields)
+ {
+ uint i;
+ const char *field= fields;
+ buf->append(STRING_WITH_LEN(" ("));
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ {
+ /*
+ Yes, the space and comma is reversed here. But this is mostly dead
+ code, at most used when reading really old binlogs from old servers,
+ so better just leave it as is...
+ */
+ buf->append(STRING_WITH_LEN(" ,"));
+ }
+ append_identifier(thd, buf, field, field_lens[i]);
+ field+= field_lens[i] + 1;
+ }
+ buf->append(STRING_WITH_LEN(")"));
+ }
+ return 0;
+}
+
+
+void Load_log_event::pack_info(Protocol *protocol)
+{
+ char query_buffer[1024];
+ String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
+
+ query_str.length(0);
+ print_query(protocol->thd, TRUE, NULL, &query_str, 0, 0, NULL);
+ protocol->store(query_str.ptr(), query_str.length(), &my_charset_bin);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+bool Load_log_event::write_data_header()
+{
+ char buf[LOAD_HEADER_LEN];
+ int4store(buf + L_THREAD_ID_OFFSET, slave_proxy_id);
+ int4store(buf + L_EXEC_TIME_OFFSET, exec_time);
+ int4store(buf + L_SKIP_LINES_OFFSET, skip_lines);
+ buf[L_TBL_LEN_OFFSET] = (char)table_name_len;
+ buf[L_DB_LEN_OFFSET] = (char)db_len;
+ int4store(buf + L_NUM_FIELDS_OFFSET, num_fields);
+ return write_data(buf, LOAD_HEADER_LEN) != 0;
+}
+
+
+bool Load_log_event::write_data_body()
+{
+ if (sql_ex.write_data(writer))
+ return 1;
+ if (num_fields && fields && field_lens)
+ {
+ if (write_data(field_lens, num_fields) ||
+ write_data(fields, field_block_len))
+ return 1;
+ }
+ return (write_data(table_name, table_name_len + 1) ||
+ write_data(db, db_len + 1) ||
+ write_data(fname, fname_len));
+}
+
+
+Load_log_event::Load_log_event(THD *thd_arg, const sql_exchange *ex,
+ const char *db_arg, const char *table_name_arg,
+ List<Item> &fields_arg,
+ bool is_concurrent_arg,
+ enum enum_duplicates handle_dup,
+ bool ignore, bool using_trans)
+ :Log_event(thd_arg,
+ thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0,
+ using_trans),
+ thread_id(thd_arg->thread_id),
+ slave_proxy_id((ulong)thd_arg->variables.pseudo_thread_id),
+ num_fields(0),fields(0),
+ field_lens(0),field_block_len(0),
+ table_name(table_name_arg ? table_name_arg : ""),
+ db(db_arg), fname(ex->file_name), local_fname(FALSE),
+ is_concurrent(is_concurrent_arg)
+{
+ time_t end_time;
+ time(&end_time);
+ exec_time = (ulong) (end_time - thd_arg->start_time);
+ /* db can never be a zero pointer in 4.0 */
+ db_len = (uint32) strlen(db);
+ table_name_len = (uint32) strlen(table_name);
+ fname_len = (fname) ? (uint) strlen(fname) : 0;
+ sql_ex.field_term = ex->field_term->ptr();
+ sql_ex.field_term_len = (uint8) ex->field_term->length();
+ sql_ex.enclosed = ex->enclosed->ptr();
+ sql_ex.enclosed_len = (uint8) ex->enclosed->length();
+ sql_ex.line_term = ex->line_term->ptr();
+ sql_ex.line_term_len = (uint8) ex->line_term->length();
+ sql_ex.line_start = ex->line_start->ptr();
+ sql_ex.line_start_len = (uint8) ex->line_start->length();
+ sql_ex.escaped = ex->escaped->ptr();
+ sql_ex.escaped_len = (uint8) ex->escaped->length();
+ sql_ex.opt_flags = 0;
+ sql_ex.cached_new_format = -1;
+
+ if (ex->dumpfile)
+ sql_ex.opt_flags|= DUMPFILE_FLAG;
+ if (ex->opt_enclosed)
+ sql_ex.opt_flags|= OPT_ENCLOSED_FLAG;
+
+ sql_ex.empty_flags= 0;
+
+ switch (handle_dup) {
+ case DUP_REPLACE:
+ sql_ex.opt_flags|= REPLACE_FLAG;
+ break;
+ case DUP_UPDATE: // Impossible here
+ case DUP_ERROR:
+ break;
+ }
+ if (ignore)
+ sql_ex.opt_flags|= IGNORE_FLAG;
+
+ if (!ex->field_term->length())
+ sql_ex.empty_flags |= FIELD_TERM_EMPTY;
+ if (!ex->enclosed->length())
+ sql_ex.empty_flags |= ENCLOSED_EMPTY;
+ if (!ex->line_term->length())
+ sql_ex.empty_flags |= LINE_TERM_EMPTY;
+ if (!ex->line_start->length())
+ sql_ex.empty_flags |= LINE_START_EMPTY;
+ if (!ex->escaped->length())
+ sql_ex.empty_flags |= ESCAPED_EMPTY;
+
+ skip_lines = ex->skip_lines;
+
+ List_iterator<Item> li(fields_arg);
+ field_lens_buf.length(0);
+ fields_buf.length(0);
+ Item* item;
+ while ((item = li++))
+ {
+ num_fields++;
+ uchar len= (uchar) item->name.length;
+ field_block_len += len + 1;
+ fields_buf.append(item->name.str, len + 1);
+ field_lens_buf.append((char*)&len, 1);
+ }
+
+ field_lens = (const uchar*)field_lens_buf.ptr();
+ fields = fields_buf.ptr();
+}
+
+
+/**
+ Load_log_event::set_fields()
+
+ @note
+ This function can not use the member variable
+ for the database, since LOAD DATA INFILE on the slave
+ can be for a different database than the current one.
+ This is the reason for the affected_db argument to this method.
+*/
+
+void Load_log_event::set_fields(const char* affected_db,
+ List<Item> &field_list,
+ Name_resolution_context *context)
+{
+ uint i;
+ const char* field = fields;
+ for (i= 0; i < num_fields; i++)
+ {
+ LEX_CSTRING field_name= {field, field_lens[i] };
+ field_list.push_back(new (thd->mem_root)
+ Item_field(thd, context,
+ Lex_cstring_strlen(affected_db),
+ Lex_cstring_strlen(table_name),
+ field_name),
+ thd->mem_root);
+ field+= field_lens[i] + 1;
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+/**
+ Does the data loading job when executing a LOAD DATA on the slave.
+
+ @param net
+ @param rli
+ @param use_rli_only_for_errors If set to 1, rli is provided to
+ Load_log_event::exec_event only for this
+ function to have RPL_LOG_NAME and
+ rli->last_slave_error, both being used by
+ error reports. rli's position advancing
+ is skipped (done by the caller which is
+ Execute_load_log_event::exec_event).
+ If set to 0, rli is provided for full use,
+ i.e. for error reports and position
+ advancing.
+
+ @todo
+ fix this; this can be done by testing rules in
+ Create_file_log_event::exec_event() and then discarding Append_block and
+ al.
+ @todo
+ this is a bug - this needs to be moved to the I/O thread
+
+ @retval
+ 0 Success
+ @retval
+ 1 Failure
+*/
+
+int Load_log_event::do_apply_event(NET* net, rpl_group_info *rgi,
+ bool use_rli_only_for_errors)
+{
+ Relay_log_info const *rli= rgi->rli;
+ Rpl_filter *rpl_filter= rli->mi->rpl_filter;
+ DBUG_ENTER("Load_log_event::do_apply_event");
+
+ DBUG_ASSERT(thd->query() == 0);
+ set_thd_db(thd, rpl_filter, db, db_len);
+ thd->clear_error(1);
+
+ /* see Query_log_event::do_apply_event() and BUG#13360 */
+ DBUG_ASSERT(!rgi->m_table_map.count());
+ /*
+ Usually lex_start() is called by mysql_parse(), but we need it here
+ as the present method does not call mysql_parse().
+ */
+ lex_start(thd);
+ thd->lex->local_file= local_fname;
+ thd->reset_for_next_command(0); // Errors are cleared above
+
+ /*
+ We test replicate_*_db rules. Note that we have already prepared
+ the file to load, even if we are going to ignore and delete it
+ now. So it is possible that we did a lot of disk writes for
+ nothing. In other words, a big LOAD DATA INFILE on the master will
+ still consume a lot of space on the slave (space in the relay log
+ + space of temp files: twice the space of the file to load...)
+ even if it will finally be ignored. TODO: fix this; this can be
+ done by testing rules in Create_file_log_event::do_apply_event()
+ and then discarding Append_block and al. Another way is do the
+ filtering in the I/O thread (more efficient: no disk writes at
+ all).
+
+
+ Note: We do not need to execute reset_one_shot_variables() if this
+ db_ok() test fails.
+ Reason: The db stored in binlog events is the same for SET and for
+ its companion query. If the SET is ignored because of
+ db_ok(), the companion query will also be ignored, and if
+ the companion query is ignored in the db_ok() test of
+ ::do_apply_event(), then the companion SET also have so
+ we don't need to reset_one_shot_variables().
+ */
+ if (rpl_filter->db_ok(thd->db.str))
+ {
+ thd->set_time(when, when_sec_part);
+ thd->set_query_id(next_query_id());
+ thd->get_stmt_da()->opt_clear_warning_info(thd->query_id);
+
+ TABLE_LIST tables;
+ LEX_CSTRING db_name= { thd->strmake(thd->db.str, thd->db.length), thd->db.length };
+ if (lower_case_table_names)
+ my_casedn_str(system_charset_info, (char *)table_name);
+ LEX_CSTRING tbl_name= { table_name, strlen(table_name) };
+ tables.init_one_table(&db_name, &tbl_name, 0, TL_WRITE);
+ tables.updating= 1;
+
+ // the table will be opened in mysql_load
+ if (rpl_filter->is_on() && !rpl_filter->tables_ok(thd->db.str, &tables))
+ {
+ // TODO: this is a bug - this needs to be moved to the I/O thread
+ if (net)
+ skip_load_data_infile(net);
+ }
+ else
+ {
+ enum enum_duplicates handle_dup;
+ bool ignore= 0;
+ char query_buffer[1024];
+ String query_str(query_buffer, sizeof(query_buffer), system_charset_info);
+ char *load_data_query;
+
+ query_str.length(0);
+ /*
+ Forge LOAD DATA INFILE query which will be used in SHOW PROCESS LIST
+ and written to slave's binlog if binlogging is on.
+ */
+ print_query(thd, FALSE, NULL, &query_str, NULL, NULL, NULL);
+ if (!(load_data_query= (char *)thd->strmake(query_str.ptr(),
+ query_str.length())))
+ {
+ /*
+ This will set thd->fatal_error in case of OOM. So we surely will notice
+ that something is wrong.
+ */
+ goto error;
+ }
+
+ thd->set_query(load_data_query, (uint) (query_str.length()));
+
+ if (sql_ex.opt_flags & REPLACE_FLAG)
+ handle_dup= DUP_REPLACE;
+ else if (sql_ex.opt_flags & IGNORE_FLAG)
+ {
+ ignore= 1;
+ handle_dup= DUP_ERROR;
+ }
+ else
+ {
+ /*
+ When replication is running fine, if it was DUP_ERROR on the
+ master then we could choose IGNORE here, because if DUP_ERROR
+ suceeded on master, and data is identical on the master and slave,
+ then there should be no uniqueness errors on slave, so IGNORE is
+ the same as DUP_ERROR. But in the unlikely case of uniqueness errors
+ (because the data on the master and slave happen to be different
+ (user error or bug), we want LOAD DATA to print an error message on
+ the slave to discover the problem.
+
+ If reading from net (a 3.23 master), mysql_load() will change this
+ to IGNORE.
+ */
+ handle_dup= DUP_ERROR;
+ }
+ /*
+ We need to set thd->lex->sql_command and thd->lex->duplicates
+ since InnoDB tests these variables to decide if this is a LOAD
+ DATA ... REPLACE INTO ... statement even though mysql_parse()
+ is not called. This is not needed in 5.0 since there the LOAD
+ DATA ... statement is replicated using mysql_parse(), which
+ sets the thd->lex fields correctly.
+ */
+ thd->lex->sql_command= SQLCOM_LOAD;
+ thd->lex->duplicates= handle_dup;
+
+ sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
+ String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
+ String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
+ String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
+ String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
+ String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
+ ex.field_term= &field_term;
+ ex.enclosed= &enclosed;
+ ex.line_term= &line_term;
+ ex.line_start= &line_start;
+ ex.escaped= &escaped;
+
+ ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
+ if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
+ ex.field_term->length(0);
+
+ ex.skip_lines = skip_lines;
+ List<Item> field_list;
+ thd->lex->first_select_lex()->context.resolve_in_table_list_only(&tables);
+ set_fields(tables.db.str,
+ field_list, &thd->lex->first_select_lex()->context);
+ thd->variables.pseudo_thread_id= thread_id;
+ if (net)
+ {
+ // mysql_load will use thd->net to read the file
+ thd->net.vio = net->vio;
+ // Make sure the client does not get confused about the packet sequence
+ thd->net.pkt_nr = net->pkt_nr;
+ }
+ /*
+ It is safe to use tmp_list twice because we are not going to
+ update it inside mysql_load().
+ */
+ List<Item> tmp_list;
+ if (thd->open_temporary_tables(&tables) ||
+ mysql_load(thd, &ex, &tables, field_list, tmp_list, tmp_list,
+ handle_dup, ignore, net != 0))
+ thd->is_slave_error= 1;
+ if (thd->cuted_fields)
+ {
+ /* log_pos is the position of the LOAD event in the master log */
+ sql_print_warning("Slave: load data infile on table '%s' at "
+ "log position %llu in log '%s' produced %ld "
+ "warning(s). Default database: '%s'",
+ (char*) table_name, log_pos, RPL_LOG_NAME,
+ (ulong) thd->cuted_fields,
+ thd->get_db());
+ }
+ if (net)
+ net->pkt_nr= thd->net.pkt_nr;
+ }
+ }
+ else
+ {
+ /*
+ We will just ask the master to send us /dev/null if we do not
+ want to load the data.
+ TODO: this a bug - needs to be done in I/O thread
+ */
+ if (net)
+ skip_load_data_infile(net);
+ }
+
+error:
+ thd->net.vio = 0;
+ const char *remember_db= thd->get_db();
+ thd->catalog= 0;
+ thd->set_db(&null_clex_str); /* will free the current database */
+ thd->reset_query();
+ thd->get_stmt_da()->set_overwrite_status(true);
+ thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ thd->get_stmt_da()->set_overwrite_status(false);
+ close_thread_tables(thd);
+ /*
+ - If transaction rollback was requested due to deadlock
+ perform it and release metadata locks.
+ - If inside a multi-statement transaction,
+ defer the release of metadata locks until the current
+ transaction is either committed or rolled back. This prevents
+ other statements from modifying the table for the entire
+ duration of this transaction. This provides commit ordering
+ and guarantees serializability across multiple transactions.
+ - If in autocommit mode, or outside a transactional context,
+ automatically release metadata locks of the current statement.
+ */
+ if (thd->transaction_rollback_request)
+ {
+ trans_rollback_implicit(thd);
+ thd->mdl_context.release_transactional_locks();
+ }
+ else if (! thd->in_multi_stmt_transaction_mode())
+ thd->mdl_context.release_transactional_locks();
+ else
+ thd->mdl_context.release_statement_locks();
+
+ DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
+ thd->is_slave_error= 0; thd->is_fatal_error= 1;);
+
+ if (unlikely(thd->is_slave_error))
+ {
+ /* this err/sql_errno code is copy-paste from net_send_error() */
+ const char *err;
+ int sql_errno;
+ if (thd->is_error())
+ {
+ err= thd->get_stmt_da()->message();
+ sql_errno= thd->get_stmt_da()->sql_errno();
+ }
+ else
+ {
+ sql_errno=ER_UNKNOWN_ERROR;
+ err= ER_THD(thd, sql_errno);
+ }
+ rli->report(ERROR_LEVEL, sql_errno, rgi->gtid_info(), "\
+Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
+ err, (char*)table_name, remember_db);
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ DBUG_RETURN(1);
+ }
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+
+ if (unlikely(thd->is_fatal_error))
+ {
+ char buf[256];
+ my_snprintf(buf, sizeof(buf),
+ "Running LOAD DATA INFILE on table '%-.64s'."
+ " Default database: '%-.64s'",
+ (char*)table_name,
+ remember_db);
+
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN( use_rli_only_for_errors ? 0 : Log_event::do_apply_event(rgi) );
+}
+#endif
+
+
+/**************************************************************************
+ Rotate_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Rotate_log_event::pack_info(Protocol *protocol)
+{
+ StringBuffer<256> tmp(log_cs);
+ tmp.length(0);
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(STRING_WITH_LEN(";pos="));
+ tmp.append_ulonglong(pos);
+ protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
+}
+#endif
+
+
+Rotate_log_event::Rotate_log_event(const char* new_log_ident_arg,
+ uint ident_len_arg, ulonglong pos_arg,
+ uint flags_arg)
+ :Log_event(), new_log_ident(new_log_ident_arg),
+ pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
+ (uint) strlen(new_log_ident_arg)), flags(flags_arg)
+{
+ DBUG_ENTER("Rotate_log_event::Rotate_log_event(...,flags)");
+ DBUG_PRINT("enter",("new_log_ident: %s pos: %llu flags: %lu", new_log_ident_arg,
+ pos_arg, (ulong) flags));
+ cache_type= EVENT_NO_CACHE;
+ if (flags & DUP_NAME)
+ new_log_ident= my_strndup(new_log_ident_arg, ident_len, MYF(MY_WME));
+ if (flags & RELAY_LOG)
+ set_relay_log_event();
+ DBUG_VOID_RETURN;
+}
+
+
+bool Rotate_log_event::write()
+{
+ char buf[ROTATE_HEADER_LEN];
+ int8store(buf + R_POS_OFFSET, pos);
+ return (write_header(ROTATE_HEADER_LEN + ident_len) ||
+ write_data(buf, ROTATE_HEADER_LEN) ||
+ write_data(new_log_ident, (uint) ident_len) ||
+ write_footer());
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/*
+ Got a rotate log event from the master.
+
+ This is mainly used so that we can later figure out the logname and
+ position for the master.
+
+ We can't rotate the slave's BINlog as this will cause infinitive rotations
+ in a A -> B -> A setup.
+ The NOTES below is a wrong comment which will disappear when 4.1 is merged.
+
+ This must only be called from the Slave SQL thread, since it calls
+ Relay_log_info::flush().
+
+ @retval
+ 0 ok
+ 1 error
+*/
+int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Rotate_log_event::do_update_pos");
+
+ DBUG_PRINT("info", ("server_id=%lu; ::server_id=%lu",
+ (ulong) this->server_id, (ulong) global_system_variables.server_id));
+ DBUG_PRINT("info", ("new_log_ident: %s", this->new_log_ident));
+ DBUG_PRINT("info", ("pos: %llu", this->pos));
+
+ /*
+ If we are in a transaction or in a group: the only normal case is
+ when the I/O thread was copying a big transaction, then it was
+ stopped and restarted: we have this in the relay log:
+
+ BEGIN
+ ...
+ ROTATE (a fake one)
+ ...
+ COMMIT or ROLLBACK
+
+ In that case, we don't want to touch the coordinates which
+ correspond to the beginning of the transaction. Starting from
+ 5.0.0, there also are some rotates from the slave itself, in the
+ relay log, which shall not change the group positions.
+
+ In parallel replication, rotate event is executed out-of-band with normal
+ events, so we cannot update group_master_log_name or _pos here, it will
+ be updated with the next normal event instead.
+ */
+ if ((server_id != global_system_variables.server_id ||
+ rli->replicate_same_server_id) &&
+ !is_relay_log_event() &&
+ !rli->is_in_group() &&
+ !rgi->is_parallel_exec)
+ {
+ mysql_mutex_lock(&rli->data_lock);
+ DBUG_PRINT("info", ("old group_master_log_name: '%s' "
+ "old group_master_log_pos: %lu",
+ rli->group_master_log_name,
+ (ulong) rli->group_master_log_pos));
+ memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
+ rli->notify_group_master_log_name_update();
+ rli->inc_group_relay_log_pos(pos, rgi, TRUE /* skip_lock */);
+ DBUG_PRINT("info", ("new group_master_log_name: '%s' "
+ "new group_master_log_pos: %lu",
+ rli->group_master_log_name,
+ (ulong) rli->group_master_log_pos));
+ mysql_mutex_unlock(&rli->data_lock);
+ rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
+ error= rli->flush();
+
+ /*
+ Reset thd->variables.option_bits and sql_mode etc, because this could
+ be the signal of a master's downgrade from 5.0 to 4.0.
+ However, no need to reset description_event_for_exec: indeed, if the next
+ master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
+ master is 4.0 then the events are in the slave's format (conversion).
+ */
+ set_slave_thread_options(thd);
+ set_slave_thread_default_charset(thd, rgi);
+ thd->variables.sql_mode= global_system_variables.sql_mode;
+ thd->variables.auto_increment_increment=
+ thd->variables.auto_increment_offset= 1;
+ }
+ else
+ rgi->inc_event_relay_log_pos();
+
+ DBUG_RETURN(error);
+}
+
+
+Log_event::enum_skip_reason
+Rotate_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+
+ switch (reason) {
+ case Log_event::EVENT_SKIP_NOT:
+ case Log_event::EVENT_SKIP_COUNT:
+ return Log_event::EVENT_SKIP_NOT;
+
+ case Log_event::EVENT_SKIP_IGNORE:
+ return Log_event::EVENT_SKIP_IGNORE;
+ }
+ DBUG_ASSERT(0);
+ return Log_event::EVENT_SKIP_NOT; // To keep compiler happy
+}
+
+#endif
+
+
+/**************************************************************************
+ Binlog_checkpoint_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Binlog_checkpoint_log_event::pack_info(Protocol *protocol)
+{
+ protocol->store(binlog_file_name, binlog_file_len, &my_charset_bin);
+}
+
+
+Log_event::enum_skip_reason
+Binlog_checkpoint_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+ if (reason == EVENT_SKIP_COUNT)
+ reason= EVENT_SKIP_NOT;
+ return reason;
+}
+#endif
+
+
+Binlog_checkpoint_log_event::Binlog_checkpoint_log_event(
+ const char *binlog_file_name_arg,
+ uint binlog_file_len_arg)
+ :Log_event(),
+ binlog_file_name(my_strndup(binlog_file_name_arg, binlog_file_len_arg,
+ MYF(MY_WME))),
+ binlog_file_len(binlog_file_len_arg)
+{
+ cache_type= EVENT_NO_CACHE;
+}
+
+
+bool Binlog_checkpoint_log_event::write()
+{
+ uchar buf[BINLOG_CHECKPOINT_HEADER_LEN];
+ int4store(buf, binlog_file_len);
+ return write_header(BINLOG_CHECKPOINT_HEADER_LEN + binlog_file_len) ||
+ write_data(buf, BINLOG_CHECKPOINT_HEADER_LEN) ||
+ write_data(binlog_file_name, binlog_file_len) ||
+ write_footer();
+}
+
+
+/**************************************************************************
+ Global transaction ID stuff
+**************************************************************************/
+
+Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
+ uint32 domain_id_arg, bool standalone,
+ uint16 flags_arg, bool is_transactional,
+ uint64 commit_id_arg)
+ : Log_event(thd_arg, flags_arg, is_transactional),
+ seq_no(seq_no_arg), commit_id(commit_id_arg), domain_id(domain_id_arg),
+ flags2((standalone ? FL_STANDALONE : 0) | (commit_id_arg ? FL_GROUP_COMMIT_ID : 0))
+{
+ cache_type= Log_event::EVENT_NO_CACHE;
+ bool is_tmp_table= thd_arg->lex->stmt_accessed_temp_table();
+ if (thd_arg->transaction.stmt.trans_did_wait() ||
+ thd_arg->transaction.all.trans_did_wait())
+ flags2|= FL_WAITED;
+ if (thd_arg->transaction.stmt.trans_did_ddl() ||
+ thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
+ thd_arg->transaction.all.trans_did_ddl() ||
+ thd_arg->transaction.all.has_created_dropped_temp_table())
+ flags2|= FL_DDL;
+ else if (is_transactional && !is_tmp_table)
+ flags2|= FL_TRANSACTIONAL;
+ if (!(thd_arg->variables.option_bits & OPTION_RPL_SKIP_PARALLEL))
+ flags2|= FL_ALLOW_PARALLEL;
+ /* Preserve any DDL or WAITED flag in the slave's binlog. */
+ if (thd_arg->rgi_slave)
+ flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
+}
+
+
+/*
+ Used to record GTID while sending binlog to slave, without having to
+ fully contruct every Gtid_log_event() needlessly.
+*/
+bool
+Gtid_log_event::peek(const char *event_start, size_t event_len,
+ enum enum_binlog_checksum_alg checksum_alg,
+ uint32 *domain_id, uint32 *server_id, uint64 *seq_no,
+ uchar *flags2, const Format_description_log_event *fdev)
+{
+ const char *p;
+
+ if (checksum_alg == BINLOG_CHECKSUM_ALG_CRC32)
+ {
+ if (event_len > BINLOG_CHECKSUM_LEN)
+ event_len-= BINLOG_CHECKSUM_LEN;
+ else
+ event_len= 0;
+ }
+ else
+ DBUG_ASSERT(checksum_alg == BINLOG_CHECKSUM_ALG_UNDEF ||
+ checksum_alg == BINLOG_CHECKSUM_ALG_OFF);
+
+ if (event_len < (uint32)fdev->common_header_len + GTID_HEADER_LEN)
+ return true;
+ *server_id= uint4korr(event_start + SERVER_ID_OFFSET);
+ p= event_start + fdev->common_header_len;
+ *seq_no= uint8korr(p);
+ p+= 8;
+ *domain_id= uint4korr(p);
+ p+= 4;
+ *flags2= (uchar)*p;
+ return false;
+}
+
+
+bool
+Gtid_log_event::write()
+{
+ uchar buf[GTID_HEADER_LEN+2];
+ size_t write_len;
+
+ int8store(buf, seq_no);
+ int4store(buf+8, domain_id);
+ buf[12]= flags2;
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ int8store(buf+13, commit_id);
+ write_len= GTID_HEADER_LEN + 2;
+ }
+ else
+ {
+ bzero(buf+13, GTID_HEADER_LEN-13);
+ write_len= GTID_HEADER_LEN;
+ }
+ return write_header(write_len) ||
+ write_data(buf, write_len) ||
+ write_footer();
+}
+
+
+/*
+ Replace a GTID event with either a BEGIN event, dummy event, or nothing, as
+ appropriate to work with old slave that does not know global transaction id.
+
+ The need_dummy_event argument is an IN/OUT argument. It is passed as TRUE
+ if slave has capability lower than MARIA_SLAVE_CAPABILITY_TOLERATE_HOLES.
+ It is returned TRUE if we return a BEGIN (or dummy) event to be sent to the
+ slave, FALSE if event should be skipped completely.
+*/
+int
+Gtid_log_event::make_compatible_event(String *packet, bool *need_dummy_event,
+ ulong ev_offset,
+ enum enum_binlog_checksum_alg checksum_alg)
+{
+ uchar flags2;
+ if (packet->length() - ev_offset < LOG_EVENT_HEADER_LEN + GTID_HEADER_LEN)
+ return 1;
+ flags2= (*packet)[ev_offset + LOG_EVENT_HEADER_LEN + 12];
+ if (flags2 & FL_STANDALONE)
+ {
+ if (*need_dummy_event)
+ return Query_log_event::dummy_event(packet, ev_offset, checksum_alg);
+ return 0;
+ }
+
+ *need_dummy_event= true;
+ return Query_log_event::begin_event(packet, ev_offset, checksum_alg);
+}
+
+
+#ifdef HAVE_REPLICATION
+void
+Gtid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[6+5+10+1+10+1+20+1+4+20+1];
+ char *p;
+ p = strmov(buf, (flags2 & FL_STANDALONE ? "GTID " : "BEGIN GTID "));
+ p= longlong10_to_str(domain_id, p, 10);
+ *p++= '-';
+ p= longlong10_to_str(server_id, p, 10);
+ *p++= '-';
+ p= longlong10_to_str(seq_no, p, 10);
+ if (flags2 & FL_GROUP_COMMIT_ID)
+ {
+ p= strmov(p, " cid=");
+ p= longlong10_to_str(commit_id, p, 10);
+ }
+
+ protocol->store(buf, p-buf, &my_charset_bin);
+}
+
+static char gtid_begin_string[] = "BEGIN";
+
+int
+Gtid_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ ulonglong bits= thd->variables.option_bits;
+ thd->variables.server_id= this->server_id;
+ thd->variables.gtid_domain_id= this->domain_id;
+ thd->variables.gtid_seq_no= this->seq_no;
+ rgi->gtid_ev_flags2= flags2;
+ thd->reset_for_next_command();
+
+ if (opt_gtid_strict_mode && opt_bin_log && opt_log_slave_updates)
+ {
+ if (mysql_bin_log.check_strict_gtid_sequence(this->domain_id,
+ this->server_id, this->seq_no))
+ return 1;
+ }
+
+ DBUG_ASSERT((bits & OPTION_GTID_BEGIN) == 0);
+
+ Master_info *mi=rgi->rli->mi;
+ switch (flags2 & (FL_DDL | FL_TRANSACTIONAL))
+ {
+ case FL_TRANSACTIONAL:
+ mi->total_trans_groups++;
+ break;
+ case FL_DDL:
+ mi->total_ddl_groups++;
+ break;
+ default:
+ mi->total_non_trans_groups++;
+ }
+
+ if (flags2 & FL_STANDALONE)
+ return 0;
+
+ /* Execute this like a BEGIN query event. */
+ bits|= OPTION_GTID_BEGIN;
+ if (flags2 & FL_ALLOW_PARALLEL)
+ bits&= ~(ulonglong)OPTION_RPL_SKIP_PARALLEL;
+ else
+ bits|= (ulonglong)OPTION_RPL_SKIP_PARALLEL;
+ thd->variables.option_bits= bits;
+ DBUG_PRINT("info", ("Set OPTION_GTID_BEGIN"));
+ thd->set_query_and_id(gtid_begin_string, sizeof(gtid_begin_string)-1,
+ &my_charset_bin, next_query_id());
+ thd->lex->sql_command= SQLCOM_BEGIN;
+ thd->is_slave_error= 0;
+ status_var_increment(thd->status_var.com_stat[thd->lex->sql_command]);
+ if (trans_begin(thd, 0))
+ {
+ DBUG_PRINT("error", ("trans_begin() failed"));
+ thd->is_slave_error= 1;
+ }
+ thd->update_stats();
+
+ if (likely(!thd->is_slave_error))
+ general_log_write(thd, COM_QUERY, thd->query(), thd->query_length());
+
+ thd->reset_query();
+ free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
+ return thd->is_slave_error;
+}
+
+
+int
+Gtid_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Gtid_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ /*
+ An event skipped due to @@skip_replication must not be counted towards the
+ number of events to be skipped due to @@sql_slave_skip_counter.
+ */
+ if (flags & LOG_EVENT_SKIP_REPLICATION_F &&
+ opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE)
+ return Log_event::EVENT_SKIP_IGNORE;
+
+ if (rli->slave_skip_counter > 0)
+ {
+ if (!(flags2 & FL_STANDALONE))
+ {
+ thd->variables.option_bits|= OPTION_BEGIN;
+ DBUG_ASSERT(rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ }
+ return Log_event::continue_group(rgi);
+ }
+ return Log_event::do_shall_skip(rgi);
+}
+
+
+#endif /* HAVE_REPLICATION */
+
+
+
+Gtid_list_log_event::Gtid_list_log_event(rpl_binlog_state *gtid_set,
+ uint32 gl_flags_)
+ : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
+{
+ cache_type= EVENT_NO_CACHE;
+ /* Failure to allocate memory will be caught by is_valid() returning false. */
+ if (count < (1<<28) &&
+ (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
+ MYF(MY_WME))))
+ gtid_set->get_gtid_list(list, count);
+}
+
+
+Gtid_list_log_event::Gtid_list_log_event(slave_connection_state *gtid_set,
+ uint32 gl_flags_)
+ : count(gtid_set->count()), gl_flags(gl_flags_), list(0), sub_id_list(0)
+{
+ cache_type= EVENT_NO_CACHE;
+ /* Failure to allocate memory will be caught by is_valid() returning false. */
+ if (count < (1<<28) &&
+ (list = (rpl_gtid *)my_malloc(count * sizeof(*list) + (count == 0),
+ MYF(MY_WME))))
+ {
+ gtid_set->get_gtid_list(list, count);
+#if defined(HAVE_REPLICATION)
+ if (gl_flags & FLAG_IGN_GTIDS)
+ {
+ uint32 i;
+
+ if (!(sub_id_list= (uint64 *)my_malloc(count * sizeof(uint64),
+ MYF(MY_WME))))
+ {
+ my_free(list);
+ list= NULL;
+ return;
+ }
+ for (i= 0; i < count; ++i)
+ {
+ if (!(sub_id_list[i]=
+ rpl_global_gtid_slave_state->next_sub_id(list[i].domain_id)))
+ {
+ my_free(list);
+ my_free(sub_id_list);
+ list= NULL;
+ sub_id_list= NULL;
+ return;
+ }
+ }
+ }
+#endif
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+bool
+Gtid_list_log_event::to_packet(String *packet)
+{
+ uint32 i;
+ uchar *p;
+ uint32 needed_length;
+
+ DBUG_ASSERT(count < 1<<28);
+
+ needed_length= packet->length() + get_data_size();
+ if (packet->reserve(needed_length))
+ return true;
+ p= (uchar *)packet->ptr() + packet->length();;
+ packet->length(needed_length);
+ int4store(p, (count & ((1<<28)-1)) | gl_flags);
+ p += 4;
+ /* Initialise the padding for empty Gtid_list. */
+ if (count == 0)
+ int2store(p, 0);
+ for (i= 0; i < count; ++i)
+ {
+ int4store(p, list[i].domain_id);
+ int4store(p+4, list[i].server_id);
+ int8store(p+8, list[i].seq_no);
+ p += 16;
+ }
+
+ return false;
+}
+
+
+bool
+Gtid_list_log_event::write()
+{
+ char buf[128];
+ String packet(buf, sizeof(buf), system_charset_info);
+
+ packet.length(0);
+ if (to_packet(&packet))
+ return true;
+ return write_header(get_data_size()) ||
+ write_data(packet.ptr(), packet.length()) ||
+ write_footer();
+}
+
+
+int
+Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= const_cast<Relay_log_info*>(rgi->rli);
+ int ret;
+ if (gl_flags & FLAG_IGN_GTIDS)
+ {
+ void *hton= NULL;
+ uint32 i;
+
+ for (i= 0; i < count; ++i)
+ {
+ if ((ret= rpl_global_gtid_slave_state->record_gtid(thd, &list[i],
+ sub_id_list[i],
+ false, false, &hton)))
+ return ret;
+ rpl_global_gtid_slave_state->update_state_hash(sub_id_list[i], &list[i],
+ hton, NULL);
+ }
+ }
+ ret= Log_event::do_apply_event(rgi);
+ if (rli->until_condition == Relay_log_info::UNTIL_GTID &&
+ (gl_flags & FLAG_UNTIL_REACHED))
+ {
+ char str_buf[128];
+ String str(str_buf, sizeof(str_buf), system_charset_info);
+ rli->until_gtid_pos.to_string(&str);
+ sql_print_information("Slave SQL thread stops because it reached its"
+ " UNTIL master_gtid_pos %s", str.c_ptr_safe());
+ rli->abort_slave= true;
+ rli->stop_for_until= true;
+ }
+ free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
+ return ret;
+}
+
+
+Log_event::enum_skip_reason
+Gtid_list_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ enum_skip_reason reason= Log_event::do_shall_skip(rgi);
+ if (reason == EVENT_SKIP_COUNT)
+ reason= EVENT_SKIP_NOT;
+ return reason;
+}
+
+
+void
+Gtid_list_log_event::pack_info(Protocol *protocol)
+{
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ uint32 i;
+ bool first;
+
+ buf.length(0);
+ buf.append(STRING_WITH_LEN("["));
+ first= true;
+ for (i= 0; i < count; ++i)
+ rpl_slave_state_tostring_helper(&buf, &list[i], &first);
+ buf.append(STRING_WITH_LEN("]"));
+
+ protocol->store(&buf);
+}
+#endif /* HAVE_REPLICATION */
+
+
+
+/**************************************************************************
+ Intvar_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Intvar_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256], *pos;
+ pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
+ *pos++= '=';
+ pos= longlong10_to_str(val, pos, -10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+
+bool Intvar_log_event::write()
+{
+ uchar buf[9];
+ buf[I_TYPE_OFFSET]= (uchar) type;
+ int8store(buf + I_VAL_OFFSET, val);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/*
+ Intvar_log_event::do_apply_event()
+*/
+
+int Intvar_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Intvar_log_event::do_apply_event");
+ if (rgi->deferred_events_collecting)
+ {
+ DBUG_PRINT("info",("deferring event"));
+ DBUG_RETURN(rgi->deferred_events->add(this));
+ }
+
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ thd->first_successful_insert_id_in_prev_stmt= val;
+ DBUG_PRINT("info",("last_insert_id_event: %ld", (long) val));
+ break;
+ case INSERT_ID_EVENT:
+ thd->force_one_auto_inc_interval(val);
+ break;
+ }
+ DBUG_RETURN(0);
+}
+
+int Intvar_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Intvar_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+
+#endif
+
+
+/**************************************************************************
+ Rand_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Rand_log_event::pack_info(Protocol *protocol)
+{
+ char buf1[256], *pos;
+ pos= strmov(buf1,"rand_seed1=");
+ pos= int10_to_str((long) seed1, pos, 10);
+ pos= strmov(pos, ",rand_seed2=");
+ pos= int10_to_str((long) seed2, pos, 10);
+ protocol->store(buf1, (uint) (pos-buf1), &my_charset_bin);
+}
+#endif
+
+
+bool Rand_log_event::write()
+{
+ uchar buf[16];
+ int8store(buf + RAND_SEED1_OFFSET, seed1);
+ int8store(buf + RAND_SEED2_OFFSET, seed2);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int Rand_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ if (rgi->deferred_events_collecting)
+ return rgi->deferred_events->add(this);
+
+ thd->rand.seed1= (ulong) seed1;
+ thd->rand.seed2= (ulong) seed2;
+ return 0;
+}
+
+int Rand_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+
+Log_event::enum_skip_reason
+Rand_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead of
+ 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+
+/**
+ Exec deferred Int-, Rand- and User- var events prefixing
+ a Query-log-event event.
+
+ @param thd THD handle
+
+ @return false on success, true if a failure in an event applying occurred.
+*/
+bool slave_execute_deferred_events(THD *thd)
+{
+ bool res= false;
+ rpl_group_info *rgi= thd->rgi_slave;
+
+ DBUG_ASSERT(rgi && (!rgi->deferred_events_collecting || rgi->deferred_events));
+
+ if (!rgi->deferred_events_collecting || rgi->deferred_events->is_empty())
+ return res;
+
+ res= rgi->deferred_events->execute(rgi);
+ rgi->deferred_events->rewind();
+
+ return res;
+}
+
+#endif /* HAVE_REPLICATION */
+
+
+/**************************************************************************
+ Xid_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+void Xid_log_event::pack_info(Protocol *protocol)
+{
+ char buf[128], *pos;
+ pos= strmov(buf, "COMMIT /* xid=");
+ pos= longlong10_to_str(xid, pos, 10);
+ pos= strmov(pos, " */");
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif
+
+
+bool Xid_log_event::write()
+{
+ DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
+ return write_header(sizeof(xid)) ||
+ write_data((uchar*)&xid, sizeof(xid)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int Xid_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ bool res;
+ int err;
+ rpl_gtid gtid;
+ uint64 sub_id= 0;
+ Relay_log_info const *rli= rgi->rli;
+ void *hton= NULL;
+
+ /*
+ XID_EVENT works like a COMMIT statement. And it also updates the
+ mysql.gtid_slave_pos table with the GTID of the current transaction.
+
+ Therefore, it acts much like a normal SQL statement, so we need to do
+ THD::reset_for_next_command() as if starting a new statement.
+ */
+ thd->reset_for_next_command();
+ /*
+ Record any GTID in the same transaction, so slave state is transactionally
+ consistent.
+ */
+#ifdef WITH_WSREP
+ thd->wsrep_affected_rows= 0;
+#endif
+
+ if (rgi->gtid_pending)
+ {
+ sub_id= rgi->gtid_sub_id;
+ rgi->gtid_pending= false;
+
+ gtid= rgi->current_gtid;
+ err= rpl_global_gtid_slave_state->record_gtid(thd, &gtid, sub_id, true,
+ false, &hton);
+ if (unlikely(err))
+ {
+ int ec= thd->get_stmt_da()->sql_errno();
+ /*
+ Do not report an error if this is really a kill due to a deadlock.
+ In this case, the transaction will be re-tried instead.
+ */
+ if (!is_parallel_retry_error(rgi, ec))
+ rli->report(ERROR_LEVEL, ER_CANNOT_UPDATE_GTID_STATE, rgi->gtid_info(),
+ "Error during XID COMMIT: failed to update GTID state in "
+ "%s.%s: %d: %s",
+ "mysql", rpl_gtid_slave_state_table_name.str, ec,
+ thd->get_stmt_da()->message());
+ thd->is_slave_error= 1;
+ return err;
+ }
+
+ DBUG_EXECUTE_IF("gtid_fail_after_record_gtid",
+ { my_error(ER_ERROR_DURING_COMMIT, MYF(0), HA_ERR_WRONG_COMMAND);
+ thd->is_slave_error= 1;
+ return 1;
+ });
+ }
+
+ /* For a slave Xid_log_event is COMMIT */
+ general_log_print(thd, COM_QUERY,
+ "COMMIT /* implicit, from Xid_log_event */");
+ thd->variables.option_bits&= ~OPTION_GTID_BEGIN;
+ res= trans_commit(thd); /* Automatically rolls back on error. */
+ thd->mdl_context.release_transactional_locks();
+
+ if (likely(!res) && sub_id)
+ rpl_global_gtid_slave_state->update_state_hash(sub_id, &gtid, hton, rgi);
+
+ /*
+ Increment the global status commit count variable
+ */
+ status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+
+ return res;
+}
+
+Log_event::enum_skip_reason
+Xid_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Xid_log_event::do_shall_skip");
+ if (rgi->rli->slave_skip_counter > 0)
+ {
+ DBUG_ASSERT(!rgi->rli->get_flag(Relay_log_info::IN_TRANSACTION));
+ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_GTID_BEGIN);
+ DBUG_RETURN(Log_event::EVENT_SKIP_COUNT);
+ }
+#ifdef WITH_WSREP
+ else if (wsrep_mysql_replication_bundle && WSREP_ON &&
+ opt_slave_domain_parallel_threads == 0)
+ {
+ if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle)
+ {
+ WSREP_DEBUG("skipping wsrep commit %d", thd->wsrep_mysql_replicated);
+ DBUG_RETURN(Log_event::EVENT_SKIP_IGNORE);
+ }
+ else
+ {
+ thd->wsrep_mysql_replicated = 0;
+ }
+ }
+#endif
+ DBUG_RETURN(Log_event::do_shall_skip(rgi));
+}
+#endif // HAVE_REPLICATION
+
+
+/**************************************************************************
+ User_var_log_event methods
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+static bool
+user_var_append_name_part(THD *thd, String *buf,
+ const char *name, size_t name_len)
+{
+ return buf->append("@") ||
+ append_identifier(thd, buf, name, name_len) ||
+ buf->append("=");
+}
+
+void User_var_log_event::pack_info(Protocol* protocol)
+{
+ if (is_null)
+ {
+ char buf_mem[FN_REFLEN+7];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append("NULL"))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ {
+ double real_val;
+ char buf2[MY_GCVT_MAX_FIELD_WIDTH+1];
+ char buf_mem[FN_REFLEN + MY_GCVT_MAX_FIELD_WIDTH + 1];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ float8get(real_val, val);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2, my_gcvt(real_val, MY_GCVT_ARG_DOUBLE,
+ MY_GCVT_MAX_FIELD_WIDTH, buf2, NULL)))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case INT_RESULT:
+ {
+ char buf2[22];
+ char buf_mem[FN_REFLEN + 22];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.length(0);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2,
+ longlong10_to_str(uint8korr(val), buf2,
+ ((flags & User_var_log_event::UNSIGNED_F) ? 10 : -10))-buf2))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ char buf_mem[FN_REFLEN + DECIMAL_MAX_STR_LENGTH];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ char buf2[DECIMAL_MAX_STR_LENGTH+1];
+ String str(buf2, sizeof(buf2), &my_charset_bin);
+ buf.length(0);
+ my_decimal((const uchar *) (val + 2), val[0], val[1]).to_string(&str);
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append(buf2))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case STRING_RESULT:
+ {
+ /* 15 is for 'COLLATE' and other chars */
+ char buf_mem[FN_REFLEN + 512 + 1 + 2*MY_CS_NAME_SIZE+15];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ CHARSET_INFO *cs;
+ buf.length(0);
+ if (!(cs= get_charset(charset_number, MYF(0))))
+ {
+ if (buf.append("???"))
+ return;
+ }
+ else
+ {
+ size_t old_len;
+ char *beg, *end;
+ if (user_var_append_name_part(protocol->thd, &buf, name, name_len) ||
+ buf.append("_") ||
+ buf.append(cs->csname) ||
+ buf.append(" "))
+ return;
+ old_len= buf.length();
+ if (buf.reserve(old_len + val_len * 2 + 3 + sizeof(" COLLATE ") +
+ MY_CS_NAME_SIZE))
+ return;
+ beg= const_cast<char *>(buf.ptr()) + old_len;
+ end= str_to_hex(beg, val, val_len);
+ buf.length(old_len + (end - beg));
+ if (buf.append(" COLLATE ") ||
+ buf.append(cs->name))
+ return;
+ }
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return;
+ }
+ }
+}
+#endif // HAVE_REPLICATION
+
+
+bool User_var_log_event::write()
+{
+ char buf[UV_NAME_LEN_SIZE];
+ char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
+ uchar buf2[MY_MAX(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
+ uint unsigned_len= 0;
+ uint buf1_length;
+ size_t event_length;
+
+ int4store(buf, name_len);
+
+ if ((buf1[0]= is_null))
+ {
+ buf1_length= 1;
+ val_len= 0; // Length of 'pos'
+ }
+ else
+ {
+ buf1[1]= type;
+ int4store(buf1 + 2, charset_number);
+
+ switch (type) {
+ case REAL_RESULT:
+ float8store(buf2, *(double*) val);
+ break;
+ case INT_RESULT:
+ int8store(buf2, *(longlong*) val);
+ unsigned_len= 1;
+ break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal *dec= (my_decimal *)val;
+ dec->fix_buffer_pointer();
+ buf2[0]= (char)(dec->intg + dec->frac);
+ buf2[1]= (char)dec->frac;
+ decimal2bin((decimal_t*)val, buf2+2, buf2[0], buf2[1]);
+ val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
+ break;
+ }
+ case STRING_RESULT:
+ pos= (uchar*) val;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
+ buf1_length= 10;
+ }
+
+ /* Length of the whole event */
+ event_length= sizeof(buf)+ name_len + buf1_length + val_len + unsigned_len;
+
+ return write_header(event_length) ||
+ write_data(buf, sizeof(buf)) ||
+ write_data(name, name_len) ||
+ write_data(buf1, buf1_length) ||
+ write_data(pos, val_len) ||
+ write_data(&flags, unsigned_len) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int User_var_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Item *it= 0;
+ CHARSET_INFO *charset;
+ DBUG_ENTER("User_var_log_event::do_apply_event");
+ query_id_t sav_query_id= 0; /* memorize orig id when deferred applying */
+
+ if (rgi->deferred_events_collecting)
+ {
+ set_deferred(current_thd->query_id);
+ DBUG_RETURN(rgi->deferred_events->add(this));
+ }
+ else if (is_deferred())
+ {
+ sav_query_id= current_thd->query_id;
+ current_thd->query_id= query_id; /* recreating original time context */
+ }
+
+ if (!(charset= get_charset(charset_number, MYF(MY_WME))))
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid character set for User var event");
+ DBUG_RETURN(1);
+ }
+ LEX_CSTRING user_var_name;
+ user_var_name.str= name;
+ user_var_name.length= name_len;
+ double real_val;
+ longlong int_val;
+
+ if (is_null)
+ {
+ it= new (thd->mem_root) Item_null(thd);
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ if (val_len != 8)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ float8get(real_val, val);
+ it= new (thd->mem_root) Item_float(thd, real_val, 0);
+ val= (char*) &real_val; // Pointer to value in native format
+ val_len= 8;
+ break;
+ case INT_RESULT:
+ if (val_len != 8)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ int_val= (longlong) uint8korr(val);
+ it= new (thd->mem_root) Item_int(thd, int_val);
+ val= (char*) &int_val; // Pointer to value in native format
+ val_len= 8;
+ break;
+ case DECIMAL_RESULT:
+ {
+ if (val_len < 3)
+ {
+ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR),
+ "Invalid variable length at User var event");
+ return 1;
+ }
+ Item_decimal *dec= new (thd->mem_root) Item_decimal(thd, (uchar*) val+2, val[0], val[1]);
+ it= dec;
+ val= (char *)dec->val_decimal(NULL);
+ val_len= sizeof(my_decimal);
+ break;
+ }
+ case STRING_RESULT:
+ it= new (thd->mem_root) Item_string(thd, val, (uint)val_len, charset);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0);
+ }
+ }
+
+ Item_func_set_user_var *e= new (thd->mem_root) Item_func_set_user_var(thd, &user_var_name, it);
+ /*
+ Item_func_set_user_var can't substitute something else on its place =>
+ 0 can be passed as last argument (reference on item)
+
+ Fix_fields() can fail, in which case a call of update_hash() might
+ crash the server, so if fix fields fails, we just return with an
+ error.
+ */
+ if (e->fix_fields(thd, 0))
+ DBUG_RETURN(1);
+
+ /*
+ A variable can just be considered as a table with
+ a single record and with a single column. Thus, like
+ a column value, it could always have IMPLICIT derivation.
+ */
+ e->update_hash((void*) val, val_len, type, charset,
+ (flags & User_var_log_event::UNSIGNED_F));
+ if (!is_deferred())
+ free_root(thd->mem_root, 0);
+ else
+ current_thd->query_id= sav_query_id; /* restore current query's context */
+
+ DBUG_RETURN(0);
+}
+
+int User_var_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+Log_event::enum_skip_reason
+User_var_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ It is a common error to set the slave skip counter to 1 instead
+ of 2 when recovering from an insert which used a auto increment,
+ rand, or user var. Therefore, if the slave skip counter is 1, we
+ just say that this event should be skipped by ignoring it, meaning
+ that we do not change the value of the slave skip counter since it
+ will be decreased by the following insert event.
+ */
+ return continue_group(rgi);
+}
+#endif // HAVE_REPLICATION
+
+
+#ifdef HAVE_REPLICATION
+
+/**************************************************************************
+ Stop_log_event methods
+**************************************************************************/
+
+/*
+ The master stopped. We used to clean up all temporary tables but
+ this is useless as, as the master has shut down properly, it has
+ written all DROP TEMPORARY TABLE (prepared statements' deletion is
+ TODO only when we binlog prep stmts). We used to clean up
+ slave_load_tmpdir, but this is useless as it has been cleared at the
+ end of LOAD DATA INFILE. So we have nothing to do here. The place
+ were we must do this cleaning is in
+ Start_log_event_v3::do_apply_event(), not here. Because if we come
+ here, the master was sane.
+
+ This must only be called from the Slave SQL thread, since it calls
+ Relay_log_info::flush().
+*/
+
+int Stop_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ int error= 0;
+ Relay_log_info *rli= rgi->rli;
+ DBUG_ENTER("Stop_log_event::do_update_pos");
+ /*
+ We do not want to update master_log pos because we get a rotate event
+ before stop, so by now group_master_log_name is set to the next log.
+ If we updated it, we will have incorrect master coordinates and this
+ could give false triggers in MASTER_POS_WAIT() that we have reached
+ the target position when in fact we have not.
+ */
+ if (rli->get_flag(Relay_log_info::IN_TRANSACTION))
+ rgi->inc_event_relay_log_pos();
+ else if (!rgi->is_parallel_exec)
+ {
+ rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
+ rli->inc_group_relay_log_pos(0, rgi);
+ if (rli->flush())
+ error= 1;
+ }
+ DBUG_RETURN(error);
+}
+
+#endif /* HAVE_REPLICATION */
+
+
+/**************************************************************************
+ Create_file_log_event methods
+**************************************************************************/
+
+Create_file_log_event::
+Create_file_log_event(THD* thd_arg, sql_exchange* ex,
+ const char* db_arg, const char* table_name_arg,
+ List<Item>& fields_arg,
+ bool is_concurrent_arg,
+ enum enum_duplicates handle_dup,
+ bool ignore,
+ uchar* block_arg, uint block_len_arg, bool using_trans)
+ :Load_log_event(thd_arg, ex, db_arg, table_name_arg, fields_arg,
+ is_concurrent_arg,
+ handle_dup, ignore, using_trans),
+ fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg),
+ file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
+{
+ DBUG_ENTER("Create_file_log_event");
+ sql_ex.force_new_format();
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Create_file_log_event::write_data_body()
+*/
+
+bool Create_file_log_event::write_data_body()
+{
+ bool res;
+ if ((res= Load_log_event::write_data_body()) || fake_base)
+ return res;
+ return write_data("", 1) ||
+ write_data(block, block_len);
+}
+
+
+/*
+ Create_file_log_event::write_data_header()
+*/
+
+bool Create_file_log_event::write_data_header()
+{
+ bool res;
+ uchar buf[CREATE_FILE_HEADER_LEN];
+ if ((res= Load_log_event::write_data_header()) || fake_base)
+ return res;
+ int4store(buf + CF_FILE_ID_OFFSET, file_id);
+ return write_data(buf, CREATE_FILE_HEADER_LEN) != 0;
+}
+
+
+/*
+ Create_file_log_event::write_base()
+*/
+
+bool Create_file_log_event::write_base()
+{
+ bool res;
+ fake_base= 1; // pretend we are Load event
+ res= write();
+ fake_base= 0;
+ return res;
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Create_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[SAFE_NAME_LEN*2 + 30 + 21*2], *pos;
+ pos= strmov(buf, "db=");
+ memcpy(pos, db, db_len);
+ pos= strmov(pos + db_len, ";table=");
+ memcpy(pos, table_name, table_name_len);
+ pos= strmov(pos + table_name_len, ";file_id=");
+ pos= int10_to_str((long) file_id, pos, 10);
+ pos= strmov(pos, ";block_len=");
+ pos= int10_to_str((long) block_len, pos, 10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**
+ Create_file_log_event::do_apply_event()
+ Constructor for Create_file_log_event to intantiate an event
+ from the relay log on the slave.
+
+ @retval
+ 0 Success
+ @retval
+ 1 Failure
+*/
+
+#if defined(HAVE_REPLICATION)
+int Create_file_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname_buf[FN_REFLEN];
+ char *ext;
+ int fd = -1;
+ IO_CACHE file;
+ Log_event_writer lew(&file, 0);
+ int error = 1;
+ Relay_log_info const *rli= rgi->rli;
+
+ THD_STAGE_INFO(thd, stage_making_temp_file_create_before_load_data);
+ bzero((char*)&file, sizeof(file));
+ ext= slave_load_file_stem(fname_buf, file_id, server_id, ".info",
+ &rli->mi->connection_name);
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_info, fname_buf, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_info,
+ fname_buf, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
+ goto err;
+ }
+
+ // a trick to avoid allocating another buffer
+ fname= fname_buf;
+ fname_len= (uint) (strmov(ext, ".data") - fname);
+ writer= &lew;
+ if (write_base())
+ {
+ strmov(ext, ".info"); // to have it right in the error message
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not write to file '%s'",
+ fname_buf);
+ goto err;
+ }
+ end_io_cache(&file);
+ mysql_file_close(fd, MYF(0));
+
+ // fname_buf now already has .data, not .info, because we did our trick
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_data, fname_buf, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_data,
+ fname_buf, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: could not open file '%s'",
+ fname_buf);
+ goto err;
+ }
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Create_file event: write to '%s' failed",
+ fname_buf);
+ goto err;
+ }
+ error=0; // Everything is ok
+
+err:
+ if (unlikely(error))
+ end_io_cache(&file);
+ if (likely(fd >= 0))
+ mysql_file_close(fd, MYF(0));
+ return error != 0;
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Append_block_log_event methods
+**************************************************************************/
+
+Append_block_log_event::Append_block_log_event(THD *thd_arg,
+ const char *db_arg,
+ uchar *block_arg,
+ uint block_len_arg,
+ bool using_trans)
+ :Log_event(thd_arg,0, using_trans), block(block_arg),
+ block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Append_block_log_event::write()
+{
+ uchar buf[APPEND_BLOCK_HEADER_LEN];
+ int4store(buf + AB_FILE_ID_OFFSET, file_id);
+ return write_header(APPEND_BLOCK_HEADER_LEN + block_len) ||
+ write_data(buf, APPEND_BLOCK_HEADER_LEN) ||
+ write_data(block, block_len) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Append_block_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u;block_len=%u", file_id, block_len);
+ protocol->store(buf, length, &my_charset_bin);
+}
+
+
+/*
+ Append_block_log_event::get_create_or_append()
+*/
+
+int Append_block_log_event::get_create_or_append() const
+{
+ return 0; /* append to the file, fail if not exists */
+}
+
+/*
+ Append_block_log_event::do_apply_event()
+*/
+
+int Append_block_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN];
+ int fd;
+ int error = 1;
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Append_block_log_event::do_apply_event");
+
+ THD_STAGE_INFO(thd, stage_making_temp_file_append_before_load_data);
+ slave_load_file_stem(fname, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ if (get_create_or_append())
+ {
+ /*
+ Usually lex_start() is called by mysql_parse(), but we need it here
+ as the present method does not call mysql_parse().
+ */
+ lex_start(thd);
+ thd->reset_for_next_command();
+ /* old copy may exist already */
+ mysql_file_delete(key_file_log_event_data, fname, MYF(0));
+ if ((fd= mysql_file_create(key_file_log_event_data,
+ fname, CREATE_MODE,
+ O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: could not create file '%s'",
+ get_type_str(), fname);
+ goto err;
+ }
+ }
+ else if ((fd= mysql_file_open(key_file_log_event_data,
+ fname,
+ O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0)
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: could not open file '%s'",
+ get_type_str(), fname);
+ goto err;
+ }
+
+ DBUG_EXECUTE_IF("remove_slave_load_file_before_write",
+ {
+ my_delete(fname, MYF(0));
+ });
+
+ if (mysql_file_write(fd, (uchar*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in %s event: write to '%s' failed",
+ get_type_str(), fname);
+ goto err;
+ }
+ error=0;
+
+err:
+ if (fd >= 0)
+ mysql_file_close(fd, MYF(0));
+ DBUG_RETURN(error);
+}
+#endif // HAVE_REPLICATION
+
+
+/**************************************************************************
+ Delete_file_log_event methods
+**************************************************************************/
+
+Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Delete_file_log_event::write()
+{
+ uchar buf[DELETE_FILE_HEADER_LEN];
+ int4store(buf + DF_FILE_ID_OFFSET, file_id);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Delete_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
+ protocol->store(buf, (int32) length, &my_charset_bin);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Delete_file_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN+10];
+ Relay_log_info const *rli= rgi->rli;
+ char *ext= slave_load_file_stem(fname, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+ strmov(ext, ".info");
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
+ return 0;
+}
+#endif /* defined(HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Execute_load_log_event methods
+**************************************************************************/
+
+Execute_load_log_event::Execute_load_log_event(THD *thd_arg,
+ const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
+{
+}
+
+
+bool Execute_load_log_event::write()
+{
+ uchar buf[EXEC_LOAD_HEADER_LEN];
+ int4store(buf + EL_FILE_ID_OFFSET, file_id);
+ return write_header(sizeof(buf)) ||
+ write_data(buf, sizeof(buf)) ||
+ write_footer();
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Execute_load_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) sprintf(buf, ";file_id=%u", (uint) file_id);
+ protocol->store(buf, (int32) length, &my_charset_bin);
+}
+
+
+/*
+ Execute_load_log_event::do_apply_event()
+*/
+
+int Execute_load_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char fname[FN_REFLEN+10];
+ char *ext;
+ int fd;
+ int error= 1;
+ IO_CACHE file;
+ Load_log_event *lev= 0;
+ Relay_log_info const *rli= rgi->rli;
+
+ ext= slave_load_file_stem(fname, file_id, server_id, ".info",
+ &rli->mi->cmp_connection_name);
+ if ((fd= mysql_file_open(key_file_log_event_info,
+ fname, O_RDONLY | O_BINARY | O_NOFOLLOW,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ rli->report(ERROR_LEVEL, my_errno, rgi->gtid_info(),
+ "Error in Exec_load event: could not open file '%s'",
+ fname);
+ goto err;
+ }
+ if (!(lev= (Load_log_event*)
+ Log_event::read_log_event(&file,
+ rli->relay_log.description_event_for_exec,
+ opt_slave_sql_verify_checksum)) ||
+ lev->get_type_code() != NEW_LOAD_EVENT)
+ {
+ rli->report(ERROR_LEVEL, 0, rgi->gtid_info(), "Error in Exec_load event: "
+ "file '%s' appears corrupted", fname);
+ goto err;
+ }
+ lev->thd = thd;
+ /*
+ lev->do_apply_event should use rli only for errors i.e. should
+ not advance rli's position.
+
+ lev->do_apply_event is the place where the table is loaded (it
+ calls mysql_load()).
+ */
+
+ if (lev->do_apply_event(0,rgi,1))
+ {
+ /*
+ We want to indicate the name of the file that could not be loaded
+ (SQL_LOADxxx).
+ But as we are here we are sure the error is in rli->last_slave_error and
+ rli->last_slave_errno (example of error: duplicate entry for key), so we
+ don't want to overwrite it with the filename.
+ What we want instead is add the filename to the current error message.
+ */
+ char *tmp= my_strdup(rli->last_error().message, MYF(MY_WME));
+ if (tmp)
+ {
+ rli->report(ERROR_LEVEL, rli->last_error().number, rgi->gtid_info(),
+ "%s. Failed executing load from '%s'", tmp, fname);
+ my_free(tmp);
+ }
+ goto err;
+ }
+ /*
+ We have an open file descriptor to the .info file; we need to close it
+ or Windows will refuse to delete the file in mysql_file_delete().
+ */
+ if (fd >= 0)
+ {
+ mysql_file_close(fd, MYF(0));
+ end_io_cache(&file);
+ fd= -1;
+ }
+ mysql_file_delete(key_file_log_event_info, fname, MYF(MY_WME));
+ memcpy(ext, ".data", 6);
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+ error = 0;
+
+err:
+ delete lev;
+ if (fd >= 0)
+ {
+ mysql_file_close(fd, MYF(0));
+ end_io_cache(&file);
+ }
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+/**************************************************************************
+ Begin_load_query_log_event methods
+**************************************************************************/
+
+Begin_load_query_log_event::
+Begin_load_query_log_event(THD* thd_arg, const char* db_arg, uchar* block_arg,
+ uint block_len_arg, bool using_trans)
+ :Append_block_log_event(thd_arg, db_arg, block_arg, block_len_arg,
+ using_trans)
+{
+ file_id= thd_arg->file_id= mysql_bin_log.next_file_id();
+}
+
+
+#if defined( HAVE_REPLICATION)
+int Begin_load_query_log_event::get_create_or_append() const
+{
+ return 1; /* create the file */
+}
+
+
+Log_event::enum_skip_reason
+Begin_load_query_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ return continue_group(rgi);
+}
+#endif /* defined( HAVE_REPLICATION) */
+
+
+/**************************************************************************
+ Execute_load_query_log_event methods
+**************************************************************************/
+
+Execute_load_query_log_event::
+Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
+ ulong query_length_arg, uint fn_pos_start_arg,
+ uint fn_pos_end_arg,
+ enum_load_dup_handling dup_handling_arg,
+ bool using_trans, bool direct, bool suppress_use,
+ int errcode):
+ Query_log_event(thd_arg, query_arg, query_length_arg, using_trans, direct,
+ suppress_use, errcode),
+ file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
+ fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
+{
+}
+
+
+bool
+Execute_load_query_log_event::write_post_header_for_derived()
+{
+ uchar buf[EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN];
+ int4store(buf, file_id);
+ int4store(buf + 4, fn_pos_start);
+ int4store(buf + 4 + 4, fn_pos_end);
+ *(buf + 4 + 4 + 4)= (uchar) dup_handling;
+ return write_data(buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Execute_load_query_log_event::pack_info(Protocol *protocol)
+{
+ char buf_mem[1024];
+ String buf(buf_mem, sizeof(buf_mem), system_charset_info);
+ buf.real_alloc(9 + db_len + q_len + 10 + 21);
+ if (db && db_len)
+ {
+ if (buf.append(STRING_WITH_LEN("use ")) ||
+ append_identifier(protocol->thd, &buf, db, db_len) ||
+ buf.append(STRING_WITH_LEN("; ")))
+ return;
+ }
+ if (query && q_len && buf.append(query, q_len))
+ return;
+ if (buf.append(" ;file_id=") ||
+ buf.append_ulonglong(file_id))
+ return;
+ protocol->store(buf.ptr(), buf.length(), &my_charset_bin);
+}
+
+
+int
+Execute_load_query_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ char *p;
+ char *buf;
+ char *fname;
+ char *fname_end;
+ int error;
+ Relay_log_info const *rli= rgi->rli;
+
+ buf= (char*) my_malloc(q_len + 1 - (fn_pos_end - fn_pos_start) +
+ (FN_REFLEN + 10) + 10 + 8 + 5, MYF(MY_WME));
+
+ DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", my_free(buf); buf= NULL;);
+
+ /* Replace filename and LOCAL keyword in query before executing it */
+ if (buf == NULL)
+ {
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(rgi->thd, ER_SLAVE_FATAL_ERROR), "Not enough memory");
+ return 1;
+ }
+
+ p= buf;
+ memcpy(p, query, fn_pos_start);
+ p+= fn_pos_start;
+ fname= (p= strmake(p, STRING_WITH_LEN(" INFILE \'")));
+ p= slave_load_file_stem(p, file_id, server_id, ".data",
+ &rli->mi->cmp_connection_name);
+ fname_end= p= strend(p); // Safer than p=p+5
+ *(p++)='\'';
+ switch (dup_handling) {
+ case LOAD_DUP_IGNORE:
+ p= strmake(p, STRING_WITH_LEN(" IGNORE"));
+ break;
+ case LOAD_DUP_REPLACE:
+ p= strmake(p, STRING_WITH_LEN(" REPLACE"));
+ break;
+ default:
+ /* Ordinary load data */
+ break;
+ }
+ p= strmake(p, STRING_WITH_LEN(" INTO "));
+ p= strmake(p, query+fn_pos_end, q_len-fn_pos_end);
+
+ error= Query_log_event::do_apply_event(rgi, buf, (uint32)(p-buf));
+
+ /* Forging file name for deletion in same buffer */
+ *fname_end= 0;
+
+ /*
+ If there was an error the slave is going to stop, leave the
+ file so that we can re-execute this event at START SLAVE.
+ */
+ if (unlikely(!error))
+ mysql_file_delete(key_file_log_event_data, fname, MYF(MY_WME));
+
+ my_free(buf);
+ return error;
+}
+#endif // HAVE_REPLICATION
+
+
+/**************************************************************************
+ sql_ex_info methods
+**************************************************************************/
+
+static bool write_str(Log_event_writer *writer, const char *str, uint length)
+{
+ uchar tmp[1];
+ tmp[0]= (uchar) length;
+ return (writer->write_data(tmp, sizeof(tmp)) ||
+ writer->write_data((uchar*) str, length));
+}
+
+bool sql_ex_info::write_data(Log_event_writer *writer)
+{
+ if (new_format())
+ {
+ return write_str(writer, field_term, field_term_len) ||
+ write_str(writer, enclosed, enclosed_len) ||
+ write_str(writer, line_term, line_term_len) ||
+ write_str(writer, line_start, line_start_len) ||
+ write_str(writer, escaped, escaped_len) ||
+ writer->write_data((uchar*) &opt_flags, 1);
+ }
+ else
+ {
+ uchar old_ex[7];
+ old_ex[0]= *field_term;
+ old_ex[1]= *enclosed;
+ old_ex[2]= *line_term;
+ old_ex[3]= *line_start;
+ old_ex[4]= *escaped;
+ old_ex[5]= opt_flags;
+ old_ex[6]= empty_flags;
+ return writer->write_data(old_ex, sizeof(old_ex));
+ }
+}
+
+
+
+/**************************************************************************
+ Rows_log_event member functions
+**************************************************************************/
+
+Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
+ MY_BITMAP const *cols, bool is_transactional,
+ Log_event_type event_type)
+ : Log_event(thd_arg, 0, is_transactional),
+ m_row_count(0),
+ m_table(tbl_arg),
+ m_table_id(tid),
+ m_width(tbl_arg ? tbl_arg->s->fields : 1),
+ m_rows_buf(0), m_rows_cur(0), m_rows_end(0), m_flags(0),
+ m_type(event_type), m_extra_row_data(0)
+#ifdef HAVE_REPLICATION
+ , m_curr_row(NULL), m_curr_row_end(NULL),
+ m_key(NULL), m_key_info(NULL), m_key_nr(0),
+ master_had_triggers(0)
+#endif
+{
+ /*
+ We allow a special form of dummy event when the table, and cols
+ are null and the table id is ~0UL. This is a temporary
+ solution, to be able to terminate a started statement in the
+ binary log: the extraneous events will be removed in the future.
+ */
+ DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
+ (!tbl_arg && !cols && tid == ~0UL));
+
+ if (thd_arg->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)
+ set_flags(NO_FOREIGN_KEY_CHECKS_F);
+ if (thd_arg->variables.option_bits & OPTION_RELAXED_UNIQUE_CHECKS)
+ set_flags(RELAXED_UNIQUE_CHECKS_F);
+ if (thd_arg->variables.option_bits & OPTION_NO_CHECK_CONSTRAINT_CHECKS)
+ set_flags(NO_CHECK_CONSTRAINT_CHECKS_F);
+ /* if my_bitmap_init fails, caught in is_valid() */
+ if (likely(!my_bitmap_init(&m_cols,
+ m_width <= sizeof(m_bitbuf)*8 ? m_bitbuf : NULL,
+ m_width,
+ false)))
+ {
+ /* Cols can be zero if this is a dummy binrows event */
+ if (likely(cols != NULL))
+ {
+ memcpy(m_cols.bitmap, cols->bitmap, no_bytes_in_map(cols));
+ create_last_word_mask(&m_cols);
+ }
+ }
+ else
+ {
+ // Needed because my_bitmap_init() does not set it to null on failure
+ m_cols.bitmap= 0;
+ }
+}
+
+
+int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
+{
+ /*
+ When the table has a primary key, we would probably want, by default, to
+ log only the primary key value instead of the entire "before image". This
+ would save binlog space. TODO
+ */
+ DBUG_ENTER("Rows_log_event::do_add_row_data");
+ DBUG_PRINT("enter", ("row_data:%p length: %lu", row_data,
+ (ulong) length));
+
+ /*
+ If length is zero, there is nothing to write, so we just
+ return. Note that this is not an optimization, since calling
+ realloc() with size 0 means free().
+ */
+ if (length == 0)
+ {
+ m_row_count++;
+ DBUG_RETURN(0);
+ }
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_DUMP("row_data", row_data, MY_MIN(length, 32));
+#endif
+
+ DBUG_ASSERT(m_rows_buf <= m_rows_cur);
+ DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end));
+ DBUG_ASSERT(m_rows_cur <= m_rows_end);
+
+ /* The cast will always work since m_rows_cur <= m_rows_end */
+ if (static_cast<size_t>(m_rows_end - m_rows_cur) <= length)
+ {
+ size_t const block_size= 1024;
+ size_t cur_size= m_rows_cur - m_rows_buf;
+ DBUG_EXECUTE_IF("simulate_too_big_row_case1",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case2",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= block_size * 10;);
+ DBUG_EXECUTE_IF("simulate_too_big_row_case3",
+ cur_size= block_size * 10;
+ length= UINT_MAX32 - (block_size * 10););
+ DBUG_EXECUTE_IF("simulate_too_big_row_case4",
+ cur_size= UINT_MAX32 - (block_size * 10);
+ length= (block_size * 10) - block_size + 1;);
+ size_t remaining_space= UINT_MAX32 - cur_size;
+ /* Check that the new data fits within remaining space and we can add
+ block_size without wrapping.
+ */
+ if (cur_size > UINT_MAX32 || length > remaining_space ||
+ ((length + block_size) > remaining_space))
+ {
+ sql_print_error("The row data is greater than 4GB, which is too big to "
+ "write to the binary log.");
+ DBUG_RETURN(ER_BINLOG_ROW_LOGGING_FAILED);
+ }
+ size_t const new_alloc=
+ block_size * ((cur_size + length + block_size - 1) / block_size);
+
+ uchar* const new_buf= (uchar*)my_realloc((uchar*)m_rows_buf, new_alloc,
+ MYF(MY_ALLOW_ZERO_PTR|MY_WME));
+ if (unlikely(!new_buf))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+ /* If the memory moved, we need to move the pointers */
+ if (new_buf != m_rows_buf)
+ {
+ m_rows_buf= new_buf;
+ m_rows_cur= m_rows_buf + cur_size;
+ }
+
+ /*
+ The end pointer should always be changed to point to the end of
+ the allocated memory.
+ */
+ m_rows_end= m_rows_buf + new_alloc;
+ }
+
+ DBUG_ASSERT(m_rows_cur + length <= m_rows_end);
+ memcpy(m_rows_cur, row_data, length);
+ m_rows_cur+= length;
+ m_row_count++;
+ DBUG_RETURN(0);
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ Restores empty table list as it was before trigger processing.
+
+ @note We have a lot of ASSERTS that check the lists when we close tables.
+ There was the same problem with MERGE MYISAM tables and so here we try to
+ go the same way.
+*/
+static void restore_empty_query_table_list(LEX *lex)
+{
+ if (lex->first_not_own_table())
+ (*lex->first_not_own_table()->prev_global)= NULL;
+ lex->query_tables= NULL;
+ lex->query_tables_last= &lex->query_tables;
+}
+
+
+int Rows_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info const *rli= rgi->rli;
+ TABLE* table;
+ DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
+ int error= 0;
+ /*
+ If m_table_id == ~0ULL, then we have a dummy event that does not
+ contain any data. In that case, we just remove all tables in the
+ tables_to_lock list, close the thread tables, and return with
+ success.
+ */
+ if (m_table_id == ~0ULL)
+ {
+ /*
+ This one is supposed to be set: just an extra check so that
+ nothing strange has happened.
+ */
+ DBUG_ASSERT(get_flags(STMT_END_F));
+
+ rgi->slave_close_thread_tables(thd);
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+
+ /*
+ 'thd' has been set by exec_relay_log_event(), just before calling
+ do_apply_event(). We still check here to prevent future coding
+ errors.
+ */
+ DBUG_ASSERT(rgi->thd == thd);
+
+ /*
+ If there is no locks taken, this is the first binrow event seen
+ after the table map events. We should then lock all the tables
+ used in the transaction and proceed with execution of the actual
+ event.
+ */
+ if (!thd->lock)
+ {
+ /*
+ Lock_tables() reads the contents of thd->lex, so they must be
+ initialized.
+
+ We also call the THD::reset_for_next_command(), since this
+ is the logical start of the next "statement". Note that this
+ call might reset the value of current_stmt_binlog_format, so
+ we need to do any changes to that value after this function.
+ */
+ delete_explain_query(thd->lex);
+ lex_start(thd);
+ thd->reset_for_next_command();
+ /*
+ The current statement is just about to begin and
+ has not yet modified anything. Note, all.modified is reset
+ by THD::reset_for_next_command().
+ */
+ thd->transaction.stmt.modified_non_trans_table= FALSE;
+ thd->transaction.stmt.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ /*
+ This is a row injection, so we flag the "statement" as
+ such. Note that this code is called both when the slave does row
+ injections and when the BINLOG statement is used to do row
+ injections.
+ */
+ thd->lex->set_stmt_row_injection();
+
+ /*
+ There are a few flags that are replicated with each row event.
+ Make sure to set/clear them before executing the main body of
+ the event.
+ */
+ if (get_flags(NO_FOREIGN_KEY_CHECKS_F))
+ thd->variables.option_bits|= OPTION_NO_FOREIGN_KEY_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_NO_FOREIGN_KEY_CHECKS;
+
+ if (get_flags(RELAXED_UNIQUE_CHECKS_F))
+ thd->variables.option_bits|= OPTION_RELAXED_UNIQUE_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_RELAXED_UNIQUE_CHECKS;
+
+ if (get_flags(NO_CHECK_CONSTRAINT_CHECKS_F))
+ thd->variables.option_bits|= OPTION_NO_CHECK_CONSTRAINT_CHECKS;
+ else
+ thd->variables.option_bits&= ~OPTION_NO_CHECK_CONSTRAINT_CHECKS;
+
+ /* A small test to verify that objects have consistent types */
+ DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+
+ DBUG_EXECUTE_IF("rows_log_event_before_open_table",
+ {
+ const char action[] = "now SIGNAL before_open_table WAIT_FOR go_ahead_sql";
+ DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
+ };);
+
+ if (slave_run_triggers_for_rbr)
+ {
+ LEX *lex= thd->lex;
+ uint8 new_trg_event_map= get_trg_event_map();
+
+ /*
+ Trigger's procedures work with global table list. So we have to add
+ rgi->tables_to_lock content there to get trigger's in the list.
+
+ Then restore_empty_query_table_list() restore the list as it was
+ */
+ DBUG_ASSERT(lex->query_tables == NULL);
+ if ((lex->query_tables= rgi->tables_to_lock))
+ rgi->tables_to_lock->prev_global= &lex->query_tables;
+
+ for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
+ tables= tables->next_global)
+ {
+ tables->trg_event_map= new_trg_event_map;
+ lex->query_tables_last= &tables->next_global;
+ }
+ }
+ if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
+ {
+#ifdef WITH_WSREP
+ if (WSREP(thd))
+ {
+ WSREP_WARN("BF applier failed to open_and_lock_tables: %u, fatal: %d "
+ "wsrep = (exec_mode: %d conflict_state: %d seqno: %lld)",
+ thd->get_stmt_da()->sql_errno(),
+ thd->is_fatal_error,
+ thd->wsrep_cs().mode(),
+ thd->wsrep_trx().state(),
+ (long long) wsrep_thd_trx_seqno(thd));
+ }
+#endif /* WITH_WSREP */
+ if (thd->is_error() &&
+ !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno()))
+ {
+ /*
+ Error reporting borrowed from Query_log_event with many excessive
+ simplifications.
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skipped.
+ */
+ rli->report(ERROR_LEVEL, error, rgi->gtid_info(),
+ "Error executing row event: '%s'",
+ (error ? thd->get_stmt_da()->message() :
+ "unexpected success or fatal error"));
+ thd->is_slave_error= 1;
+ }
+ /* remove trigger's tables */
+ goto err;
+ }
+
+ /*
+ When the open and locking succeeded, we check all tables to
+ ensure that they still have the correct type.
+ */
+
+ {
+ DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
+ rgi->tables_to_lock));
+
+ /**
+ When using RBR and MyISAM MERGE tables the base tables that make
+ up the MERGE table can be appended to the list of tables to lock.
+
+ Thus, we just check compatibility for those that tables that have
+ a correspondent table map event (ie, those that are actually going
+ to be accessed while applying the event). That's why the loop stops
+ at rli->tables_to_lock_count .
+
+ NOTE: The base tables are added here are removed when
+ close_thread_tables is called.
+ */
+ TABLE_LIST *table_list_ptr= rgi->tables_to_lock;
+ for (uint i=0 ; table_list_ptr && (i < rgi->tables_to_lock_count);
+ table_list_ptr= table_list_ptr->next_global, i++)
+ {
+ /*
+ Below if condition takes care of skipping base tables that
+ make up the MERGE table (which are added by open_tables()
+ call). They are added next to the merge table in the list.
+ For eg: If RPL_TABLE_LIST is t3->t1->t2 (where t1 and t2
+ are base tables for merge table 't3'), open_tables will modify
+ the list by adding t1 and t2 again immediately after t3 in the
+ list (*not at the end of the list*). New table_to_lock list will
+ look like t3->t1'->t2'->t1->t2 (where t1' and t2' are TABLE_LIST
+ objects added by open_tables() call). There is no flag(or logic) in
+ open_tables() that can skip adding these base tables to the list.
+ So the logic here should take care of skipping them.
+
+ tables_to_lock_count logic will take care of skipping base tables
+ that are added at the end of the list.
+ For eg: If RPL_TABLE_LIST is t1->t2->t3, open_tables will modify
+ the list into t1->t2->t3->t1'->t2'. t1' and t2' will be skipped
+ because tables_to_lock_count logic in this for loop.
+ */
+ if (table_list_ptr->parent_l)
+ continue;
+ /*
+ We can use a down cast here since we know that every table added
+ to the tables_to_lock is a RPL_TABLE_LIST (or child table which is
+ skipped above).
+ */
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(table_list_ptr);
+ DBUG_ASSERT(ptr->m_tabledef_valid);
+ TABLE *conv_table;
+ if (!ptr->m_tabledef.compatible_with(thd, rgi, ptr->table, &conv_table))
+ {
+ DBUG_PRINT("debug", ("Table: %s.%s is not compatible with master",
+ ptr->table->s->db.str,
+ ptr->table->s->table_name.str));
+ /*
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skiped.
+ */
+ thd->is_slave_error= 1;
+ /* remove trigger's tables */
+ error= ERR_BAD_TABLE_DEF;
+ goto err;
+ }
+ DBUG_PRINT("debug", ("Table: %s.%s is compatible with master"
+ " - conv_table: %p",
+ ptr->table->s->db.str,
+ ptr->table->s->table_name.str, conv_table));
+ ptr->m_conv_table= conv_table;
+ }
+ }
+
+ /*
+ ... and then we add all the tables to the table map and but keep
+ them in the tables to lock list.
+
+ We also invalidate the query cache for all the tables, since
+ they will now be changed.
+
+ TODO [/Matz]: Maybe the query cache should not be invalidated
+ here? It might be that a table is not changed, even though it
+ was locked for the statement. We do know that each
+ Rows_log_event contain at least one row, so after processing one
+ Rows_log_event, we can invalidate the query cache for the
+ associated table.
+ */
+ TABLE_LIST *ptr= rgi->tables_to_lock;
+ for (uint i=0 ; ptr && (i < rgi->tables_to_lock_count); ptr= ptr->next_global, i++)
+ {
+ /*
+ Please see comment in above 'for' loop to know the reason
+ for this if condition
+ */
+ if (ptr->parent_l)
+ continue;
+ rgi->m_table_map.set_table(ptr->table_id, ptr->table);
+ /*
+ Following is passing flag about triggers on the server. The problem was
+ to pass it between table map event and row event. I do it via extended
+ TABLE_LIST (RPL_TABLE_LIST) but row event uses only TABLE so I need to
+ find somehow the corresponding TABLE_LIST.
+ */
+ if (m_table_id == ptr->table_id)
+ {
+ ptr->table->master_had_triggers=
+ ((RPL_TABLE_LIST*)ptr)->master_had_triggers;
+ }
+ }
+
+#ifdef HAVE_QUERY_CACHE
+#ifdef WITH_WSREP
+ /*
+ Moved invalidation right before the call to rows_event_stmt_cleanup(),
+ to avoid query cache being polluted with stale entries,
+ */
+ if (! (WSREP(thd) && wsrep_thd_is_applying(thd)))
+ {
+#endif /* WITH_WSREP */
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+#ifdef WITH_WSREP
+ }
+#endif /* WITH_WSREP */
+#endif
+ }
+
+ table= m_table= rgi->m_table_map.get_table(m_table_id);
+
+ DBUG_PRINT("debug", ("m_table:%p, m_table_id: %llu%s",
+ m_table, m_table_id,
+ table && master_had_triggers ?
+ " (master had triggers)" : ""));
+ if (table)
+ {
+ master_had_triggers= table->master_had_triggers;
+ bool transactional_table= table->file->has_transactions();
+ /*
+ table == NULL means that this table should not be replicated
+ (this was set up by Table_map_log_event::do_apply_event()
+ which tested replicate-* rules).
+ */
+
+ /*
+ It's not needed to set_time() but
+ 1) it continues the property that "Time" in SHOW PROCESSLIST shows how
+ much slave is behind
+ 2) it will be needed when we allow replication from a table with no
+ TIMESTAMP column to a table with one.
+ So we call set_time(), like in SBR. Presently it changes nothing.
+ */
+ thd->set_time(when, when_sec_part);
+
+ if (m_width == table->s->fields && bitmap_is_set_all(&m_cols))
+ set_flags(COMPLETE_ROWS_F);
+
+ /*
+ Set tables write and read sets.
+
+ Read_set contains all slave columns (in case we are going to fetch
+ a complete record from slave)
+
+ Write_set equals the m_cols bitmap sent from master but it can be
+ longer if slave has extra columns.
+ */
+
+ DBUG_PRINT_BITSET("debug", "Setting table's read_set from: %s", &m_cols);
+
+ bitmap_set_all(table->read_set);
+ if (get_general_type_code() == DELETE_ROWS_EVENT ||
+ get_general_type_code() == UPDATE_ROWS_EVENT)
+ bitmap_intersect(table->read_set,&m_cols);
+
+ bitmap_set_all(table->write_set);
+ table->rpl_write_set= table->write_set;
+
+ /* WRITE ROWS EVENTS store the bitmap in m_cols instead of m_cols_ai */
+ MY_BITMAP *after_image= ((get_general_type_code() == UPDATE_ROWS_EVENT) ?
+ &m_cols_ai : &m_cols);
+ bitmap_intersect(table->write_set, after_image);
+
+ this->slave_exec_mode= slave_exec_mode_options; // fix the mode
+
+ // Do event specific preparations
+ error= do_before_row_operations(rli);
+
+ /*
+ Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc
+ Don't allow generation of auto_increment value when processing
+ rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. The exception
+ to this rule happens when the auto_inc column exists on some
+ extra columns on the slave. In that case, do not force
+ MODE_NO_AUTO_VALUE_ON_ZERO.
+ */
+ sql_mode_t saved_sql_mode= thd->variables.sql_mode;
+ if (!is_auto_inc_in_extra_columns())
+ thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO;
+
+ // row processing loop
+
+ /*
+ set the initial time of this ROWS statement if it was not done
+ before in some other ROWS event.
+ */
+ rgi->set_row_stmt_start_timestamp();
+
+ THD_STAGE_INFO(thd, stage_executing);
+ do
+ {
+ /* in_use can have been set to NULL in close_tables_for_reopen */
+ THD* old_thd= table->in_use;
+ if (!table->in_use)
+ table->in_use= thd;
+
+ error= do_exec_row(rgi);
+
+ if (unlikely(error))
+ DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
+ DBUG_ASSERT(error != HA_ERR_RECORD_DELETED);
+
+ table->in_use = old_thd;
+
+ if (unlikely(error))
+ {
+ int actual_error= convert_handler_error(error, thd, table);
+ bool idempotent_error= (idempotent_error_code(error) &&
+ (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT));
+ bool ignored_error= (idempotent_error == 0 ?
+ ignored_error_code(actual_error) : 0);
+
+#ifdef WITH_WSREP
+ if (WSREP(thd) && wsrep_ignored_error_code(this, actual_error))
+ {
+ idempotent_error= true;
+ thd->wsrep_has_ignored_error= true;
+ }
+#endif /* WITH_WSREP */
+ if (idempotent_error || ignored_error)
+ {
+ if (global_system_variables.log_warnings)
+ slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ thd->clear_error(1);
+ error= 0;
+ if (idempotent_error == 0)
+ break;
+ }
+ }
+
+ /*
+ If m_curr_row_end was not set during event execution (e.g., because
+ of errors) we can't proceed to the next row. If the error is transient
+ (i.e., error==0 at this point) we must call unpack_current_row() to set
+ m_curr_row_end.
+ */
+
+ DBUG_PRINT("info", ("curr_row: %p; curr_row_end: %p; rows_end:%p",
+ m_curr_row, m_curr_row_end, m_rows_end));
+
+ if (!m_curr_row_end && likely(!error))
+ error= unpack_current_row(rgi);
+
+ m_curr_row= m_curr_row_end;
+
+ if (likely(error == 0) && !transactional_table)
+ thd->transaction.all.modified_non_trans_table=
+ thd->transaction.stmt.modified_non_trans_table= TRUE;
+ } // row processing loop
+ while (error == 0 && (m_curr_row != m_rows_end));
+
+ /*
+ Restore the sql_mode after the rows event is processed.
+ */
+ thd->variables.sql_mode= saved_sql_mode;
+
+ {/**
+ The following failure injecion works in cooperation with tests
+ setting @@global.debug= 'd,stop_slave_middle_group'.
+ The sql thread receives the killed status and will proceed
+ to shutdown trying to finish incomplete events group.
+ */
+ DBUG_EXECUTE_IF("stop_slave_middle_group",
+ if (thd->transaction.all.modified_non_trans_table)
+ const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
+ }
+
+ if (unlikely(error= do_after_row_operations(rli, error)) &&
+ ignored_error_code(convert_handler_error(error, thd, table)))
+ {
+
+ if (global_system_variables.log_warnings)
+ slave_rows_error_report(WARNING_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ thd->clear_error(1);
+ error= 0;
+ }
+ } // if (table)
+
+
+ if (unlikely(error))
+ {
+ slave_rows_error_report(ERROR_LEVEL, error, rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ /*
+ @todo We should probably not call
+ reset_current_stmt_binlog_format_row() from here.
+
+ Note: this applies to log_event_old.cc too.
+ /Sven
+ */
+ thd->reset_current_stmt_binlog_format_row();
+ thd->is_slave_error= 1;
+ /* remove trigger's tables */
+ goto err;
+ }
+
+ /* remove trigger's tables */
+ if (slave_run_triggers_for_rbr)
+ restore_empty_query_table_list(thd->lex);
+
+#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
+ if (WSREP(thd) && wsrep_thd_is_applying(thd))
+ {
+ query_cache.invalidate_locked_for_write(thd, rgi->tables_to_lock);
+ }
+#endif /* WITH_WSREP && HAVE_QUERY_CACHE */
+
+ if (unlikely(get_flags(STMT_END_F) &&
+ (error= rows_event_stmt_cleanup(rgi, thd))))
+ slave_rows_error_report(ERROR_LEVEL,
+ thd->is_error() ? 0 : error,
+ rgi, thd, table,
+ get_type_str(),
+ RPL_LOG_NAME, log_pos);
+ DBUG_RETURN(error);
+
+err:
+ if (slave_run_triggers_for_rbr)
+ restore_empty_query_table_list(thd->lex);
+ rgi->slave_close_thread_tables(thd);
+ DBUG_RETURN(error);
+}
+
+Log_event::enum_skip_reason
+Rows_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1 and this event does not end a
+ statement, then we should not start executing on the next event.
+ Otherwise, we defer the decision to the normal skipping logic.
+ */
+ if (rgi->rli->slave_skip_counter == 1 && !get_flags(STMT_END_F))
+ return Log_event::EVENT_SKIP_IGNORE;
+ else
+ return Log_event::do_shall_skip(rgi);
+}
+
+/**
+ The function is called at Rows_log_event statement commit time,
+ normally from Rows_log_event::do_update_pos() and possibly from
+ Query_log_event::do_apply_event() of the COMMIT.
+ The function commits the last statement for engines, binlog and
+ releases resources have been allocated for the statement.
+
+ @retval 0 Ok.
+ @retval non-zero Error at the commit.
+ */
+
+static int rows_event_stmt_cleanup(rpl_group_info *rgi, THD * thd)
+{
+ int error;
+ DBUG_ENTER("rows_event_stmt_cleanup");
+
+ {
+ /*
+ This is the end of a statement or transaction, so close (and
+ unlock) the tables we opened when processing the
+ Table_map_log_event starting the statement.
+
+ OBSERVER. This will clear *all* mappings, not only those that
+ are open for the table. There is not good handle for on-close
+ actions for tables.
+
+ NOTE. Even if we have no table ('table' == 0) we still need to be
+ here, so that we increase the group relay log position. If we didn't, we
+ could have a group relay log position which lags behind "forever"
+ (assume the last master's transaction is ignored by the slave because of
+ replicate-ignore rules).
+ */
+ error= thd->binlog_flush_pending_rows_event(TRUE);
+
+ /*
+ If this event is not in a transaction, the call below will, if some
+ transactional storage engines are involved, commit the statement into
+ them and flush the pending event to binlog.
+ If this event is in a transaction, the call will do nothing, but a
+ Xid_log_event will come next which will, if some transactional engines
+ are involved, commit the transaction and flush the pending event to the
+ binlog.
+ If there was a deadlock the transaction should have been rolled back
+ already. So there should be no need to rollback the transaction.
+ */
+ DBUG_ASSERT(! thd->transaction_rollback_request);
+ error|= (int)(error ? trans_rollback_stmt(thd) : trans_commit_stmt(thd));
+
+ /*
+ Now what if this is not a transactional engine? we still need to
+ flush the pending event to the binlog; we did it with
+ thd->binlog_flush_pending_rows_event(). Note that we imitate
+ what is done for real queries: a call to
+ ha_autocommit_or_rollback() (sometimes only if involves a
+ transactional engine), and a call to be sure to have the pending
+ event flushed.
+ */
+
+ /*
+ @todo We should probably not call
+ reset_current_stmt_binlog_format_row() from here.
+
+ Note: this applies to log_event_old.cc too
+
+ Btw, the previous comment about transactional engines does not
+ seem related to anything that happens here.
+ /Sven
+ */
+ thd->reset_current_stmt_binlog_format_row();
+
+ /*
+ Reset modified_non_trans_table that we have set in
+ rows_log_event::do_apply_event()
+ */
+ if (!thd->in_multi_stmt_transaction_mode())
+ {
+ thd->transaction.all.modified_non_trans_table= 0;
+ thd->transaction.all.m_unsafe_rollback_flags&= ~THD_TRANS::DID_WAIT;
+ }
+
+ rgi->cleanup_context(thd, 0);
+ }
+ DBUG_RETURN(error);
+}
+
+/**
+ The method either increments the relay log position or
+ commits the current statement and increments the master group
+ possition if the event is STMT_END_F flagged and
+ the statement corresponds to the autocommit query (i.e replicated
+ without wrapping in BEGIN/COMMIT)
+
+ @retval 0 Success
+ @retval non-zero Error in the statement commit
+ */
+int
+Rows_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ Relay_log_info *rli= rgi->rli;
+ int error= 0;
+ DBUG_ENTER("Rows_log_event::do_update_pos");
+
+ DBUG_PRINT("info", ("flags: %s",
+ get_flags(STMT_END_F) ? "STMT_END_F " : ""));
+
+ if (get_flags(STMT_END_F))
+ {
+ /*
+ Indicate that a statement is finished.
+ Step the group log position if we are not in a transaction,
+ otherwise increase the event log position.
+ */
+ error= rli->stmt_done(log_pos, thd, rgi);
+ /*
+ Clear any errors in thd->net.last_err*. It is not known if this is
+ needed or not. It is believed that any errors that may exist in
+ thd->net.last_err* are allowed. Examples of errors are "key not
+ found", which is produced in the test case rpl_row_conflicts.test
+ */
+ thd->clear_error();
+ }
+ else
+ {
+ rgi->inc_event_relay_log_pos();
+ }
+
+ DBUG_RETURN(error);
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+bool Rows_log_event::write_data_header()
+{
+ uchar buf[ROWS_HEADER_LEN_V2]; // No need to init the buffer
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
+ {
+ int4store(buf + 0, m_table_id);
+ int2store(buf + 4, m_flags);
+ return (write_data(buf, 6));
+ });
+ int6store(buf + RW_MAPID_OFFSET, m_table_id);
+ int2store(buf + RW_FLAGS_OFFSET, m_flags);
+ return write_data(buf, ROWS_HEADER_LEN);
+}
+
+bool Rows_log_event::write_data_body()
+{
+ /*
+ Note that this should be the number of *bits*, not the number of
+ bytes.
+ */
+ uchar sbuf[MAX_INT_WIDTH];
+ my_ptrdiff_t const data_size= m_rows_cur - m_rows_buf;
+ bool res= false;
+ uchar *const sbuf_end= net_store_length(sbuf, (size_t) m_width);
+ DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
+
+ DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
+ res= res || write_data(sbuf, (size_t) (sbuf_end - sbuf));
+
+ DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
+ res= res || write_data((uchar*)m_cols.bitmap, no_bytes_in_map(&m_cols));
+ /*
+ TODO[refactor write]: Remove the "down cast" here (and elsewhere).
+ */
+ if (get_general_type_code() == UPDATE_ROWS_EVENT)
+ {
+ DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ res= res || write_data((uchar*)m_cols_ai.bitmap,
+ no_bytes_in_map(&m_cols_ai));
+ }
+ DBUG_DUMP("rows", m_rows_buf, data_size);
+ res= res || write_data(m_rows_buf, (size_t) data_size);
+
+ return res;
+
+}
+
+bool Rows_log_event::write_compressed()
+{
+ uchar *m_rows_buf_tmp = m_rows_buf;
+ uchar *m_rows_cur_tmp = m_rows_cur;
+ bool ret = true;
+ uint32 comlen, alloc_size;
+ comlen= alloc_size= binlog_get_compress_len((uint32)(m_rows_cur_tmp - m_rows_buf_tmp));
+ m_rows_buf = (uchar *)my_safe_alloca(alloc_size);
+ if(m_rows_buf &&
+ !binlog_buf_compress((const char *)m_rows_buf_tmp, (char *)m_rows_buf,
+ (uint32)(m_rows_cur_tmp - m_rows_buf_tmp), &comlen))
+ {
+ m_rows_cur= comlen + m_rows_buf;
+ ret= Log_event::write();
+ }
+ my_safe_afree(m_rows_buf, alloc_size);
+ m_rows_buf= m_rows_buf_tmp;
+ m_rows_cur= m_rows_cur_tmp;
+ return ret;
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Rows_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ char const *const flagstr=
+ get_flags(STMT_END_F) ? " flags: STMT_END_F" : "";
+ size_t bytes= my_snprintf(buf, sizeof(buf),
+ "table_id: %llu%s", m_table_id, flagstr);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+
+/**************************************************************************
+ Annotate_rows_log_event member functions
+**************************************************************************/
+
+Annotate_rows_log_event::Annotate_rows_log_event(THD *thd,
+ bool using_trans,
+ bool direct)
+ : Log_event(thd, 0, using_trans),
+ m_save_thd_query_txt(0),
+ m_save_thd_query_len(0),
+ m_saved_thd_query(false),
+ m_used_query_txt(0)
+{
+ m_query_txt= thd->query();
+ m_query_len= thd->query_length();
+ if (direct)
+ cache_type= Log_event::EVENT_NO_CACHE;
+}
+
+
+bool Annotate_rows_log_event::write_data_header()
+{
+ return 0;
+}
+
+
+bool Annotate_rows_log_event::write_data_body()
+{
+ return write_data(m_query_txt, m_query_len);
+}
+
+
+#if defined(HAVE_REPLICATION)
+void Annotate_rows_log_event::pack_info(Protocol* protocol)
+{
+ if (m_query_txt && m_query_len)
+ protocol->store(m_query_txt, m_query_len, &my_charset_bin);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Annotate_rows_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ rgi->free_annotate_event();
+ m_save_thd_query_txt= thd->query();
+ m_save_thd_query_len= thd->query_length();
+ m_saved_thd_query= true;
+ m_used_query_txt= 1;
+ thd->set_query(m_query_txt, m_query_len);
+ return 0;
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int Annotate_rows_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+Log_event::enum_skip_reason
+Annotate_rows_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ return continue_group(rgi);
+}
+#endif
+
+/**************************************************************************
+ Table_map_log_event member functions and support functions
+**************************************************************************/
+
+/**
+ Save the field metadata based on the real_type of the field.
+ The metadata saved depends on the type of the field. Some fields
+ store a single byte for pack_length() while others store two bytes
+ for field_length (max length).
+
+ @retval 0 Ok.
+
+ @todo
+ We may want to consider changing the encoding of the information.
+ Currently, the code attempts to minimize the number of bytes written to
+ the tablemap. There are at least two other alternatives; 1) using
+ net_store_length() to store the data allowing it to choose the number of
+ bytes that are appropriate thereby making the code much easier to
+ maintain (only 1 place to change the encoding), or 2) use a fixed number
+ of bytes for each field. The problem with option 1 is that net_store_length()
+ will use one byte if the value < 251, but 3 bytes if it is > 250. Thus,
+ for fields like CHAR which can be no larger than 255 characters, the method
+ will use 3 bytes when the value is > 250. Further, every value that is
+ encoded using 2 parts (e.g., pack_length, field_length) will be numerically
+ > 250 therefore will use 3 bytes for eah value. The problem with option 2
+ is less wasteful for space but does waste 1 byte for every field that does
+ not encode 2 parts.
+*/
+int Table_map_log_event::save_field_metadata()
+{
+ DBUG_ENTER("Table_map_log_event::save_field_metadata");
+ int index= 0;
+ for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
+ {
+ DBUG_PRINT("debug", ("field_type: %d", m_coltype[i]));
+ index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]);
+ }
+ DBUG_RETURN(index);
+}
+
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ Mats says tbl->s lives longer than this event so it's ok to copy pointers
+ (tbl->s->db etc) and not pointer content.
+ */
+Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
+ bool is_transactional)
+ : Log_event(thd, 0, is_transactional),
+ m_table(tbl),
+ m_dbnam(tbl->s->db.str),
+ m_dblen(m_dbnam ? tbl->s->db.length : 0),
+ m_tblnam(tbl->s->table_name.str),
+ m_tbllen(tbl->s->table_name.length),
+ m_colcnt(tbl->s->fields),
+ m_memory(NULL),
+ m_table_id(tid),
+ m_flags(TM_BIT_LEN_EXACT_F),
+ m_data_size(0),
+ m_field_metadata(0),
+ m_field_metadata_size(0),
+ m_null_bits(0),
+ m_meta_memory(NULL)
+{
+ uchar cbuf[MAX_INT_WIDTH];
+ uchar *cbuf_end;
+ DBUG_ENTER("Table_map_log_event::Table_map_log_event(TABLE)");
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ /*
+ In TABLE_SHARE, "db" and "table_name" are 0-terminated (see this comment in
+ table.cc / alloc_table_share():
+ Use the fact the key is db/0/table_name/0
+ As we rely on this let's assert it.
+ */
+ DBUG_ASSERT((tbl->s->db.str == 0) ||
+ (tbl->s->db.str[tbl->s->db.length] == 0));
+ DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0);
+
+
+ m_data_size= TABLE_MAP_HEADER_LEN;
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
+ m_data_size+= m_dblen + 2; // Include length and terminating \0
+ m_data_size+= m_tbllen + 2; // Include length and terminating \0
+ cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
+ m_data_size+= (cbuf_end - cbuf) + m_colcnt; // COLCNT and column types
+
+ if (tbl->triggers)
+ m_flags|= TM_BIT_HAS_TRIGGERS_F;
+
+ /* If malloc fails, caught in is_valid() */
+ if ((m_memory= (uchar*) my_malloc(m_colcnt, MYF(MY_WME))))
+ {
+ m_coltype= reinterpret_cast<uchar*>(m_memory);
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ m_coltype[i]= m_table->field[i]->binlog_type();
+ }
+
+ /*
+ Calculate a bitmap for the results of maybe_null() for all columns.
+ The bitmap is used to determine when there is a column from the master
+ that is not on the slave and is null and thus not in the row data during
+ replication.
+ */
+ uint num_null_bytes= (m_table->s->fields + 7) / 8;
+ m_data_size+= num_null_bytes;
+ m_meta_memory= (uchar *)my_multi_malloc(MYF(MY_WME),
+ &m_null_bits, num_null_bytes,
+ &m_field_metadata, (m_colcnt * 2),
+ NULL);
+
+ bzero(m_field_metadata, (m_colcnt * 2));
+
+ /*
+ Create an array for the field metadata and store it.
+ */
+ m_field_metadata_size= save_field_metadata();
+ DBUG_ASSERT(m_field_metadata_size <= (m_colcnt * 2));
+
+ /*
+ Now set the size of the data to the size of the field metadata array
+ plus one or three bytes (see pack.c:net_store_length) for number of
+ elements in the field metadata array.
+ */
+ if (m_field_metadata_size < 251)
+ m_data_size+= m_field_metadata_size + 1;
+ else
+ m_data_size+= m_field_metadata_size + 3;
+
+ bzero(m_null_bits, num_null_bytes);
+ for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
+ if (m_table->field[i]->maybe_null())
+ m_null_bits[(i / 8)]+= 1 << (i % 8);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Return value is an error code, one of:
+
+ -1 Failure to open table [from open_tables()]
+ 0 Success
+ 1 No room for more tables [from set_table()]
+ 2 Out of memory [from set_table()]
+ 3 Wrong table definition
+ 4 Daisy-chaining RBR with SBR not possible
+ */
+
+#if defined(HAVE_REPLICATION)
+
+enum enum_tbl_map_status
+{
+ /* no duplicate identifier found */
+ OK_TO_PROCESS= 0,
+
+ /* this table map must be filtered out */
+ FILTERED_OUT= 1,
+
+ /* identifier mapping table with different properties */
+ SAME_ID_MAPPING_DIFFERENT_TABLE= 2,
+
+ /* a duplicate identifier was found mapping the same table */
+ SAME_ID_MAPPING_SAME_TABLE= 3
+};
+
+/*
+ Checks if this table map event should be processed or not. First
+ it checks the filtering rules, and then looks for duplicate identifiers
+ in the existing list of rli->tables_to_lock.
+
+ It checks that there hasn't been any corruption by verifying that there
+ are no duplicate entries with different properties.
+
+ In some cases, some binary logs could get corrupted, showing several
+ tables mapped to the same table_id, 0 (see: BUG#56226). Thus we do this
+ early sanity check for such cases and avoid that the server crashes
+ later.
+
+ In some corner cases, the master logs duplicate table map events, i.e.,
+ same id, same database name, same table name (see: BUG#37137). This is
+ different from the above as it's the same table that is mapped again
+ to the same identifier. Thus we cannot just check for same ids and
+ assume that the event is corrupted we need to check every property.
+
+ NOTE: in the event that BUG#37137 ever gets fixed, this extra check
+ will still be valid because we would need to support old binary
+ logs anyway.
+
+ @param rli The relay log info reference.
+ @param table_list A list element containing the table to check against.
+ @return OK_TO_PROCESS
+ if there was no identifier already in rli->tables_to_lock
+
+ FILTERED_OUT
+ if the event is filtered according to the filtering rules
+
+ SAME_ID_MAPPING_DIFFERENT_TABLE
+ if the same identifier already maps a different table in
+ rli->tables_to_lock
+
+ SAME_ID_MAPPING_SAME_TABLE
+ if the same identifier already maps the same table in
+ rli->tables_to_lock.
+*/
+static enum_tbl_map_status
+check_table_map(rpl_group_info *rgi, RPL_TABLE_LIST *table_list)
+{
+ DBUG_ENTER("check_table_map");
+ enum_tbl_map_status res= OK_TO_PROCESS;
+ Relay_log_info *rli= rgi->rli;
+ if ((rgi->thd->slave_thread /* filtering is for slave only */ ||
+ IF_WSREP((WSREP(rgi->thd) && rgi->thd->wsrep_applier), 0)) &&
+ (!rli->mi->rpl_filter->db_ok(table_list->db.str) ||
+ (rli->mi->rpl_filter->is_on() && !rli->mi->rpl_filter->tables_ok("", table_list))))
+ res= FILTERED_OUT;
+ else
+ {
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rgi->tables_to_lock);
+ for(uint i=0 ; ptr && (i< rgi->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local), i++)
+ {
+ if (ptr->table_id == table_list->table_id)
+ {
+
+ if (cmp(&ptr->db, &table_list->db) ||
+ cmp(&ptr->alias, &table_list->table_name) ||
+ ptr->lock_type != TL_WRITE) // the ::do_apply_event always sets TL_WRITE
+ res= SAME_ID_MAPPING_DIFFERENT_TABLE;
+ else
+ res= SAME_ID_MAPPING_SAME_TABLE;
+
+ break;
+ }
+ }
+ }
+
+ DBUG_PRINT("debug", ("check of table map ended up with: %u", res));
+
+ DBUG_RETURN(res);
+}
+
+int Table_map_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ RPL_TABLE_LIST *table_list;
+ char *db_mem, *tname_mem, *ptr;
+ size_t dummy_len, db_mem_length, tname_mem_length;
+ void *memory;
+ Rpl_filter *filter;
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Table_map_log_event::do_apply_event(Relay_log_info*)");
+
+ /* Step the query id to mark what columns that are actually used. */
+ thd->set_query_id(next_query_id());
+
+ if (!(memory= my_multi_malloc(MYF(MY_WME),
+ &table_list, (uint) sizeof(RPL_TABLE_LIST),
+ &db_mem, (uint) NAME_LEN + 1,
+ &tname_mem, (uint) NAME_LEN + 1,
+ NullS)))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+
+ db_mem_length= strmov(db_mem, m_dbnam) - db_mem;
+ tname_mem_length= strmov(tname_mem, m_tblnam) - tname_mem;
+ if (lower_case_table_names)
+ {
+ my_casedn_str(files_charset_info, (char*)tname_mem);
+ my_casedn_str(files_charset_info, (char*)db_mem);
+ }
+
+ /* call from mysql_client_binlog_statement() will not set rli->mi */
+ filter= rgi->thd->slave_thread ? rli->mi->rpl_filter : global_rpl_filter;
+
+ /* rewrite rules changed the database */
+ if (((ptr= (char*) filter->get_rewrite_db(db_mem, &dummy_len)) != db_mem))
+ db_mem_length= strmov(db_mem, ptr) - db_mem;
+
+ LEX_CSTRING tmp_db_name= {db_mem, db_mem_length };
+ LEX_CSTRING tmp_tbl_name= {tname_mem, tname_mem_length };
+
+ table_list->init_one_table(&tmp_db_name, &tmp_tbl_name, 0, TL_WRITE);
+ table_list->table_id= DBUG_EVALUATE_IF("inject_tblmap_same_id_maps_diff_table", 0, m_table_id);
+ table_list->updating= 1;
+ table_list->required_type= TABLE_TYPE_NORMAL;
+
+ DBUG_PRINT("debug", ("table: %s is mapped to %llu",
+ table_list->table_name.str,
+ table_list->table_id));
+ table_list->master_had_triggers= ((m_flags & TM_BIT_HAS_TRIGGERS_F) ? 1 : 0);
+ DBUG_PRINT("debug", ("table->master_had_triggers=%d",
+ (int)table_list->master_had_triggers));
+
+ enum_tbl_map_status tblmap_status= check_table_map(rgi, table_list);
+ if (tblmap_status == OK_TO_PROCESS)
+ {
+ DBUG_ASSERT(thd->lex->query_tables != table_list);
+
+ /*
+ Use placement new to construct the table_def instance in the
+ memory allocated for it inside table_list.
+
+ The memory allocated by the table_def structure (i.e., not the
+ memory allocated *for* the table_def structure) is released
+ inside Relay_log_info::clear_tables_to_lock() by calling the
+ table_def destructor explicitly.
+ */
+ new (&table_list->m_tabledef)
+ table_def(m_coltype, m_colcnt,
+ m_field_metadata, m_field_metadata_size,
+ m_null_bits, m_flags);
+ table_list->m_tabledef_valid= TRUE;
+ table_list->m_conv_table= NULL;
+ table_list->open_type= OT_BASE_ONLY;
+
+ /*
+ We record in the slave's information that the table should be
+ locked by linking the table into the list of tables to lock.
+ */
+ table_list->next_global= table_list->next_local= rgi->tables_to_lock;
+ rgi->tables_to_lock= table_list;
+ rgi->tables_to_lock_count++;
+ /* 'memory' is freed in clear_tables_to_lock */
+ }
+ else // FILTERED_OUT, SAME_ID_MAPPING_*
+ {
+ /*
+ If mapped already but with different properties, we raise an
+ error.
+ If mapped already but with same properties we skip the event.
+ If filtered out we skip the event.
+
+ In all three cases, we need to free the memory previously
+ allocated.
+ */
+ if (tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE)
+ {
+ /*
+ Something bad has happened. We need to stop the slave as strange things
+ could happen if we proceed: slave crash, wrong table being updated, ...
+ As a consequence we push an error in this case.
+ */
+
+ char buf[256];
+
+ my_snprintf(buf, sizeof(buf),
+ "Found table map event mapping table id %u which "
+ "was already mapped but with different settings.",
+ table_list->table_id);
+
+ if (thd->slave_thread)
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_FATAL_ERROR), buf);
+ else
+ /*
+ For the cases in which a 'BINLOG' statement is set to
+ execute in a user session
+ */
+ my_error(ER_SLAVE_FATAL_ERROR, MYF(0), buf);
+ }
+
+ my_free(memory);
+ }
+
+ DBUG_RETURN(tblmap_status == SAME_ID_MAPPING_DIFFERENT_TABLE);
+}
+
+Log_event::enum_skip_reason
+Table_map_log_event::do_shall_skip(rpl_group_info *rgi)
+{
+ /*
+ If the slave skip counter is 1, then we should not start executing
+ on the next event.
+ */
+ return continue_group(rgi);
+}
+
+int Table_map_log_event::do_update_pos(rpl_group_info *rgi)
+{
+ rgi->inc_event_relay_log_pos();
+ return 0;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+bool Table_map_log_event::write_data_header()
+{
+ DBUG_ASSERT(m_table_id != ~0ULL);
+ uchar buf[TABLE_MAP_HEADER_LEN];
+ DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master",
+ {
+ int4store(buf + 0, m_table_id);
+ int2store(buf + 4, m_flags);
+ return (write_data(buf, 6));
+ });
+ int6store(buf + TM_MAPID_OFFSET, m_table_id);
+ int2store(buf + TM_FLAGS_OFFSET, m_flags);
+ return write_data(buf, TABLE_MAP_HEADER_LEN);
+}
+
+bool Table_map_log_event::write_data_body()
+{
+ DBUG_ASSERT(m_dbnam != NULL);
+ DBUG_ASSERT(m_tblnam != NULL);
+ /* We use only one byte per length for storage in event: */
+ DBUG_ASSERT(m_dblen <= MY_MIN(NAME_LEN, 255));
+ DBUG_ASSERT(m_tbllen <= MY_MIN(NAME_LEN, 255));
+
+ uchar const dbuf[]= { (uchar) m_dblen };
+ uchar const tbuf[]= { (uchar) m_tbllen };
+
+ uchar cbuf[MAX_INT_WIDTH];
+ uchar *const cbuf_end= net_store_length(cbuf, (size_t) m_colcnt);
+ DBUG_ASSERT(static_cast<size_t>(cbuf_end - cbuf) <= sizeof(cbuf));
+
+ /*
+ Store the size of the field metadata.
+ */
+ uchar mbuf[MAX_INT_WIDTH];
+ uchar *const mbuf_end= net_store_length(mbuf, m_field_metadata_size);
+
+ return write_data(dbuf, sizeof(dbuf)) ||
+ write_data(m_dbnam, m_dblen+1) ||
+ write_data(tbuf, sizeof(tbuf)) ||
+ write_data(m_tblnam, m_tbllen+1) ||
+ write_data(cbuf, (size_t) (cbuf_end - cbuf)) ||
+ write_data(m_coltype, m_colcnt) ||
+ write_data(mbuf, (size_t) (mbuf_end - mbuf)) ||
+ write_data(m_field_metadata, m_field_metadata_size),
+ write_data(m_null_bits, (m_colcnt + 7) / 8);
+ }
+
+
+#if defined(HAVE_REPLICATION)
+/*
+ Print some useful information for the SHOW BINARY LOG information
+ field.
+ */
+
+void Table_map_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes= my_snprintf(buf, sizeof(buf),
+ "table_id: %llu (%s.%s)",
+ m_table_id, m_dbnam, m_tblnam);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+#endif
+
+
+/**************************************************************************
+ Write_rows_log_event member functions
+**************************************************************************/
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+Write_rows_log_event::Write_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ :Rows_log_event(thd_arg, tbl_arg, tid_arg, tbl_arg->rpl_write_set,
+ is_transactional, WRITE_ROWS_EVENT_V1)
+{
+}
+
+Write_rows_compressed_log_event::Write_rows_compressed_log_event(
+ THD *thd_arg,
+ TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ : Write_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
+{
+ m_type = WRITE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Write_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+
+#if defined(HAVE_REPLICATION)
+int
+Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ int error= 0;
+
+ /*
+ Increment the global status insert count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_INSERT]);
+
+ /**
+ todo: to introduce a property for the event (handler?) which forces
+ applying the event in the replace (idempotent) fashion.
+ */
+ if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
+ {
+ /*
+ We are using REPLACE semantics and not INSERT IGNORE semantics
+ when writing rows, that is: new rows replace old rows. We need to
+ inform the storage engine that it should use this behaviour.
+ */
+
+ /* Tell the storage engine that we are using REPLACE semantics. */
+ thd->lex->duplicates= DUP_REPLACE;
+
+ /*
+ Pretend we're executing a REPLACE command: this is needed for
+ InnoDB since it is not (properly) checking the lex->duplicates flag.
+ */
+ thd->lex->sql_command= SQLCOM_REPLACE;
+ /*
+ Do not raise the error flag in case of hitting to an unique attribute
+ */
+ m_table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ /*
+ The following is needed in case if we have AFTER DELETE triggers.
+ */
+ m_table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
+ m_table->file->extra(HA_EXTRA_IGNORE_NO_KEY);
+ }
+ if (slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers )
+ m_table->prepare_triggers_for_insert_stmt_or_event();
+
+ /* Honor next number column if present */
+ m_table->next_number_field= m_table->found_next_number_field;
+ /*
+ * Fixed Bug#45999, In RBR, Store engine of Slave auto-generates new
+ * sequence numbers for auto_increment fields if the values of them are 0.
+ * If generateing a sequence number is decided by the values of
+ * table->auto_increment_field_not_null and SQL_MODE(if includes
+ * MODE_NO_AUTO_VALUE_ON_ZERO) in update_auto_increment function.
+ * SQL_MODE of slave sql thread is always consistency with master's.
+ * In RBR, auto_increment fields never are NULL, except if the auto_inc
+ * column exists only on the slave side (i.e., in an extra column
+ * on the slave's table).
+ */
+ if (!is_auto_inc_in_extra_columns())
+ m_table->auto_increment_field_not_null= TRUE;
+ else
+ {
+ /*
+ Here we have checked that there is an extra field
+ on this server's table that has an auto_inc column.
+
+ Mark that the auto_increment field is null and mark
+ the read and write set bits.
+
+ (There can only be one AUTO_INC column, it is always
+ indexed and it cannot have a DEFAULT value).
+ */
+ m_table->auto_increment_field_not_null= FALSE;
+ m_table->mark_auto_increment_column();
+ }
+
+ return error;
+}
+
+int
+Write_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ int local_error= 0;
+
+ /**
+ Clear the write_set bit for auto_inc field that only
+ existed on the destination table as an extra column.
+ */
+ if (is_auto_inc_in_extra_columns())
+ {
+ bitmap_clear_bit(m_table->rpl_write_set,
+ m_table->next_number_field->field_index);
+ bitmap_clear_bit(m_table->read_set,
+ m_table->next_number_field->field_index);
+
+ if (get_flags(STMT_END_F))
+ m_table->file->ha_release_auto_increment();
+ }
+ m_table->next_number_field=0;
+ m_table->auto_increment_field_not_null= FALSE;
+ if (slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT)
+ {
+ m_table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
+ m_table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
+ /*
+ resetting the extra with
+ table->file->extra(HA_EXTRA_NO_IGNORE_NO_KEY);
+ fires bug#27077
+ explanation: file->reset() performs this duty
+ ultimately. Still todo: fix
+ */
+ }
+ if (unlikely((local_error= m_table->file->ha_end_bulk_insert())))
+ {
+ m_table->file->print_error(local_error, MYF(0));
+ }
+ return error? error : local_error;
+}
+
+bool Rows_log_event::process_triggers(trg_event_type event,
+ trg_action_time_type time_type,
+ bool old_row_is_record1)
+{
+ bool result;
+ DBUG_ENTER("Rows_log_event::process_triggers");
+ m_table->triggers->mark_fields_used(event);
+ if (slave_run_triggers_for_rbr == SLAVE_RUN_TRIGGERS_FOR_RBR_YES)
+ {
+ tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */
+ result= m_table->triggers->process_triggers(thd, event,
+ time_type, old_row_is_record1);
+ reenable_binlog(thd);
+ }
+ else
+ result= m_table->triggers->process_triggers(thd, event,
+ time_type, old_row_is_record1);
+
+ DBUG_RETURN(result);
+}
+/*
+ Check if there are more UNIQUE keys after the given key.
+*/
+static int
+last_uniq_key(TABLE *table, uint keyno)
+{
+ while (++keyno < table->s->keys)
+ if (table->key_info[keyno].flags & HA_NOSAME)
+ return 0;
+ return 1;
+}
+
+/**
+ Check if an error is a duplicate key error.
+
+ This function is used to check if an error code is one of the
+ duplicate key error, i.e., and error code for which it is sensible
+ to do a <code>get_dup_key()</code> to retrieve the duplicate key.
+
+ @param errcode The error code to check.
+
+ @return <code>true</code> if the error code is such that
+ <code>get_dup_key()</code> will return true, <code>false</code>
+ otherwise.
+ */
+bool
+is_duplicate_key_error(int errcode)
+{
+ switch (errcode)
+ {
+ case HA_ERR_FOUND_DUPP_KEY:
+ case HA_ERR_FOUND_DUPP_UNIQUE:
+ return true;
+ }
+ return false;
+}
+
+/**
+ Write the current row into event's table.
+
+ The row is located in the row buffer, pointed by @c m_curr_row member.
+ Number of columns of the row is stored in @c m_width member (it can be
+ different from the number of columns in the table to which we insert).
+ Bitmap @c m_cols indicates which columns are present in the row. It is assumed
+ that event's table is already open and pointed by @c m_table.
+
+ If the same record already exists in the table it can be either overwritten
+ or an error is reported depending on the value of @c overwrite flag
+ (error reporting not yet implemented). Note that the matching record can be
+ different from the row we insert if we use primary keys to identify records in
+ the table.
+
+ The row to be inserted can contain values only for selected columns. The
+ missing columns are filled with default values using @c prepare_record()
+ function. If a matching record is found in the table and @c overwritte is
+ true, the missing columns are taken from it.
+
+ @param rli Relay log info (needed for row unpacking).
+ @param overwrite
+ Shall we overwrite if the row already exists or signal
+ error (currently ignored).
+
+ @returns Error code on failure, 0 on success.
+
+ This method, if successful, sets @c m_curr_row_end pointer to point at the
+ next row in the rows buffer. This is done when unpacking the row to be
+ inserted.
+
+ @note If a matching record is found, it is either updated using
+ @c ha_update_row() or first deleted and then new record written.
+*/
+
+int
+Rows_log_event::write_row(rpl_group_info *rgi,
+ const bool overwrite)
+{
+ DBUG_ENTER("write_row");
+ DBUG_ASSERT(m_table != NULL && thd != NULL);
+
+ TABLE *table= m_table; // pointer to event's table
+ int error;
+ int UNINIT_VAR(keynum);
+ const bool invoke_triggers=
+ slave_run_triggers_for_rbr && !master_had_triggers && table->triggers;
+ auto_afree_ptr<char> key(NULL);
+
+ prepare_record(table, m_width, true);
+
+ /* unpack row into table->record[0] */
+ if (unlikely((error= unpack_current_row(rgi))))
+ {
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ if (m_curr_row == m_rows_buf && !invoke_triggers)
+ {
+ /*
+ This table has no triggers so we can do bulk insert.
+
+ This is the first row to be inserted, we estimate the rows with
+ the size of the first row and use that value to initialize
+ storage engine for bulk insertion.
+ */
+ /* this is the first row to be inserted, we estimate the rows with
+ the size of the first row and use that value to initialize
+ storage engine for bulk insertion */
+ DBUG_ASSERT(!(m_curr_row > m_curr_row_end));
+ ha_rows estimated_rows= 0;
+ if (m_curr_row < m_curr_row_end)
+ estimated_rows= (m_rows_end - m_curr_row) / (m_curr_row_end - m_curr_row);
+ else if (m_curr_row == m_curr_row_end)
+ estimated_rows= 1;
+
+ table->file->ha_start_bulk_insert(estimated_rows);
+ }
+
+ /*
+ Explicitly set the auto_inc to null to make sure that
+ it gets an auto_generated value.
+ */
+ if (is_auto_inc_in_extra_columns())
+ m_table->next_number_field->set_null();
+
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_PRINT_BITSET("debug", "rpl_write_set: %s", table->rpl_write_set);
+ DBUG_PRINT_BITSET("debug", "read_set: %s", table->read_set);
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_BEFORE, TRUE)))
+ {
+ DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
+ }
+
+ // Handle INSERT.
+ if (table->versioned(VERS_TIMESTAMP))
+ {
+ ulong sec_part;
+ bitmap_set_bit(table->read_set, table->vers_start_field()->field_index);
+ // Check whether a row came from unversioned table and fix vers fields.
+ if (table->vers_start_field()->get_timestamp(&sec_part) == 0 && sec_part == 0)
+ table->vers_update_fields();
+ }
+
+ /*
+ Try to write record. If a corresponding record already exists in the table,
+ we try to change it using ha_update_row() if possible. Otherwise we delete
+ it and repeat the whole process again.
+
+ TODO: Add safety measures against infinite looping.
+ */
+
+ if (table->s->sequence)
+ error= update_sequence();
+ else while (unlikely(error= table->file->ha_write_row(table->record[0])))
+ {
+ if (error == HA_ERR_LOCK_DEADLOCK ||
+ error == HA_ERR_LOCK_WAIT_TIMEOUT ||
+ (keynum= table->file->get_dup_key(error)) < 0 ||
+ !overwrite)
+ {
+ DBUG_PRINT("info",("get_dup_key returns %d)", keynum));
+ /*
+ Deadlock, waiting for lock or just an error from the handler
+ such as HA_ERR_FOUND_DUPP_KEY when overwrite is false.
+ Retrieval of the duplicate key number may fail
+ - either because the error was not "duplicate key" error
+ - or because the information which key is not available
+ */
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ /*
+ We need to retrieve the old row into record[1] to be able to
+ either update or delete the offending record. We either:
+
+ - use rnd_pos() with a row-id (available as dupp_row) to the
+ offending row, if that is possible (MyISAM and Blackhole), or else
+
+ - use index_read_idx() with the key that is duplicated, to
+ retrieve the offending row.
+ */
+ if (table->file->ha_table_flags() & HA_DUPLICATE_POS)
+ {
+ DBUG_PRINT("info",("Locating offending record using rnd_pos()"));
+
+ if ((error= table->file->ha_rnd_init_with_error(0)))
+ {
+ DBUG_RETURN(error);
+ }
+
+ error= table->file->ha_rnd_pos(table->record[1], table->file->dup_ref);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("rnd_pos() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ table->file->ha_rnd_end();
+ }
+ else
+ {
+ DBUG_PRINT("info",("Locating offending record using index_read_idx()"));
+
+ if (table->file->extra(HA_EXTRA_FLUSH_CACHE))
+ {
+ DBUG_PRINT("info",("Error when setting HA_EXTRA_FLUSH_CACHE"));
+ DBUG_RETURN(my_errno);
+ }
+
+ if (key.get() == NULL)
+ {
+ key.assign(static_cast<char*>(my_alloca(table->s->max_unique_length)));
+ if (key.get() == NULL)
+ {
+ DBUG_PRINT("info",("Can't allocate key buffer"));
+ DBUG_RETURN(ENOMEM);
+ }
+ }
+
+ key_copy((uchar*)key.get(), table->record[0], table->key_info + keynum,
+ 0);
+ error= table->file->ha_index_read_idx_map(table->record[1], keynum,
+ (const uchar*)key.get(),
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("index_read_idx() returns %s", HA_ERR(error)));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+
+ /*
+ Now, record[1] should contain the offending row. That
+ will enable us to update it or, alternatively, delete it (so
+ that we can insert the new row afterwards).
+ */
+
+ /*
+ If row is incomplete we will use the record found to fill
+ missing columns.
+ */
+ if (!get_flags(COMPLETE_ROWS_F))
+ {
+ restore_record(table,record[1]);
+ error= unpack_current_row(rgi);
+ }
+
+ DBUG_PRINT("debug",("preparing for update: before and after image"));
+ DBUG_DUMP("record[1] (before)", table->record[1], table->s->reclength);
+ DBUG_DUMP("record[0] (after)", table->record[0], table->s->reclength);
+
+ /*
+ REPLACE is defined as either INSERT or DELETE + INSERT. If
+ possible, we can replace it with an UPDATE, but that will not
+ work on InnoDB if FOREIGN KEY checks are necessary.
+
+ I (Matz) am not sure of the reason for the last_uniq_key()
+ check as, but I'm guessing that it's something along the
+ following lines.
+
+ Suppose that we got the duplicate key to be a key that is not
+ the last unique key for the table and we perform an update:
+ then there might be another key for which the unique check will
+ fail, so we're better off just deleting the row and inserting
+ the correct row.
+
+ Additionally we don't use UPDATE if rbr triggers should be invoked -
+ when triggers are used we want a simple and predictable execution path.
+ */
+ if (last_uniq_key(table, keynum) && !invoke_triggers &&
+ !table->file->referenced_by_foreign_key())
+ {
+ DBUG_PRINT("info",("Updating row using ha_update_row()"));
+ error= table->file->ha_update_row(table->record[1],
+ table->record[0]);
+ switch (error) {
+
+ case HA_ERR_RECORD_IS_THE_SAME:
+ DBUG_PRINT("info",("ignoring HA_ERR_RECORD_IS_THE_SAME error from"
+ " ha_update_row()"));
+ error= 0;
+
+ case 0:
+ break;
+
+ default:
+ DBUG_PRINT("info",("ha_update_row() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+ }
+ else
+ {
+ DBUG_PRINT("info",("Deleting offending row and trying to write new one again"));
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE,
+ TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ else
+ {
+ if (unlikely((error= table->file->ha_delete_row(table->record[1]))))
+ {
+ DBUG_PRINT("info",("ha_delete_row() returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER,
+ TRUE)))
+ DBUG_RETURN(HA_ERR_GENERIC); // in case if error is not set yet
+ }
+ /* Will retry ha_write_row() with the offending row removed. */
+ }
+ }
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_INSERT, TRG_ACTION_AFTER, TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+
+ DBUG_RETURN(error);
+}
+
+
+int Rows_log_event::update_sequence()
+{
+ TABLE *table= m_table; // pointer to event's table
+
+ if (!bitmap_is_set(table->rpl_write_set, MIN_VALUE_FIELD_NO))
+ {
+ /* This event come from a setval function executed on the master.
+ Update the sequence next_number and round, like we do with setval()
+ */
+ my_bitmap_map *old_map= dbug_tmp_use_all_columns(table,
+ table->read_set);
+ longlong nextval= table->field[NEXT_FIELD_NO]->val_int();
+ longlong round= table->field[ROUND_FIELD_NO]->val_int();
+ dbug_tmp_restore_column_map(table->read_set, old_map);
+
+ return table->s->sequence->set_value(table, nextval, round, 0) > 0;
+ }
+
+ /*
+ Update all fields in table and update the active sequence, like with
+ ALTER SEQUENCE
+ */
+ return table->file->ha_write_row(table->record[0]);
+}
+
+
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Write_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ DBUG_ASSERT(m_table != NULL);
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Write_rows_log_event::write_row()";
+ int error;
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Write_rows_log_event::write_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ error= write_row(rgi, slave_exec_mode == SLAVE_EXEC_MODE_IDEMPOTENT);
+ thd_proc_info(thd, tmp);
+
+ if (unlikely(error) && unlikely(!thd->is_error()))
+ {
+ DBUG_ASSERT(0);
+ my_error(ER_UNKNOWN_ERROR, MYF(0));
+ }
+
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+#if defined(HAVE_REPLICATION)
+uint8 Write_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_INSERT) | trg2bit(TRG_EVENT_UPDATE) |
+ trg2bit(TRG_EVENT_DELETE);
+}
+#endif
+
+/**************************************************************************
+ Delete_rows_log_event member functions
+**************************************************************************/
+
+#if defined(HAVE_REPLICATION)
+/*
+ Compares table->record[0] and table->record[1]
+
+ Returns TRUE if different.
+*/
+static bool record_compare(TABLE *table)
+{
+ bool result= FALSE;
+ /**
+ Compare full record only if:
+ - there are no blob fields (otherwise we would also need
+ to compare blobs contents as well);
+ - there are no varchar fields (otherwise we would also need
+ to compare varchar contents as well);
+ - there are no null fields, otherwise NULLed fields
+ contents (i.e., the don't care bytes) may show arbitrary
+ values, depending on how each engine handles internally.
+ */
+ if ((table->s->blob_fields +
+ table->s->varchar_fields +
+ table->s->null_fields) == 0)
+ {
+ result= cmp_record(table,record[1]);
+ goto record_compare_exit;
+ }
+
+ /* Compare null bits */
+ if (memcmp(table->null_flags,
+ table->null_flags+table->s->rec_buff_length,
+ table->s->null_bytes))
+ {
+ result= TRUE; // Diff in NULL value
+ goto record_compare_exit;
+ }
+
+ /* Compare fields */
+ for (Field **ptr=table->field ; *ptr ; ptr++)
+ {
+ if (table->versioned() && (*ptr)->vers_sys_field())
+ {
+ continue;
+ }
+ /**
+ We only compare field contents that are not null.
+ NULL fields (i.e., their null bits) were compared
+ earlier.
+ */
+ if (!(*(ptr))->is_null())
+ {
+ if ((*ptr)->cmp_binary_offset(table->s->rec_buff_length))
+ {
+ result= TRUE;
+ goto record_compare_exit;
+ }
+ }
+ }
+
+record_compare_exit:
+ return result;
+}
+
+
+/**
+ Find the best key to use when locating the row in @c find_row().
+
+ A primary key is preferred if it exists; otherwise a unique index is
+ preferred. Else we pick the index with the smalles rec_per_key value.
+
+ If a suitable key is found, set @c m_key, @c m_key_nr and @c m_key_info
+ member fields appropriately.
+
+ @returns Error code on failure, 0 on success.
+*/
+int Rows_log_event::find_key()
+{
+ uint i, best_key_nr, last_part;
+ KEY *key, *UNINIT_VAR(best_key);
+ ulong UNINIT_VAR(best_rec_per_key), tmp;
+ DBUG_ENTER("Rows_log_event::find_key");
+ DBUG_ASSERT(m_table);
+
+ best_key_nr= MAX_KEY;
+
+ /*
+ Keys are sorted so that any primary key is first, followed by unique keys,
+ followed by any other. So we will automatically pick the primary key if
+ it exists.
+ */
+ for (i= 0, key= m_table->key_info; i < m_table->s->keys; i++, key++)
+ {
+ if (!m_table->s->keys_in_use.is_set(i))
+ continue;
+ /*
+ We cannot use a unique key with NULL-able columns to uniquely identify
+ a row (but we can still select it for range scan below if nothing better
+ is available).
+ */
+ if ((key->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME)
+ {
+ best_key_nr= i;
+ best_key= key;
+ break;
+ }
+ /*
+ We can only use a non-unique key if it allows range scans (ie. skip
+ FULLTEXT indexes and such).
+ */
+ last_part= key->user_defined_key_parts - 1;
+ DBUG_PRINT("info", ("Index %s rec_per_key[%u]= %lu",
+ key->name.str, last_part, key->rec_per_key[last_part]));
+ if (!(m_table->file->index_flags(i, last_part, 1) & HA_READ_NEXT))
+ continue;
+
+ tmp= key->rec_per_key[last_part];
+ if (best_key_nr == MAX_KEY || (tmp > 0 && tmp < best_rec_per_key))
+ {
+ best_key_nr= i;
+ best_key= key;
+ best_rec_per_key= tmp;
+ }
+ }
+
+ if (best_key_nr == MAX_KEY)
+ {
+ m_key_info= NULL;
+ DBUG_RETURN(0);
+ }
+
+ // Allocate buffer for key searches
+ m_key= (uchar *) my_malloc(best_key->key_length, MYF(MY_WME));
+ if (m_key == NULL)
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ m_key_info= best_key;
+ m_key_nr= best_key_nr;
+
+ DBUG_RETURN(0);;
+}
+
+
+/*
+ Check if we are already spending too much time on this statement.
+ if we are, warn user that it might be because table does not have
+ a PK, but only if the warning was not printed before for this STMT.
+
+ @param type The event type code.
+ @param table_name The name of the table that the slave is
+ operating.
+ @param is_index_scan States whether the slave is doing an index scan
+ or not.
+ @param rli The relay metadata info.
+*/
+static inline
+void issue_long_find_row_warning(Log_event_type type,
+ const char *table_name,
+ bool is_index_scan,
+ rpl_group_info *rgi)
+{
+ if ((global_system_variables.log_warnings > 1 &&
+ !rgi->is_long_find_row_note_printed()))
+ {
+ ulonglong now= microsecond_interval_timer();
+ ulonglong stmt_ts= rgi->get_row_stmt_start_timestamp();
+
+ DBUG_EXECUTE_IF("inject_long_find_row_note",
+ stmt_ts-=(LONG_FIND_ROW_THRESHOLD*2*HRTIME_RESOLUTION););
+
+ longlong delta= (now - stmt_ts)/HRTIME_RESOLUTION;
+
+ if (delta > LONG_FIND_ROW_THRESHOLD)
+ {
+ rgi->set_long_find_row_note_printed();
+ const char* evt_type= LOG_EVENT_IS_DELETE_ROW(type) ? " DELETE" : "n UPDATE";
+ const char* scan_type= is_index_scan ? "scanning an index" : "scanning the table";
+
+ sql_print_information("The slave is applying a ROW event on behalf of a%s statement "
+ "on table %s and is currently taking a considerable amount "
+ "of time (%lld seconds). This is due to the fact that it is %s "
+ "while looking up records to be processed. Consider adding a "
+ "primary key (or unique key) to the table to improve "
+ "performance.",
+ evt_type, table_name, (long) delta, scan_type);
+ }
+ }
+}
+
+
+/*
+ HA_ERR_KEY_NOT_FOUND is a fatal error normally, but it's an expected
+ error in speculate optimistic mode, so use something non-fatal instead
+*/
+static int row_not_found_error(rpl_group_info *rgi)
+{
+ return rgi->speculation != rpl_group_info::SPECULATE_OPTIMISTIC
+ ? HA_ERR_KEY_NOT_FOUND : HA_ERR_RECORD_CHANGED;
+}
+
+/**
+ Locate the current row in event's table.
+
+ The current row is pointed by @c m_curr_row. Member @c m_width tells
+ how many columns are there in the row (this can be differnet from
+ the number of columns in the table). It is assumed that event's
+ table is already open and pointed by @c m_table.
+
+ If a corresponding record is found in the table it is stored in
+ @c m_table->record[0]. Note that when record is located based on a primary
+ key, it is possible that the record found differs from the row being located.
+
+ If no key is specified or table does not have keys, a table scan is used to
+ find the row. In that case the row should be complete and contain values for
+ all columns. However, it can still be shorter than the table, i.e. the table
+ can contain extra columns not present in the row. It is also possible that
+ the table has fewer columns than the row being located.
+
+ @returns Error code on failure, 0 on success.
+
+ @post In case of success @c m_table->record[0] contains the record found.
+ Also, the internal "cursor" of the table is positioned at the record found.
+
+ @note If the engine allows random access of the records, a combination of
+ @c position() and @c rnd_pos() will be used.
+
+ Note that one MUST call ha_index_or_rnd_end() after this function if
+ it returns 0 as we must leave the row position in the handler intact
+ for any following update/delete command.
+*/
+
+int Rows_log_event::find_row(rpl_group_info *rgi)
+{
+ DBUG_ENTER("Rows_log_event::find_row");
+
+ DBUG_ASSERT(m_table && m_table->in_use != NULL);
+
+ TABLE *table= m_table;
+ int error= 0;
+ bool is_table_scan= false, is_index_scan= false;
+
+ /*
+ rpl_row_tabledefs.test specifies that
+ if the extra field on the slave does not have a default value
+ and this is okay with Delete or Update events.
+ Todo: fix wl3228 hld that requires defauls for all types of events
+ */
+
+ prepare_record(table, m_width, FALSE);
+ error= unpack_current_row(rgi);
+
+ m_vers_from_plain= false;
+ if (table->versioned())
+ {
+ Field *row_end= table->vers_end_field();
+ DBUG_ASSERT(table->read_set);
+ bitmap_set_bit(table->read_set, row_end->field_index);
+ // check whether master table is unversioned
+ if (row_end->val_int() == 0)
+ {
+ bitmap_set_bit(table->write_set, row_end->field_index);
+ // Plain source table may have a PRIMARY KEY. And row_end is always
+ // a part of PRIMARY KEY. Set it to max value for engine to find it in
+ // index. Needed for an UPDATE/DELETE cases.
+ table->vers_end_field()->set_max();
+ m_vers_from_plain= true;
+ }
+ }
+
+ DBUG_PRINT("info",("looking for the following record"));
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+
+ if ((table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
+ table->s->primary_key < MAX_KEY)
+ {
+ /*
+ Use a more efficient method to fetch the record given by
+ table->record[0] if the engine allows it. We first compute a
+ row reference using the position() member function (it will be
+ stored in table->file->ref) and the use rnd_pos() to position
+ the "cursor" (i.e., record[0] in this case) at the correct row.
+
+ TODO: Add a check that the correct record has been fetched by
+ comparing with the original record. Take into account that the
+ record on the master and slave can be of different
+ length. Something along these lines should work:
+
+ ADD>>> store_record(table,record[1]);
+ int error= table->file->ha_rnd_pos(table->record[0],
+ table->file->ref);
+ ADD>>> DBUG_ASSERT(memcmp(table->record[1], table->record[0],
+ table->s->reclength) == 0);
+
+ */
+ int error;
+ DBUG_PRINT("info",("locating record using primary key (position)"));
+
+ error= table->file->ha_rnd_pos_by_record(table->record[0]);
+ if (unlikely(error))
+ {
+ DBUG_PRINT("info",("rnd_pos returns error %d",error));
+ if (error == HA_ERR_KEY_NOT_FOUND)
+ error= row_not_found_error(rgi);
+ table->file->print_error(error, MYF(0));
+ }
+ DBUG_RETURN(error);
+ }
+
+ // We can't use position() - try other methods.
+
+ /*
+ We need to retrieve all fields
+ TODO: Move this out from this function to main loop
+ */
+ table->use_all_columns();
+
+ /*
+ Save copy of the record in table->record[1]. It might be needed
+ later if linear search is used to find exact match.
+ */
+ store_record(table,record[1]);
+
+ if (m_key_info)
+ {
+ DBUG_PRINT("info",("locating record using key #%u [%s] (index_read)",
+ m_key_nr, m_key_info->name.str));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_wrong_index",
+ if(0 != strcmp(m_key_info->name.str,"expected_key")) abort(););
+
+ /* The key is active: search the table using the index */
+ if (!table->file->inited &&
+ (error= table->file->ha_index_init(m_key_nr, FALSE)))
+ {
+ DBUG_PRINT("info",("ha_index_init returns error %d",error));
+ table->file->print_error(error, MYF(0));
+ goto end;
+ }
+
+ /* Fill key data for the row */
+
+ DBUG_ASSERT(m_key);
+ key_copy(m_key, table->record[0], m_key_info, 0);
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_DUMP("key data", m_key, m_key_info->key_length);
+#endif
+
+ /*
+ We need to set the null bytes to ensure that the filler bit are
+ all set when returning. There are storage engines that just set
+ the necessary bits on the bytes and don't set the filler bits
+ correctly.
+ */
+ if (table->s->null_bytes > 0)
+ table->record[0][table->s->null_bytes - 1]|=
+ 256U - (1U << table->s->last_null_bit_pos);
+
+ if (unlikely((error= table->file->ha_index_read_map(table->record[0],
+ m_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))))
+ {
+ DBUG_PRINT("info",("no record matching the key found in the table"));
+ if (error == HA_ERR_KEY_NOT_FOUND)
+ error= row_not_found_error(rgi);
+ table->file->print_error(error, MYF(0));
+ table->file->ha_index_end();
+ goto end;
+ }
+
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+#ifndef HAVE_valgrind
+ DBUG_PRINT("info",("found first matching record"));
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+#endif
+ /*
+ Below is a minor "optimization". If the key (i.e., key number
+ 0) has the HA_NOSAME flag set, we know that we have found the
+ correct record (since there can be no duplicates); otherwise, we
+ have to compare the record with the one found to see if it is
+ the correct one.
+
+ CAVEAT! This behaviour is essential for the replication of,
+ e.g., the mysql.proc table since the correct record *shall* be
+ found using the primary key *only*. There shall be no
+ comparison of non-PK columns to decide if the correct record is
+ found. I can see no scenario where it would be incorrect to
+ chose the row to change only using a PK or an UNNI.
+ */
+ if (table->key_info->flags & HA_NOSAME)
+ {
+ /* Unique does not have non nullable part */
+ if (!(table->key_info->flags & (HA_NULL_PART_KEY)))
+ {
+ error= 0;
+ goto end;
+ }
+ else
+ {
+ KEY *keyinfo= table->key_info;
+ /*
+ Unique has nullable part. We need to check if there is any
+ field in the BI image that is null and part of UNNI.
+ */
+ bool null_found= FALSE;
+ for (uint i=0; i < keyinfo->user_defined_key_parts && !null_found; i++)
+ {
+ uint fieldnr= keyinfo->key_part[i].fieldnr - 1;
+ Field **f= table->field+fieldnr;
+ null_found= (*f)->is_null();
+ }
+
+ if (!null_found)
+ {
+ error= 0;
+ goto end;
+ }
+
+ /* else fall through to index scan */
+ }
+ }
+
+ is_index_scan=true;
+
+ /*
+ In case key is not unique, we still have to iterate over records found
+ and find the one which is identical to the row given. A copy of the
+ record we are looking for is stored in record[1].
+ */
+ DBUG_PRINT("info",("non-unique index, scanning it to find matching record"));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_index_scan", abort(););
+
+ while (record_compare(table))
+ {
+ while ((error= table->file->ha_index_next(table->record[0])))
+ {
+ DBUG_PRINT("info",("no record matching the given row found"));
+ table->file->print_error(error, MYF(0));
+ table->file->ha_index_end();
+ goto end;
+ }
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info",("locating record using table scan (rnd_next)"));
+ /* We use this to test that the correct key is used in test cases. */
+ DBUG_EXECUTE_IF("slave_crash_if_table_scan", abort(););
+
+ /* We don't have a key: search the table using rnd_next() */
+ if (unlikely((error= table->file->ha_rnd_init_with_error(1))))
+ {
+ DBUG_PRINT("info",("error initializing table scan"
+ " (ha_rnd_init returns %d)",error));
+ goto end;
+ }
+
+ is_table_scan= true;
+
+ /* Continue until we find the right record or have made a full loop */
+ do
+ {
+ error= table->file->ha_rnd_next(table->record[0]);
+
+ if (unlikely(error))
+ DBUG_PRINT("info", ("error: %s", HA_ERR(error)));
+ switch (error) {
+
+ case 0:
+ DBUG_DUMP("record found", table->record[0], table->s->reclength);
+ break;
+
+ case HA_ERR_END_OF_FILE:
+ DBUG_PRINT("info", ("Record not found"));
+ table->file->ha_rnd_end();
+ goto end;
+
+ default:
+ DBUG_PRINT("info", ("Failed to get next record"
+ " (rnd_next returns %d)",error));
+ table->file->print_error(error, MYF(0));
+ table->file->ha_rnd_end();
+ goto end;
+ }
+ }
+ while (record_compare(table));
+
+ /*
+ Note: above record_compare will take into accout all record fields
+ which might be incorrect in case a partial row was given in the event
+ */
+
+ DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == 0);
+ }
+
+end:
+ if (is_table_scan || is_index_scan)
+ issue_long_find_row_warning(get_general_type_code(), m_table->alias.c_ptr(),
+ is_index_scan, rgi);
+ table->default_column_bitmaps();
+ DBUG_RETURN(error);
+}
+
+#endif
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+
+Delete_rows_log_event::Delete_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid, bool is_transactional)
+ : Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
+ DELETE_ROWS_EVENT_V1)
+{
+}
+
+Delete_rows_compressed_log_event::Delete_rows_compressed_log_event(
+ THD *thd_arg, TABLE *tbl_arg,
+ ulong tid_arg,
+ bool is_transactional)
+ : Delete_rows_log_event(thd_arg, tbl_arg, tid_arg, is_transactional)
+{
+ m_type= DELETE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Delete_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ /*
+ Increment the global status delete count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]);
+
+ if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
+ m_table->s->primary_key < MAX_KEY)
+ {
+ /*
+ We don't need to allocate any memory for m_key since it is not used.
+ */
+ return 0;
+ }
+ if (slave_run_triggers_for_rbr && !master_had_triggers)
+ m_table->prepare_triggers_for_delete_stmt_or_event();
+
+ return find_key();
+}
+
+int
+Delete_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ m_table->file->ha_index_or_rnd_end();
+ my_free(m_key);
+ m_key= NULL;
+ m_key_info= NULL;
+
+ return error;
+}
+
+int Delete_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ int error;
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Delete_rows_log_event::find_row()";
+ const bool invoke_triggers=
+ slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
+ DBUG_ASSERT(m_table != NULL);
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Delete_rows_log_event::find_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ if (likely(!(error= find_row(rgi))))
+ {
+ /*
+ Delete the record found, located in record[0]
+ */
+ message= "Delete_rows_log_event::ha_delete_row()";
+#ifdef WSREP_PROC_INFO
+ snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Delete_rows_log_event::ha_delete_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif
+ thd_proc_info(thd, message);
+
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ if (likely(!error))
+ {
+ m_table->mark_columns_per_binlog_row_image();
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ {
+ Field *end= m_table->vers_end_field();
+ bitmap_set_bit(m_table->write_set, end->field_index);
+ store_record(m_table, record[1]);
+ end->set_time();
+ error= m_table->file->ha_update_row(m_table->record[1],
+ m_table->record[0]);
+ }
+ else
+ {
+ error= m_table->file->ha_delete_row(m_table->record[0]);
+ }
+ m_table->default_column_bitmaps();
+ }
+ if (invoke_triggers && likely(!error) &&
+ unlikely(process_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ m_table->file->ha_index_or_rnd_end();
+ }
+ thd_proc_info(thd, tmp);
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+#if defined(HAVE_REPLICATION)
+uint8 Delete_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_DELETE);
+}
+#endif
+
+/**************************************************************************
+ Update_rows_log_event member functions
+**************************************************************************/
+
+/*
+ Constructor used to build an event for writing to the binary log.
+ */
+Update_rows_log_event::Update_rows_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid,
+ bool is_transactional)
+: Rows_log_event(thd_arg, tbl_arg, tid, tbl_arg->read_set, is_transactional,
+ UPDATE_ROWS_EVENT_V1)
+{
+ init(tbl_arg->rpl_write_set);
+}
+
+Update_rows_compressed_log_event::Update_rows_compressed_log_event(THD *thd_arg, TABLE *tbl_arg,
+ ulong tid,
+ bool is_transactional)
+: Update_rows_log_event(thd_arg, tbl_arg, tid, is_transactional)
+{
+ m_type = UPDATE_ROWS_COMPRESSED_EVENT_V1;
+}
+
+bool Update_rows_compressed_log_event::write()
+{
+ return Rows_log_event::write_compressed();
+}
+
+void Update_rows_log_event::init(MY_BITMAP const *cols)
+{
+ /* if my_bitmap_init fails, caught in is_valid() */
+ if (likely(!my_bitmap_init(&m_cols_ai,
+ m_width <= sizeof(m_bitbuf_ai)*8 ? m_bitbuf_ai : NULL,
+ m_width,
+ false)))
+ {
+ /* Cols can be zero if this is a dummy binrows event */
+ if (likely(cols != NULL))
+ {
+ memcpy(m_cols_ai.bitmap, cols->bitmap, no_bytes_in_map(cols));
+ create_last_word_mask(&m_cols_ai);
+ }
+ }
+}
+
+
+#if defined(HAVE_REPLICATION)
+
+int
+Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
+{
+ /*
+ Increment the global status update count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]);
+
+ int err;
+ if ((err= find_key()))
+ return err;
+
+ if (slave_run_triggers_for_rbr && !master_had_triggers)
+ m_table->prepare_triggers_for_update_stmt_or_event();
+
+ return 0;
+}
+
+int
+Update_rows_log_event::do_after_row_operations(const Slave_reporting_capability *const,
+ int error)
+{
+ /*error= ToDo:find out what this should really be, this triggers close_scan in nbd, returning error?*/
+ m_table->file->ha_index_or_rnd_end();
+ my_free(m_key); // Free for multi_malloc
+ m_key= NULL;
+ m_key_info= NULL;
+
+ return error;
+}
+
+int
+Update_rows_log_event::do_exec_row(rpl_group_info *rgi)
+{
+ const bool invoke_triggers=
+ slave_run_triggers_for_rbr && !master_had_triggers && m_table->triggers;
+ const char *tmp= thd->get_proc_info();
+ const char *message= "Update_rows_log_event::find_row()";
+ DBUG_ASSERT(m_table != NULL);
+
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::find_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ int error= find_row(rgi);
+ if (unlikely(error))
+ {
+ /*
+ We need to read the second image in the event of error to be
+ able to skip to the next pair of updates
+ */
+ if ((m_curr_row= m_curr_row_end))
+ unpack_current_row(rgi, &m_cols_ai);
+ thd_proc_info(thd, tmp);
+ return error;
+ }
+
+ /*
+ This is the situation after locating BI:
+
+ ===|=== before image ====|=== after image ===|===
+ ^ ^
+ m_curr_row m_curr_row_end
+
+ BI found in the table is stored in record[0]. We copy it to record[1]
+ and unpack AI to record[0].
+ */
+
+ store_record(m_table,record[1]);
+
+ m_curr_row= m_curr_row_end;
+ message= "Update_rows_log_event::unpack_current_row()";
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::unpack_current_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ /* this also updates m_curr_row_end */
+ thd_proc_info(thd, message);
+ if (unlikely((error= unpack_current_row(rgi, &m_cols_ai))))
+ goto err;
+
+ /*
+ Now we have the right row to update. The old row (the one we're
+ looking for) is in record[1] and the new row is in record[0].
+ */
+#ifndef HAVE_valgrind
+ /*
+ Don't print debug messages when running valgrind since they can
+ trigger false warnings.
+ */
+ DBUG_PRINT("info",("Updating row in table"));
+ DBUG_DUMP("old record", m_table->record[1], m_table->s->reclength);
+ DBUG_DUMP("new values", m_table->record[0], m_table->s->reclength);
+#endif
+
+ message= "Update_rows_log_event::ha_update_row()";
+#ifdef WSREP_PROC_INFO
+ my_snprintf(thd->wsrep_info, sizeof(thd->wsrep_info) - 1,
+ "Update_rows_log_event::ha_update_row(%lld)",
+ (long long) wsrep_thd_trx_seqno(thd));
+ message= thd->wsrep_info;
+#endif /* WSREP_PROC_INFO */
+
+ thd_proc_info(thd, message);
+ if (invoke_triggers &&
+ unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_BEFORE, TRUE)))
+ {
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+ goto err;
+ }
+
+ // Temporary fix to find out why it fails [/Matz]
+ memcpy(m_table->read_set->bitmap, m_cols.bitmap, (m_table->read_set->n_bits + 7) / 8);
+ memcpy(m_table->write_set->bitmap, m_cols_ai.bitmap, (m_table->write_set->n_bits + 7) / 8);
+
+ m_table->mark_columns_per_binlog_row_image();
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ m_table->vers_update_fields();
+ error= m_table->file->ha_update_row(m_table->record[1], m_table->record[0]);
+ if (unlikely(error == HA_ERR_RECORD_IS_THE_SAME))
+ error= 0;
+ if (m_vers_from_plain && m_table->versioned(VERS_TIMESTAMP))
+ {
+ store_record(m_table, record[2]);
+ error= vers_insert_history_row(m_table);
+ restore_record(m_table, record[2]);
+ }
+ m_table->default_column_bitmaps();
+
+ if (invoke_triggers && likely(!error) &&
+ unlikely(process_triggers(TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE)))
+ error= HA_ERR_GENERIC; // in case if error is not set yet
+
+ thd_proc_info(thd, tmp);
+
+err:
+ m_table->file->ha_index_or_rnd_end();
+ return error;
+}
+
+#endif /* defined(HAVE_REPLICATION) */
+
+
+#if defined(HAVE_REPLICATION)
+uint8 Update_rows_log_event::get_trg_event_map()
+{
+ return trg2bit(TRG_EVENT_UPDATE);
+}
+#endif
+
+
+void Incident_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ if (m_message.length > 0)
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s)",
+ m_incident, description());
+ else
+ bytes= my_snprintf(buf, sizeof(buf), "#%d (%s): %s",
+ m_incident, description(), m_message.str);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+
+
+#if defined(WITH_WSREP)
+/*
+ read the first event from (*buf). The size of the (*buf) is (*buf_len).
+ At the end (*buf) is shitfed to point to the following event or NULL and
+ (*buf_len) will be changed to account just being read bytes of the 1st event.
+*/
+#define WSREP_MAX_ALLOWED_PACKET 1024*1024*1024 // current protocol max
+
+Log_event* wsrep_read_log_event(
+ char **arg_buf, size_t *arg_buf_len,
+ const Format_description_log_event *description_event)
+{
+ char *head= (*arg_buf);
+ uint data_len = uint4korr(head + EVENT_LEN_OFFSET);
+ char *buf= (*arg_buf);
+ const char *error= 0;
+ Log_event *res= 0;
+ DBUG_ENTER("wsrep_read_log_event");
+
+ if (data_len > WSREP_MAX_ALLOWED_PACKET)
+ {
+ error = "Event too big";
+ goto err;
+ }
+
+ res= Log_event::read_log_event(buf, data_len, &error, description_event, false);
+
+err:
+ if (!res)
+ {
+ DBUG_ASSERT(error != 0);
+ sql_print_error("Error in Log_event::read_log_event(): "
+ "'%s', data_len: %d, event_type: %d",
+ error,data_len,(uchar)head[EVENT_TYPE_OFFSET]);
+ }
+ (*arg_buf)+= data_len;
+ (*arg_buf_len)-= data_len;
+ DBUG_RETURN(res);
+}
+#endif
+
+
+#if defined(HAVE_REPLICATION)
+int
+Incident_log_event::do_apply_event(rpl_group_info *rgi)
+{
+ Relay_log_info const *rli= rgi->rli;
+ DBUG_ENTER("Incident_log_event::do_apply_event");
+
+ if (ignored_error_code(ER_SLAVE_INCIDENT))
+ {
+ DBUG_PRINT("info", ("Ignoring Incident"));
+ DBUG_RETURN(0);
+ }
+
+ rli->report(ERROR_LEVEL, ER_SLAVE_INCIDENT, NULL,
+ ER_THD(rgi->thd, ER_SLAVE_INCIDENT),
+ description(),
+ m_message.length > 0 ? m_message.str : "<none>");
+ DBUG_RETURN(1);
+}
+#endif
+
+
+bool
+Incident_log_event::write_data_header()
+{
+ DBUG_ENTER("Incident_log_event::write_data_header");
+ DBUG_PRINT("enter", ("m_incident: %d", m_incident));
+ uchar buf[sizeof(int16)];
+ int2store(buf, (int16) m_incident);
+ DBUG_RETURN(write_data(buf, sizeof(buf)));
+}
+
+bool
+Incident_log_event::write_data_body()
+{
+ uchar tmp[1];
+ DBUG_ENTER("Incident_log_event::write_data_body");
+ tmp[0]= (uchar) m_message.length;
+ DBUG_RETURN(write_data(tmp, sizeof(tmp)) ||
+ write_data(m_message.str, m_message.length));
+}
+
+
+/* Pack info for its unrecognized ignorable event */
+void Ignorable_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ size_t bytes;
+ bytes= my_snprintf(buf, sizeof(buf), "# Ignorable event type %d (%s)",
+ number, description);
+ protocol->store(buf, bytes, &my_charset_bin);
+}
+
+
+#if defined(HAVE_REPLICATION)
+Heartbeat_log_event::Heartbeat_log_event(const char* buf, uint event_len,
+ const Format_description_log_event* description_event)
+ :Log_event(buf, description_event)
+{
+ uint8 header_size= description_event->common_header_len;
+ ident_len = event_len - header_size;
+ set_if_smaller(ident_len,FN_REFLEN-1);
+ log_ident= buf + header_size;
+}
+#endif
+
+
+/**
+ Check if we should write event to the relay log
+
+ This is used to skip events that is only supported by MySQL
+
+ Return:
+ 0 ok
+ 1 Don't write event
+*/
+
+bool event_that_should_be_ignored(const char *buf)
+{
+ uint event_type= (uchar)buf[EVENT_TYPE_OFFSET];
+ if (event_type == GTID_LOG_EVENT ||
+ event_type == ANONYMOUS_GTID_LOG_EVENT ||
+ event_type == PREVIOUS_GTIDS_LOG_EVENT ||
+ event_type == TRANSACTION_CONTEXT_EVENT ||
+ event_type == VIEW_CHANGE_EVENT ||
+ event_type == XA_PREPARE_LOG_EVENT ||
+ (uint2korr(buf + FLAGS_OFFSET) & LOG_EVENT_IGNORABLE_F))
+ return 1;
+ return 0;
+}
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index 85507a0abde..8a83f22751a 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -188,7 +188,7 @@ int main(int argc, char **argv)
die("--datadir option not provided, and default datadir not found");
my_print_help(my_long_options);
}
- strncat(default_datadir, "\\data", sizeof(default_datadir));
+ strncat_s(default_datadir, sizeof(default_datadir), "\\data", _TRUNCATE);
opt_datadir= default_datadir;
printf("Default data directory is %s\n",opt_datadir);
}
diff --git a/sql/mysql_upgrade_service.cc b/sql/mysql_upgrade_service.cc
index 6a15364c849..a9df9eaf13b 100644
--- a/sql/mysql_upgrade_service.cc
+++ b/sql/mysql_upgrade_service.cc
@@ -514,7 +514,7 @@ int main(int argc, char **argv)
}
char pipe_name[64];
snprintf(pipe_name, sizeof(pipe_name), "\\\\.\\pipe\\mysql_upgrade_service_%u",
- GetCurrentProcessId());
+ (uint)GetCurrentProcessId());
for (;;)
{
if (WaitForSingleObject(mysqld_process, 0) != WAIT_TIMEOUT)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 63d1d07cfaa..695616f9269 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -347,7 +347,6 @@ static my_bool opt_short_log_format= 0, opt_silent_startup= 0;
bool my_disable_leak_check= false;
uint kill_cached_threads;
-static uint wake_thread;
ulong max_used_connections;
volatile ulong cached_thread_count= 0;
static char *mysqld_user, *mysqld_chroot;
@@ -704,7 +703,7 @@ mysql_mutex_t
LOCK_crypt,
LOCK_global_system_variables,
LOCK_user_conn,
- LOCK_connection_count, LOCK_error_messages, LOCK_slave_background;
+ LOCK_error_messages, LOCK_slave_background;
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
@@ -862,7 +861,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_BINLOG_LOCK_binlog_background_thread,
key_LOCK_binlog_end_pos,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
- key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
+ key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_system_variables,
key_LOCK_manager,
@@ -927,7 +926,6 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_delayed_insert_mutex, "Delayed_insert::mutex", 0},
{ &key_hash_filo_lock, "hash_filo::lock", 0},
{ &key_LOCK_active_mi, "LOCK_active_mi", PSI_FLAG_GLOBAL},
- { &key_LOCK_connection_count, "LOCK_connection_count", PSI_FLAG_GLOBAL},
{ &key_LOCK_thread_id, "LOCK_thread_id", PSI_FLAG_GLOBAL},
{ &key_LOCK_crypt, "LOCK_crypt", PSI_FLAG_GLOBAL},
{ &key_LOCK_delayed_create, "LOCK_delayed_create", PSI_FLAG_GLOBAL},
@@ -1472,10 +1470,10 @@ struct st_VioSSLFd *ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
/**
- Number of currently active user connections. The variable is protected by
- LOCK_connection_count.
+ Number of currently active user connections.
*/
-uint connection_count= 0, extra_connection_count= 0;
+Atomic_counter<uint> connection_count;
+static Atomic_counter<uint> extra_connection_count;
my_bool opt_gtid_strict_mode= FALSE;
@@ -2104,7 +2102,6 @@ static void clean_up_mutexes()
mysql_mutex_destroy(&LOCK_delayed_create);
mysql_mutex_destroy(&LOCK_crypt);
mysql_mutex_destroy(&LOCK_user_conn);
- mysql_mutex_destroy(&LOCK_connection_count);
mysql_mutex_destroy(&LOCK_thread_id);
mysql_mutex_destroy(&LOCK_stats);
mysql_mutex_destroy(&LOCK_global_user_client_stats);
@@ -2596,20 +2593,6 @@ extern "C" sig_handler end_mysqld_signal(int sig __attribute__((unused)))
}
#endif /* EMBEDDED_LIBRARY */
-/*
- Decrease number of connections
-
- SYNOPSIS
- dec_connection_count()
-*/
-
-void dec_connection_count(scheduler_functions *scheduler)
-{
- mysql_mutex_lock(&LOCK_connection_count);
- (*scheduler->connection_count)--;
- mysql_mutex_unlock(&LOCK_connection_count);
-}
-
/*
Unlink thd from global list of available connections
@@ -2635,7 +2618,7 @@ void unlink_thd(THD *thd)
*/
if (!thd->wsrep_applier)
#endif /* WITH_WSREP */
- dec_connection_count(thd->scheduler);
+ --*thd->scheduler->connection_count;
thd->free_connection();
@@ -2660,134 +2643,57 @@ void unlink_thd(THD *thd)
*/
-static bool cache_thread(THD *thd)
+CONNECT *cache_thread(THD *thd)
{
struct timespec abstime;
+ CONNECT *connect;
+ bool flushed= false;
DBUG_ENTER("cache_thread");
DBUG_ASSERT(thd);
+ set_timespec(abstime, THREAD_CACHE_TIMEOUT);
+
+ /*
+ Delete the instrumentation for the job that just completed,
+ before parking this pthread in the cache (blocked on COND_thread_cache).
+ */
+ PSI_CALL_delete_current_thread();
+
+#ifndef DBUG_OFF
+ while (_db_is_pushed_())
+ _db_pop_();
+#endif
mysql_mutex_lock(&LOCK_thread_cache);
- if (cached_thread_count < thread_cache_size &&
- ! abort_loop && !kill_cached_threads)
+ if ((connect= thread_cache.get()))
+ cached_thread_count++;
+ else if (cached_thread_count < thread_cache_size && !kill_cached_threads)
{
/* Don't kill the thread, just put it in cache for reuse */
DBUG_PRINT("info", ("Adding thread to cache"));
cached_thread_count++;
-
- /*
- Delete the instrumentation for the job that just completed,
- before parking this pthread in the cache (blocked on COND_thread_cache).
- */
- PSI_CALL_delete_current_thread();
-
-#ifndef DBUG_OFF
- while (_db_is_pushed_())
- _db_pop_();
-#endif
-
- set_timespec(abstime, THREAD_CACHE_TIMEOUT);
- while (!abort_loop && ! wake_thread && ! kill_cached_threads)
+ for (;;)
{
int error= mysql_cond_timedwait(&COND_thread_cache, &LOCK_thread_cache,
&abstime);
- if (error == ETIMEDOUT || error == ETIME)
+ flushed= kill_cached_threads;
+ if ((connect= thread_cache.get()))
+ break;
+ else if (flushed || error == ETIMEDOUT || error == ETIME)
{
/*
If timeout, end thread.
- If a new thread is requested (wake_thread is set), we will handle
+ If a new thread is requested, we will handle
the call, even if we got a timeout (as we are already awake and free)
*/
+ cached_thread_count--;
break;
}
}
- cached_thread_count--;
- if (kill_cached_threads)
- mysql_cond_signal(&COND_flush_thread_cache);
- if (wake_thread)
- {
- CONNECT *connect;
-
- wake_thread--;
- connect= thread_cache.get();
- mysql_mutex_unlock(&LOCK_thread_cache);
-
- if (!(connect->create_thd(thd)))
- {
- /* Out of resources. Free thread to get more resources */
- connect->close_and_delete();
- DBUG_RETURN(0);
- }
- delete connect;
-
- /*
- We have to call store_globals to update mysys_var->id and lock_info
- with the new thread_id
- */
- thd->store_globals();
-
- /*
- Create new instrumentation for the new THD job,
- and attach it to this running pthread.
- */
- PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection,
- thd, thd->thread_id));
-
- /* reset abort flag for the thread */
- thd->mysys_var->abort= 0;
- thd->thr_create_utime= microsecond_interval_timer();
- thd->start_utime= thd->thr_create_utime;
-
- server_threads.insert(thd);
- DBUG_RETURN(1);
- }
}
mysql_mutex_unlock(&LOCK_thread_cache);
- DBUG_RETURN(0);
-}
-
-
-/*
- End thread for the current connection
-
- SYNOPSIS
- one_thread_per_connection_end()
- thd Thread handler. This may be null if we run out of resources.
- put_in_cache Store thread in cache, if there is room in it
- Normally this is true in all cases except when we got
- out of resources initializing the current thread
-
- NOTES
- If thread is cached, we will wait until thread is scheduled to be
- reused and then we will return.
- If thread is not cached, we end the thread.
-
- RETURN
- 0 Signal to handle_one_connection to reuse connection
-*/
-
-bool one_thread_per_connection_end(THD *thd, bool put_in_cache)
-{
- DBUG_ENTER("one_thread_per_connection_end");
-
- if (thd)
- {
- const bool wsrep_applier= IF_WSREP(thd->wsrep_applier, false);
-
- unlink_thd(thd);
- if (!wsrep_applier && put_in_cache && cache_thread(thd))
- DBUG_RETURN(0); // Thread is reused
- delete thd;
- }
-
- DBUG_PRINT("info", ("killing thread"));
- DBUG_LEAVE; // Must match DBUG_ENTER()
-#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
- ERR_remove_state(0);
-#endif
- my_thread_end();
-
- pthread_exit(0);
- return 0; // Avoid compiler warnings
+ if (flushed)
+ mysql_cond_signal(&COND_flush_thread_cache);
+ DBUG_RETURN(connect);
}
@@ -3086,7 +2992,7 @@ void init_signals(void)
sigemptyset(&sa.sa_mask);
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
- my_init_stacktrace();
+ my_init_stacktrace(0);
#if defined(__amiga__)
sa.sa_handler=(void(*)())handle_fatal_signal;
#else
@@ -4525,8 +4431,6 @@ static int init_thread_environment()
&LOCK_error_messages, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_uuid_short_generator,
&LOCK_short_uuid_generator, MY_MUTEX_INIT_FAST);
- mysql_mutex_init(key_LOCK_connection_count,
- &LOCK_connection_count, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_thread_id,
&LOCK_thread_id, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_stats, &LOCK_stats, MY_MUTEX_INIT_FAST);
@@ -5466,13 +5370,13 @@ static void test_lc_time_sz()
for (const char **month= (*loc)->month_names->type_names; *month; month++)
{
set_if_bigger(max_month_len,
- my_numchars_mb(&my_charset_utf8_general_ci,
+ my_numchars_mb(&my_charset_utf8mb3_general_ci,
*month, *month + strlen(*month)));
}
for (const char **day= (*loc)->day_names->type_names; *day; day++)
{
set_if_bigger(max_day_len,
- my_numchars_mb(&my_charset_utf8_general_ci,
+ my_numchars_mb(&my_charset_utf8mb3_general_ci,
*day, *day + strlen(*day)));
}
if ((*loc)->max_month_name_length != max_month_len ||
@@ -5533,7 +5437,7 @@ int mysqld_main(int argc, char **argv)
remaining_argv= argv;
/* Must be initialized early for comparison of options name */
- system_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
sys_var_init();
@@ -6066,7 +5970,7 @@ int mysqld_main(int argc, char **argv)
"MySQLShutdown"), 10);
/* Must be initialized early for comparison of service name */
- system_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
if (my_init())
{
@@ -6197,8 +6101,7 @@ void inc_thread_created(void)
void handle_connection_in_main_thread(CONNECT *connect)
{
- thread_cache_size= 0; // Safety
- do_handle_one_connection(connect);
+ do_handle_one_connection(connect, false);
}
@@ -6208,37 +6111,32 @@ void handle_connection_in_main_thread(CONNECT *connect)
void create_thread_to_handle_connection(CONNECT *connect)
{
- char error_message_buff[MYSQL_ERRMSG_SIZE];
- int error;
DBUG_ENTER("create_thread_to_handle_connection");
- /* Check if we can get thread from the cache */
- if (cached_thread_count > wake_thread)
+ mysql_mutex_lock(&LOCK_thread_cache);
+ if (cached_thread_count)
{
- mysql_mutex_lock(&LOCK_thread_cache);
- /* Recheck condition when we have the lock */
- if (cached_thread_count > wake_thread)
- {
- /* Get thread from cache */
- thread_cache.push_back(connect);
- wake_thread++;
- mysql_cond_signal(&COND_thread_cache);
- mysql_mutex_unlock(&LOCK_thread_cache);
- DBUG_PRINT("info",("Thread created"));
- DBUG_VOID_RETURN;
- }
+ /* Get thread from cache */
+ thread_cache.push_back(connect);
+ cached_thread_count--;
mysql_mutex_unlock(&LOCK_thread_cache);
+ mysql_cond_signal(&COND_thread_cache);
+ DBUG_PRINT("info",("Thread created"));
+ DBUG_VOID_RETURN;
}
+ mysql_mutex_unlock(&LOCK_thread_cache);
/* Create new thread to handle connection */
inc_thread_created();
DBUG_PRINT("info",(("creating thread %lu"), (ulong) connect->thread_id));
connect->prior_thr_create_utime= microsecond_interval_timer();
- if ((error= mysql_thread_create(key_thread_one_connection,
- &connect->real_id, &connection_attrib,
- handle_one_connection, (void*) connect)))
+ pthread_t tmp;
+ if (auto error= mysql_thread_create(key_thread_one_connection,
+ &tmp, &connection_attrib,
+ handle_one_connection, (void*) connect))
{
+ char error_message_buff[MYSQL_ERRMSG_SIZE];
/* purecov: begin inspected */
DBUG_PRINT("error", ("Can't create thread to handle request (error %d)",
error));
@@ -6275,29 +6173,17 @@ void create_new_thread(CONNECT *connect)
Don't allow too many connections. We roughly check here that we allow
only (max_connections + 1) connections.
*/
-
- mysql_mutex_lock(&LOCK_connection_count);
-
- if (*connect->scheduler->connection_count >=
- *connect->scheduler->max_connections + 1|| abort_loop)
+ if ((*connect->scheduler->connection_count)++ >=
+ *connect->scheduler->max_connections + 1)
{
DBUG_PRINT("error",("Too many connections"));
-
- mysql_mutex_unlock(&LOCK_connection_count);
- statistic_increment(denied_connections, &LOCK_status);
- statistic_increment(connection_errors_max_connection, &LOCK_status);
- connect->close_with_error(0, NullS, abort_loop ? ER_SERVER_SHUTDOWN : ER_CON_COUNT_ERROR);
+ connect->close_with_error(0, NullS, ER_CON_COUNT_ERROR);
DBUG_VOID_RETURN;
}
- ++*connect->scheduler->connection_count;
-
- if (connection_count + extra_connection_count > max_used_connections)
- max_used_connections= connection_count + extra_connection_count;
-
- mysql_mutex_unlock(&LOCK_connection_count);
-
- connect->thread_count_incremented= 1;
+ uint sum= connection_count + extra_connection_count;
+ if (sum > max_used_connections)
+ max_used_connections= sum;
/*
The initialization of thread_id is done in create_embedded_thd() for
@@ -6318,13 +6204,6 @@ void create_new_thread(CONNECT *connect)
void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
{
- CONNECT *connect;
- bool is_unix_sock;
-
-#ifdef FD_CLOEXEC
- (void) fcntl(mysql_socket_getfd(new_sock), F_SETFD, FD_CLOEXEC);
-#endif
-
#ifdef HAVE_LIBWRAP
{
if (mysql_socket_getfd(sock) == mysql_socket_getfd(base_ip_sock) ||
@@ -6370,53 +6249,46 @@ void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock)
DBUG_PRINT("info", ("Creating CONNECT for new connection"));
- if ((connect= new CONNECT()))
- {
- is_unix_sock= (mysql_socket_getfd(sock) ==
- mysql_socket_getfd(unix_sock));
-
- if (!(connect->vio=
- mysql_socket_vio_new(new_sock,
- is_unix_sock ? VIO_TYPE_SOCKET :
- VIO_TYPE_TCPIP,
- is_unix_sock ? VIO_LOCALHOST : 0)))
- {
- delete connect;
- connect= 0; // Error handling below
- }
- }
-
- if (!connect)
+ if (auto connect= new CONNECT(new_sock,
+ mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(unix_sock) ?
+ VIO_TYPE_SOCKET : VIO_TYPE_TCPIP,
+ mysql_socket_getfd(sock) ==
+ mysql_socket_getfd(extra_ip_sock) ?
+ extra_thread_scheduler : thread_scheduler))
+ create_new_thread(connect);
+ else
{
/* Connect failure */
(void)mysql_socket_close(new_sock);
statistic_increment(aborted_connects, &LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
- return;
}
+}
- if (is_unix_sock)
- connect->host= my_localhost;
-
- if (mysql_socket_getfd(sock) == mysql_socket_getfd(extra_ip_sock))
+#ifndef _WIN32
+static void set_non_blocking_if_supported(MYSQL_SOCKET sock)
+{
+#if !defined(NO_FCNTL_NONBLOCK)
+ if (!(test_flags & TEST_BLOCKING))
{
- connect->extra_port= 1;
- connect->scheduler= extra_thread_scheduler;
+ int flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0);
+#if defined(O_NONBLOCK)
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK);
+#elif defined(O_NDELAY)
+ fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY);
+#endif
}
- create_new_thread(connect);
+#endif
}
-#ifndef _WIN32
+
void handle_connections_sockets()
{
MYSQL_SOCKET sock= mysql_socket_invalid();
- MYSQL_SOCKET new_sock= mysql_socket_invalid();
uint error_count=0;
struct sockaddr_storage cAddr;
- int ip_flags __attribute__((unused))=0;
- int socket_flags __attribute__((unused))= 0;
- int extra_ip_flags __attribute__((unused))=0;
- int flags=0,retval;
+ int retval;
#ifdef HAVE_POLL
int socket_count= 0;
struct pollfd fds[3]; // for ip_sock, unix_sock and extra_ip_sock
@@ -6438,16 +6310,16 @@ void handle_connections_sockets()
if (mysql_socket_getfd(base_ip_sock) != INVALID_SOCKET)
{
setup_fds(base_ip_sock);
- ip_flags = fcntl(mysql_socket_getfd(base_ip_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(base_ip_sock);
}
if (mysql_socket_getfd(extra_ip_sock) != INVALID_SOCKET)
{
setup_fds(extra_ip_sock);
- extra_ip_flags = fcntl(mysql_socket_getfd(extra_ip_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(extra_ip_sock);
}
#ifdef HAVE_SYS_UN_H
setup_fds(unix_sock);
- socket_flags=fcntl(mysql_socket_getfd(unix_sock), F_GETFL, 0);
+ set_non_blocking_if_supported(unix_sock);
#endif
sd_notify(0, "READY=1\n"
@@ -6489,79 +6361,44 @@ void handle_connections_sockets()
if (fds[i].revents & POLLIN)
{
sock= pfs_fds[i];
- flags= fcntl(mysql_socket_getfd(sock), F_GETFL, 0);
break;
}
}
#else // HAVE_POLL
if (FD_ISSET(mysql_socket_getfd(base_ip_sock),&readFDs))
- {
sock= base_ip_sock;
- flags= ip_flags;
- }
else
if (FD_ISSET(mysql_socket_getfd(extra_ip_sock),&readFDs))
- {
sock= extra_ip_sock;
- flags= extra_ip_flags;
- }
else
- {
sock = unix_sock;
- flags= socket_flags;
- }
#endif // HAVE_POLL
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- {
-#if defined(O_NONBLOCK)
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NONBLOCK);
-#elif defined(O_NDELAY)
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags | O_NDELAY);
-#endif
- }
-#endif /* NO_FCNTL_NONBLOCK */
for (uint retry=0; retry < MAX_ACCEPT_RETRY; retry++)
{
size_socket length= sizeof(struct sockaddr_storage);
+ MYSQL_SOCKET new_sock;
+
new_sock= mysql_socket_accept(key_socket_client_connection, sock,
(struct sockaddr *)(&cAddr),
&length);
- if (mysql_socket_getfd(new_sock) != INVALID_SOCKET ||
- (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))
- break;
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
+ if (mysql_socket_getfd(new_sock) != INVALID_SOCKET)
+ handle_accepted_socket(new_sock, sock);
+ else if (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)
{
- if (retry == MAX_ACCEPT_RETRY - 1)
- {
- // Try without O_NONBLOCK
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
- }
+ /*
+ accept(2) failed on the listening port.
+ There is not much details to report about the client,
+ increment the server global status variable.
+ */
+ statistic_increment(connection_errors_accept, &LOCK_status);
+ if ((error_count++ & 255) == 0) // This can happen often
+ sql_perror("Error in accept");
+ if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
+ sleep(1); // Give other threads some time
+ break;
}
-#endif
}
-
- if (mysql_socket_getfd(new_sock) == INVALID_SOCKET)
- {
- /*
- accept(2) failed on the listening port, after many retries.
- There is not much details to report about the client,
- increment the server global status variable.
- */
- statistic_increment(connection_errors_accept, &LOCK_status);
- if ((error_count++ & 255) == 0) // This can happen often
- sql_perror("Error in accept");
- if (socket_errno == SOCKET_ENFILE || socket_errno == SOCKET_EMFILE)
- sleep(1); // Give other threads some time
- continue;
- }
-#if !defined(NO_FCNTL_NONBLOCK)
- if (!(test_flags & TEST_BLOCKING))
- fcntl(mysql_socket_getfd(sock), F_SETFL, flags);
-#endif
- handle_accepted_socket(new_sock, sock);
}
sd_notify(0, "STOPPING=1\n"
"STATUS=Shutdown in progress\n");
@@ -7607,7 +7444,7 @@ static int debug_status_func(THD *thd, SHOW_VAR *var, char *buff,
#endif
#ifdef HAVE_POOL_OF_THREADS
-int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
+static int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
var->type= SHOW_INT;
@@ -8031,7 +7868,7 @@ static int mysql_init_variables(void)
mqh_used= 0;
cleanup_done= 0;
test_flags= select_errors= dropping_tables= ha_open_options=0;
- thread_count= kill_cached_threads= wake_thread= 0;
+ thread_count= kill_cached_threads= 0;
slave_open_temp_tables= 0;
cached_thread_count= 0;
opt_endinfo= using_udf_functions= 0;
@@ -8060,9 +7897,9 @@ static int mysql_init_variables(void)
key_map_full.set_all();
/* Character sets */
- system_charset_info= &my_charset_utf8_general_ci;
- files_charset_info= &my_charset_utf8_general_ci;
- national_charset_info= &my_charset_utf8_general_ci;
+ system_charset_info= &my_charset_utf8mb3_general_ci;
+ files_charset_info= &my_charset_utf8mb3_general_ci;
+ national_charset_info= &my_charset_utf8mb3_general_ci;
table_alias_charset= &my_charset_bin;
character_set_filesystem= &my_charset_bin;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index c5e7872262a..70a75d8eaad 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -79,11 +79,10 @@ void close_connection(THD *thd, uint sql_errno= 0);
void handle_connection_in_main_thread(CONNECT *thd);
void create_thread_to_handle_connection(CONNECT *connect);
void unlink_thd(THD *thd);
-bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
+CONNECT *cache_thread(THD *thd);
void flush_thread_cache();
void refresh_status(THD *thd);
bool is_secure_file_path(char *path);
-void dec_connection_count(scheduler_functions *scheduler);
extern void init_net_server_extension(THD *thd);
extern void handle_accepted_socket(MYSQL_SOCKET new_sock, MYSQL_SOCKET sock);
extern void create_new_thread(CONNECT *connect);
@@ -119,7 +118,7 @@ extern bool opt_ignore_builtin_innodb;
extern my_bool opt_character_set_client_handshake;
extern my_bool debug_assert_on_not_freed_memory;
extern bool volatile abort_loop;
-extern uint connection_count;
+extern Atomic_counter<uint> connection_count;
extern my_bool opt_safe_user_create;
extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
@@ -318,7 +317,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_BINLOG_LOCK_binlog_background_thread,
key_LOCK_binlog_end_pos,
key_delayed_insert_mutex, key_hash_filo_lock, key_LOCK_active_mi,
- key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create,
+ key_LOCK_crypt, key_LOCK_delayed_create,
key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log,
key_LOCK_gdl, key_LOCK_global_system_variables,
key_LOCK_logger, key_LOCK_manager,
@@ -614,7 +613,7 @@ extern mysql_mutex_t
LOCK_error_log, LOCK_delayed_insert, LOCK_short_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_active_mi, LOCK_manager, LOCK_user_conn,
- LOCK_prepared_stmt_count, LOCK_error_messages, LOCK_connection_count,
+ LOCK_prepared_stmt_count, LOCK_error_messages,
LOCK_slave_background;
extern MYSQL_PLUGIN_IMPORT mysql_mutex_t LOCK_global_system_variables;
extern mysql_rwlock_t LOCK_all_status_vars;
@@ -809,7 +808,6 @@ inline int set_current_thd(THD *thd)
*/
extern handlerton *maria_hton;
-extern uint extra_connection_count;
extern uint64 global_gtid_counter;
extern my_bool opt_gtid_strict_mode;
extern my_bool opt_userstat_running, debug_assert_if_crashed_table;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 3f8509a4b47..9e6b786d11f 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8128,16 +8128,6 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
table_map ref_tables= 0;
table_map param_comp= ~(param->prev_tables | param->read_tables |
param->current_table);
-#ifdef HAVE_SPATIAL
- Field::geometry_type sav_geom_type;
- const bool geometry= field_item->field->type() == MYSQL_TYPE_GEOMETRY;
- if (geometry)
- {
- sav_geom_type= ((Field_geom*) field_item->field)->geom_type;
- /* We have to be able to store all sorts of spatial features here */
- ((Field_geom*) field_item->field)->geom_type= Field::GEOM_GEOMETRY;
- }
-#endif /*HAVE_SPATIAL*/
for (uint i= 0; i < arg_count; i++)
{
@@ -8165,12 +8155,6 @@ SEL_TREE *Item_bool_func::get_full_func_mm_tree(RANGE_OPT_PARAM *param,
}
}
-#ifdef HAVE_SPATIAL
- if (geometry)
- {
- ((Field_geom*) field_item->field)->geom_type= sav_geom_type;
- }
-#endif /*HAVE_SPATIAL*/
DBUG_RETURN(ftree);
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index 599642b3a26..f00d0ed019d 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4483,15 +4483,7 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
/* Make entry for create table */
recinfo->length=length;
- if (field->flags & BLOB_FLAG)
- recinfo->type= FIELD_BLOB;
- else if (use_packed_rows &&
- field->real_type() == MYSQL_TYPE_STRING &&
- length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
- recinfo->type=FIELD_SKIP_ENDSPACE;
- else
- recinfo->type=FIELD_NORMAL;
-
+ recinfo->type= field->tmp_engine_column_type(use_packed_rows);
field->set_table_name(&table->alias);
}
@@ -6772,8 +6764,7 @@ get_corresponding_item_for_in_subq_having(THD *thd, Item *in_item,
Item_ref *ref=
new (thd->mem_root) Item_ref(thd,
&subq_pred->unit->first_select()->context,
- NullS, NullS,
- &new_item->name);
+ new_item->name);
if (!ref)
DBUG_ASSERT(0);
return ref;
diff --git a/sql/opt_trace.cc b/sql/opt_trace.cc
index befc7934a3a..4c9aa43669d 100644
--- a/sql/opt_trace.cc
+++ b/sql/opt_trace.cc
@@ -17,7 +17,7 @@
#include "sql_class.h"
#include "sql_show.h"
#include "field.h"
-#include "table.h"
+#include "sql_i_s.h"
#include "opt_trace.h"
#include "sql_parse.h"
#include "set_var.h"
@@ -66,18 +66,21 @@ bool sets_var_optimizer_trace(enum enum_sql_command sql_command,
}
+namespace Show {
+
+
ST_FIELD_INFO optimizer_trace_info[]=
{
- /* name, length, type, value, maybe_null, old_name, open_method */
- {"QUERY", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
- {"TRACE", 65535, MYSQL_TYPE_STRING, 0, false, NULL, SKIP_OPEN_TABLE},
- {"MISSING_BYTES_BEYOND_MAX_MEM_SIZE", 20, MYSQL_TYPE_LONG, 0, false, NULL,
- SKIP_OPEN_TABLE},
- {"INSUFFICIENT_PRIVILEGES", 1, MYSQL_TYPE_TINY, 0, false, NULL,
- SKIP_OPEN_TABLE},
- {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
+ Column("QUERY", Longtext(65535), NOT_NULL),
+ Column("TRACE", Longtext(65535), NOT_NULL),
+ Column("MISSING_BYTES_BEYOND_MAX_MEM_SIZE", SLong(20), NOT_NULL),
+ Column("INSUFFICIENT_PRIVILEGES", STiny(1), NOT_NULL),
+ CEnd()
};
+} // namespace Show
+
+
/*
TODO: one-line needs to be implemented seperately
*/
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index ba6fc8a49ec..66216493de8 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -2146,7 +2146,6 @@ bool partition_info::fix_column_value_functions(THD *thd,
{
uchar *val_ptr;
uint len= field->pack_length();
- sql_mode_t save_sql_mode;
bool save_got_warning;
if (!(column_item= get_column_item(column_item, field)))
@@ -2154,20 +2153,17 @@ bool partition_info::fix_column_value_functions(THD *thd,
result= TRUE;
goto end;
}
- save_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
save_got_warning= thd->got_warning;
thd->got_warning= 0;
if (column_item->save_in_field(field, TRUE) ||
thd->got_warning)
{
my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0));
- thd->variables.sql_mode= save_sql_mode;
result= TRUE;
goto end;
}
thd->got_warning= save_got_warning;
- thd->variables.sql_mode= save_sql_mode;
if (!(val_ptr= (uchar*) thd->memdup(field->ptr, len)))
{
result= TRUE;
diff --git a/sql/procedure.h b/sql/procedure.h
index 15fd525ec65..b7e7b38a4d2 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -44,7 +44,7 @@ public:
this->name.length= strlen(name_par);
}
enum Type type() const { return Item::PROC_ITEM; }
- Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
+ Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
@@ -52,7 +52,7 @@ public:
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
OPEN c;
*/
- return create_tmp_field_ex_simple(table, src, param);
+ return create_tmp_field_ex_simple(root, table, src, param);
}
virtual void set(double nr)=0;
virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
@@ -107,7 +107,11 @@ class Item_proc_int :public Item_proc
public:
Item_proc_int(THD *thd, const char *name_par): Item_proc(thd, name_par)
{ max_length=11; }
- const Type_handler *type_handler() const { return &type_handler_longlong; }
+ const Type_handler *type_handler() const
+ {
+ return unsigned_flag ? &type_handler_ulonglong :
+ &type_handler_slonglong;
+ }
void set(double nr) { value=(longlong) nr; }
void set(longlong nr) { value=nr; }
void set(const char *str,uint length, CHARSET_INFO *cs)
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 8c7eeaec90c..7e63fcf81a4 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -1001,7 +1001,7 @@ bool Protocol_text::store_field_metadata_for_list_fields(const THD *thd,
uint pos)
{
Send_field field= tl->view ?
- Send_field(fld, tl->view_db.str, tl->view_name.str) :
+ Send_field(fld, tl->view_db, tl->view_name) :
Send_field(fld);
return store_field_metadata(thd, field, fld->charset_for_protocol(), pos);
}
diff --git a/sql/protocol.h b/sql/protocol.h
index 3b2c905ed9e..c5e525cac8c 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -122,11 +122,6 @@ public:
virtual bool store(const char *from, size_t length, CHARSET_INFO *cs)=0;
virtual bool store(const char *from, size_t length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
- bool store_str(const char *s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
- {
- DBUG_ASSERT(s);
- return store(s, (uint) strlen(s), fromcs, tocs);
- }
bool store_str(const LEX_CSTRING &s, CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
return store(s.str, (uint) s.length, fromcs, tocs);
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 18fc3d9431a..7905e112e2e 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -147,6 +147,9 @@ int THD::register_slave(uchar *packet, size_t packet_length)
if (!(si->master_id= uint4korr(p)))
si->master_id= global_system_variables.server_id;
+ if (!*si->host)
+ ::strmake(si->host, main_security_ctx.host_or_ip, sizeof(si->host));
+
unregister_slave();
mysql_mutex_lock(&LOCK_thd_data);
slave_info= si;
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index b36838b9b22..1e4b59844b8 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -19,185 +19,7 @@
#include "rpl_utility.h"
#include "log_event.h"
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-#include "rpl_rli.h"
-#include "sql_select.h"
-/**
- Calculate display length for MySQL56 temporal data types from their metadata.
- It contains fractional precision in the low 16-bit word.
-*/
-static uint32
-max_display_length_for_temporal2_field(uint32 int_display_length,
- unsigned int metadata)
-{
- metadata&= 0x00ff;
- return int_display_length + metadata + (metadata ? 1 : 0);
-}
-
-
-/**
- Compute the maximum display length of a field.
-
- @param sql_type Type of the field
- @param metadata The metadata from the master for the field.
- @return Maximum length of the field in bytes.
-
- The precise values calculated by field->max_display_length() and
- calculated by max_display_length_for_field() can differ (by +1 or -1)
- for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT).
- This slight difference is not important here, because we call
- this function only for two *different* integer data types.
- */
-static uint32
-max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
-{
- DBUG_PRINT("debug", ("sql_type: %d, metadata: 0x%x", sql_type, metadata));
- DBUG_ASSERT(metadata >> 16 == 0);
-
- switch (sql_type) {
- case MYSQL_TYPE_NEWDECIMAL:
- return metadata >> 8;
-
- case MYSQL_TYPE_FLOAT:
- return 12;
-
- case MYSQL_TYPE_DOUBLE:
- return 22;
-
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_ENUM:
- return metadata & 0x00ff;
-
- case MYSQL_TYPE_STRING:
- {
- uchar type= metadata >> 8;
- if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM)
- return metadata & 0xff;
- else
- /* This is taken from Field_string::unpack. */
- return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- }
-
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_TINY:
- return 4;
-
- case MYSQL_TYPE_SHORT:
- return 6;
-
- case MYSQL_TYPE_INT24:
- return 9;
-
- case MYSQL_TYPE_LONG:
- return 11;
-
-#ifdef HAVE_LONG_LONG
- case MYSQL_TYPE_LONGLONG:
- return 20;
-
-#endif
- case MYSQL_TYPE_NULL:
- return 0;
-
- case MYSQL_TYPE_NEWDATE:
- return 3;
-
- case MYSQL_TYPE_DATE:
- return 3;
-
- case MYSQL_TYPE_TIME:
- return MIN_TIME_WIDTH;
-
- case MYSQL_TYPE_TIME2:
- return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata);
-
- case MYSQL_TYPE_TIMESTAMP:
- return MAX_DATETIME_WIDTH;
-
- case MYSQL_TYPE_TIMESTAMP2:
- return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
-
- case MYSQL_TYPE_DATETIME:
- return MAX_DATETIME_WIDTH;
-
- case MYSQL_TYPE_DATETIME2:
- return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata);
-
- case MYSQL_TYPE_BIT:
- /*
- Decode the size of the bit field from the master.
- */
- DBUG_ASSERT((metadata & 0xff) <= 7);
- return 8 * (metadata >> 8U) + (metadata & 0x00ff);
-
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- return metadata;
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- return metadata - 1;
-
- /*
- The actual length for these types does not really matter since
- they are used to calc_pack_length, which ignores the given
- length for these types.
-
- Since we want this to be accurate for other uses, we return the
- maximum size in bytes of these BLOBs.
- */
-
- case MYSQL_TYPE_TINY_BLOB:
- return (uint32)my_set_bits(1 * 8);
-
- case MYSQL_TYPE_MEDIUM_BLOB:
- return (uint32)my_set_bits(3 * 8);
-
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- /*
- For the blob type, Field::real_type() lies and say that all
- blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
- at the length instead to decide what the max display size is.
- */
- return (uint32)my_set_bits(metadata * 8);
-
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_GEOMETRY:
- return (uint32)my_set_bits(4 * 8);
-
- default:
- return ~(uint32) 0;
- }
-}
-
-
-/*
- Compare the pack lengths of a source field (on the master) and a
- target field (on the slave).
-
- @param field Target field.
- @param type Source field type.
- @param metadata Source field metadata.
-
- @retval -1 The length of the source field is smaller than the target field.
- @retval 0 The length of the source and target fields are the same.
- @retval 1 The length of the source field is greater than the target field.
- */
-int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata)
-{
- DBUG_ENTER("compare_lengths");
- size_t const source_length=
- max_display_length_for_field(source_type, metadata);
- size_t const target_length= field->max_display_length();
- DBUG_PRINT("debug", ("source_length: %lu, source_type: %u,"
- " target_length: %lu, target_type: %u",
- (unsigned long) source_length, source_type,
- (unsigned long) target_length, field->real_type()));
- int result= source_length < target_length ? -1 : source_length > target_length;
- DBUG_PRINT("result", ("%d", result));
- DBUG_RETURN(result);
-}
-#endif //MYSQL_CLIENT
/*********************************************************************
* table_def member definitions *
*********************************************************************/
@@ -349,739 +171,6 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
return length;
}
-#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
-/**
- */
-void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_INFO *field_cs)
-{
- DBUG_ENTER("show_sql_type");
- DBUG_PRINT("enter", ("type: %d, metadata: 0x%x", type, metadata));
-
- switch (type)
- {
- case MYSQL_TYPE_TINY:
- str->set_ascii(STRING_WITH_LEN("tinyint"));
- break;
-
- case MYSQL_TYPE_SHORT:
- str->set_ascii(STRING_WITH_LEN("smallint"));
- break;
-
- case MYSQL_TYPE_LONG:
- str->set_ascii(STRING_WITH_LEN("int"));
- break;
-
- case MYSQL_TYPE_FLOAT:
- str->set_ascii(STRING_WITH_LEN("float"));
- break;
-
- case MYSQL_TYPE_DOUBLE:
- str->set_ascii(STRING_WITH_LEN("double"));
- break;
-
- case MYSQL_TYPE_NULL:
- str->set_ascii(STRING_WITH_LEN("null"));
- break;
-
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_TIMESTAMP2:
- str->set_ascii(STRING_WITH_LEN("timestamp"));
- break;
-
- case MYSQL_TYPE_LONGLONG:
- str->set_ascii(STRING_WITH_LEN("bigint"));
- break;
-
- case MYSQL_TYPE_INT24:
- str->set_ascii(STRING_WITH_LEN("mediumint"));
- break;
-
- case MYSQL_TYPE_NEWDATE:
- case MYSQL_TYPE_DATE:
- str->set_ascii(STRING_WITH_LEN("date"));
- break;
-
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_TIME2:
- str->set_ascii(STRING_WITH_LEN("time"));
- break;
-
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- str->set_ascii(STRING_WITH_LEN("datetime"));
- break;
-
- case MYSQL_TYPE_YEAR:
- str->set_ascii(STRING_WITH_LEN("year"));
- break;
-
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "varchar(%u)%s", metadata,
- type == MYSQL_TYPE_VARCHAR_COMPRESSED ? " compressed"
- : "");
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_BIT:
- {
- CHARSET_INFO *cs= str->charset();
- int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF);
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "bit(%d)", bit_length);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_DECIMAL:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "decimal(%d,?)/*old*/", metadata);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_NEWDECIMAL:
- {
- CHARSET_INFO *cs= str->charset();
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "decimal(%d,%d)", metadata >> 8, metadata & 0xff);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_ENUM:
- str->set_ascii(STRING_WITH_LEN("enum"));
- break;
-
- case MYSQL_TYPE_SET:
- str->set_ascii(STRING_WITH_LEN("set"));
- break;
-
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- /*
- Field::real_type() lies regarding the actual type of a BLOB, so
- it is necessary to check the pack length to figure out what kind
- of blob it really is.
- */
- switch (get_blob_type_from_length(metadata))
- {
- case MYSQL_TYPE_TINY_BLOB:
- str->set_ascii(STRING_WITH_LEN("tinyblob"));
- break;
-
- case MYSQL_TYPE_MEDIUM_BLOB:
- str->set_ascii(STRING_WITH_LEN("mediumblob"));
- break;
-
- case MYSQL_TYPE_LONG_BLOB:
- str->set_ascii(STRING_WITH_LEN("longblob"));
- break;
-
- case MYSQL_TYPE_BLOB:
- str->set_ascii(STRING_WITH_LEN("blob"));
- break;
-
- default:
- DBUG_ASSERT(0);
- break;
- }
-
- if (type == MYSQL_TYPE_BLOB_COMPRESSED)
- str->append(STRING_WITH_LEN(" compressed"));
- break;
-
- case MYSQL_TYPE_STRING:
- {
- /*
- This is taken from Field_string::unpack.
- */
- CHARSET_INFO *cs= str->charset();
- uint bytes= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- size_t length=
- cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
- "char(%d)", bytes / field_cs->mbmaxlen);
- str->length(length);
- }
- break;
-
- case MYSQL_TYPE_GEOMETRY:
- str->set_ascii(STRING_WITH_LEN("geometry"));
- break;
-
- default:
- str->set_ascii(STRING_WITH_LEN("<unknown type>"));
- }
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Check the order variable and print errors if the order is not
- acceptable according to the current settings.
-
- @param order The computed order of the conversion needed.
- @param rli The relay log info data structure: for error reporting.
- */
-bool is_conversion_ok(int order, Relay_log_info *rli)
-{
- DBUG_ENTER("is_conversion_ok");
- bool allow_non_lossy, allow_lossy;
-
- allow_non_lossy = slave_type_conversions_options &
- (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY);
- allow_lossy= slave_type_conversions_options &
- (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY);
-
- DBUG_PRINT("enter", ("order: %d, flags:%s%s", order,
- allow_non_lossy ? " ALL_NON_LOSSY" : "",
- allow_lossy ? " ALL_LOSSY" : ""));
- if (order < 0 && !allow_non_lossy)
- {
- /* !!! Add error message saying that non-lossy conversions need to be allowed. */
- DBUG_RETURN(false);
- }
-
- if (order > 0 && !allow_lossy)
- {
- /* !!! Add error message saying that lossy conversions need to be allowed. */
- DBUG_RETURN(false);
- }
-
- DBUG_RETURN(true);
-}
-
-
-/**
- Can a type potentially be converted to another type?
-
- This function check if the types are convertible and what
- conversion is required.
-
- If conversion is not possible, and error is printed.
-
- If conversion is possible:
-
- - *order will be set to -1 if source type is smaller than target
- type and a non-lossy conversion can be required. This includes
- the case where the field types are different but types could
- actually be converted in either direction.
-
- - *order will be set to 0 if no conversion is required.
-
- - *order will be set to 1 if the source type is strictly larger
- than the target type and that conversion is potentially lossy.
-
- @param[in] field Target field
- @param[in] type Source field type
- @param[in] metadata Source field metadata
- @param[in] rli Relay log info (for error reporting)
- @param[in] mflags Flags from the table map event
- @param[out] order Order between source field and target field
-
- @return @c true if conversion is possible according to the current
- settings, @c false if conversion is not possible according to the
- current setting.
- */
-static bool
-can_convert_field_to(Field *field,
- enum_field_types source_type, uint16 metadata,
- Relay_log_info *rli, uint16 mflags,
- int *order_var)
-{
- DBUG_ENTER("can_convert_field_to");
- bool same_type;
-#ifndef DBUG_OFF
- char field_type_buf[MAX_FIELD_WIDTH];
- String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1);
- field->sql_type(field_type);
- DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x",
- field_type.c_ptr_safe(), field->real_type(), source_type, metadata));
-#endif
- /**
- @todo
- Implement Field_varstring_cmopressed::real_type() and
- Field_blob_compressed::real_type() properly. All occurencies
- of Field::real_type() have to be inspected and adjusted if needed.
-
- Until it is not ready we have to compare source_type against
- binlog_type() when replicating from or to compressed data types.
-
- @sa Comment for Field::binlog_type()
- */
- if (source_type == MYSQL_TYPE_VARCHAR_COMPRESSED ||
- source_type == MYSQL_TYPE_BLOB_COMPRESSED ||
- field->binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
- field->binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED)
- same_type= field->binlog_type() == source_type;
- else
- same_type= field->real_type() == source_type;
-
- /*
- If the real type is the same, we need to check the metadata to
- decide if conversions are allowed.
- */
- if (same_type)
- {
- if (metadata == 0) // Metadata can only be zero if no metadata was provided
- {
- /*
- If there is no metadata, we either have an old event where no
- metadata were supplied, or a type that does not require any
- metadata. In either case, conversion can be done but no
- conversion table is necessary.
- */
- DBUG_PRINT("debug", ("Base types are identical, but there is no metadata"));
- *order_var= 0;
- DBUG_RETURN(true);
- }
-
- DBUG_PRINT("debug", ("Base types are identical, doing field size comparison"));
- if (field->compatible_field_size(metadata, rli, mflags, order_var))
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- else
- DBUG_RETURN(false);
- }
- else if (
- /*
- Conversion from MariaDB TIMESTAMP(0), TIME(0), DATETIME(0)
- to the corresponding MySQL56 types is non-lossy.
- */
- (metadata == 0 &&
- ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 &&
- source_type == MYSQL_TYPE_TIMESTAMP) ||
- (field->real_type() == MYSQL_TYPE_TIME2 &&
- source_type == MYSQL_TYPE_TIME) ||
- (field->real_type() == MYSQL_TYPE_DATETIME2 &&
- source_type == MYSQL_TYPE_DATETIME))) ||
- /*
- Conversion from MySQL56 TIMESTAMP(N), TIME(N), DATETIME(N)
- to the corresponding MariaDB or MySQL55 types is non-lossy.
- */
- (metadata == field->decimals() &&
- ((field->real_type() == MYSQL_TYPE_TIMESTAMP &&
- source_type == MYSQL_TYPE_TIMESTAMP2) ||
- (field->real_type() == MYSQL_TYPE_TIME &&
- source_type == MYSQL_TYPE_TIME2) ||
- (field->real_type() == MYSQL_TYPE_DATETIME &&
- source_type == MYSQL_TYPE_DATETIME2))))
- {
- /*
- TS-TODO: conversion from FSP1>FSP2.
- */
- *order_var= -1;
- DBUG_RETURN(true);
- }
- else if (!slave_type_conversions_options)
- DBUG_RETURN(false);
-
- /*
- Here, from and to will always be different. Since the types are
- different, we cannot use the compatible_field_size() function, but
- have to rely on hard-coded max-sizes for fields.
- */
-
- DBUG_PRINT("debug", ("Base types are different, checking conversion"));
- switch (source_type) // Source type (on master)
- {
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- switch (field->real_type())
- {
- case MYSQL_TYPE_NEWDECIMAL:
- /*
- Then the other type is either FLOAT, DOUBLE, or old style
- DECIMAL, so we require lossy conversion.
- */
- *order_var= 1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- {
- if (source_type == MYSQL_TYPE_NEWDECIMAL ||
- source_type == MYSQL_TYPE_DECIMAL)
- *order_var = 1; // Always require lossy conversions
- else
- *order_var= compare_lengths(field, source_type, metadata);
- DBUG_ASSERT(*order_var != 0);
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- }
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- /*
- The length comparison check will do the correct job of comparing
- the field lengths (in bytes) of two integer types.
- */
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- switch (field->real_type())
- {
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_INT24:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_LONGLONG:
- /*
- max_display_length_for_field() is not fully precise for the integer
- data types. So its result cannot be compared to the result of
- field->max_dispay_length() when the table field and the binlog field
- are of the same type.
- This code should eventually be rewritten not to use
- compare_lengths(), to detect subtype/supetype relations
- just using the type codes.
- */
- DBUG_ASSERT(source_type != field->real_type());
- *order_var= compare_lengths(field, source_type, metadata);
- DBUG_ASSERT(*order_var != 0);
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- /*
- Since source and target type is different, and it is not possible
- to convert bit types to anything else, this will return false.
- */
- case MYSQL_TYPE_BIT:
- DBUG_RETURN(false);
-
- /*
- If all conversions are disabled, it is not allowed to convert
- between these types. Since the TEXT vs. BINARY is distinguished by
- the charset, and the charset is not replicated, we cannot
- currently distinguish between , e.g., TEXT and BLOB.
- */
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- switch (field->real_type())
- {
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- case MYSQL_TYPE_BLOB_COMPRESSED:
- case MYSQL_TYPE_STRING:
- case MYSQL_TYPE_VAR_STRING:
- case MYSQL_TYPE_VARCHAR:
- case MYSQL_TYPE_VARCHAR_COMPRESSED:
- *order_var= compare_lengths(field, source_type, metadata);
- /*
- Here we know that the types are different, so if the order
- gives that they do not require any conversion, we still need
- to have non-lossy conversion enabled to allow conversion
- between different (string) types of the same length.
- */
- if (*order_var == 0)
- *order_var= -1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
-
- default:
- DBUG_RETURN(false);
- }
- break;
-
- case MYSQL_TYPE_GEOMETRY:
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_TIME:
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_YEAR:
- case MYSQL_TYPE_NULL:
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- case MYSQL_TYPE_TIMESTAMP2:
- case MYSQL_TYPE_TIME2:
- DBUG_RETURN(false);
- case MYSQL_TYPE_NEWDATE:
- {
- if (field->real_type() == MYSQL_TYPE_DATETIME2 ||
- field->real_type() == MYSQL_TYPE_DATETIME)
- {
- *order_var= -1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- }
- else
- {
- DBUG_RETURN(false);
- }
- }
- break;
-
- //case MYSQL_TYPE_DATETIME: TODO: fix MDEV-17394 and uncomment.
- //
- //The "old" type does not specify the fraction part size which is required
- //for correct conversion.
- case MYSQL_TYPE_DATETIME2:
- {
- if (field->real_type() == MYSQL_TYPE_NEWDATE)
- {
- *order_var= 1;
- DBUG_RETURN(is_conversion_ok(*order_var, rli));
- }
- else
- {
- DBUG_RETURN(false);
- }
- }
- break;
- }
- DBUG_RETURN(false); // To keep GCC happy
-}
-
-
-/**
- Is the definition compatible with a table?
-
- This function will compare the master table with an existing table
- on the slave and see if they are compatible with respect to the
- current settings of @c SLAVE_TYPE_CONVERSIONS.
-
- If the tables are compatible and conversions are required, @c
- *tmp_table_var will be set to a virtual temporary table with field
- pointers for the fields that require conversions. This allow simple
- checking of whether a conversion are to be applied or not.
-
- If tables are compatible, but no conversions are necessary, @c
- *tmp_table_var will be set to NULL.
-
- @param rli_arg[in]
- Relay log info, for error reporting.
-
- @param table[in]
- Table to compare with
-
- @param tmp_table_var[out]
- Virtual temporary table for performing conversions, if necessary.
-
- @retval true Master table is compatible with slave table.
- @retval false Master table is not compatible with slave table.
-*/
-bool
-table_def::compatible_with(THD *thd, rpl_group_info *rgi,
- TABLE *table, TABLE **conv_table_var)
- const
-{
- /*
- We only check the initial columns for the tables.
- */
- uint const cols_to_check= MY_MIN(table->s->fields, size());
- Relay_log_info *rli= rgi->rli;
- TABLE *tmp_table= NULL;
-
- for (uint col= 0 ; col < cols_to_check ; ++col)
- {
- Field *const field= table->field[col];
- int order;
- if (can_convert_field_to(field, type(col), field_metadata(col), rli, m_flags, &order))
- {
- DBUG_PRINT("debug", ("Checking column %d -"
- " field '%s' can be converted - order: %d",
- col, field->field_name.str, order));
- DBUG_ASSERT(order >= -1 && order <= 1);
-
- /*
- If order is not 0, a conversion is required, so we need to set
- up the conversion table.
- */
- if (order != 0 && tmp_table == NULL)
- {
- /*
- This will create the full table with all fields. This is
- necessary to ge the correct field lengths for the record.
- */
- tmp_table= create_conversion_table(thd, rgi, table);
- if (tmp_table == NULL)
- return false;
- /*
- Clear all fields up to, but not including, this column.
- */
- for (unsigned int i= 0; i < col; ++i)
- tmp_table->field[i]= NULL;
- }
-
- if (order == 0 && tmp_table != NULL)
- tmp_table->field[col]= NULL;
- }
- else
- {
- DBUG_PRINT("debug", ("Checking column %d -"
- " field '%s' can not be converted",
- col, field->field_name.str));
- DBUG_ASSERT(col < size() && col < table->s->fields);
- DBUG_ASSERT(table->s->db.str && table->s->table_name.str);
- DBUG_ASSERT(table->in_use);
- const char *db_name= table->s->db.str;
- const char *tbl_name= table->s->table_name.str;
- char source_buf[MAX_FIELD_WIDTH];
- char target_buf[MAX_FIELD_WIDTH];
- String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
- String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
- THD *thd= table->in_use;
-
- show_sql_type(type(col), field_metadata(col), &source_type, field->charset());
- field->sql_type(target_type);
- rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_CONVERSION_FAILED),
- col, db_name, tbl_name,
- source_type.c_ptr_safe(), target_type.c_ptr_safe());
- return false;
- }
- }
-
-#ifndef DBUG_OFF
- if (tmp_table)
- {
- for (unsigned int col= 0; col < tmp_table->s->fields; ++col)
- if (tmp_table->field[col])
- {
- char source_buf[MAX_FIELD_WIDTH];
- char target_buf[MAX_FIELD_WIDTH];
- String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
- String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
- tmp_table->field[col]->sql_type(source_type);
- table->field[col]->sql_type(target_type);
- DBUG_PRINT("debug", ("Field %s - conversion required."
- " Source type: '%s', Target type: '%s'",
- tmp_table->field[col]->field_name.str,
- source_type.c_ptr_safe(), target_type.c_ptr_safe()));
- }
- }
-#endif
-
- *conv_table_var= tmp_table;
- return true;
-}
-
-
-/**
- A wrapper to Virtual_tmp_table, to get access to its constructor,
- which is protected for safety purposes (against illegal use on stack).
-*/
-class Virtual_conversion_table: public Virtual_tmp_table
-{
-public:
- Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { }
- /**
- Add a new field into the virtual table.
- @param sql_type - The real_type of the field.
- @param metadata - The RBR binary log metadata for this field.
- @param target_field - The field from the target table, to get extra
- attributes from (e.g. typelib in case of ENUM).
- */
- bool add(enum_field_types sql_type,
- uint16 metadata, const Field *target_field)
- {
- const Type_handler *handler= Type_handler::get_handler_by_real_type(sql_type);
- if (!handler)
- {
- sql_print_error("In RBR mode, Slave received unknown field type field %d "
- " for column Name: %s.%s.%s.",
- (int) sql_type,
- target_field->table->s->db.str,
- target_field->table->s->table_name.str,
- target_field->field_name.str);
- return true;
- }
- Field *tmp= handler->make_conversion_table_field(this, metadata,
- target_field);
- if (!tmp)
- return true;
- Virtual_tmp_table::add(tmp);
- DBUG_PRINT("debug", ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d,"
- " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
- sql_type, target_field->field_name.str,
- tmp->field_length, tmp->decimals(), TRUE,
- tmp->flags, tmp->pack_length()));
- return false;
- }
-};
-
-
-/**
- Create a conversion table.
-
- If the function is unable to create the conversion table, an error
- will be printed and NULL will be returned.
-
- @return Pointer to conversion table, or NULL if unable to create
- conversion table.
- */
-
-TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi,
- TABLE *target_table) const
-{
- DBUG_ENTER("table_def::create_conversion_table");
-
- Virtual_conversion_table *conv_table;
- Relay_log_info *rli= rgi->rli;
- /*
- At slave, columns may differ. So we should create
- MY_MIN(columns@master, columns@slave) columns in the
- conversion table.
- */
- uint const cols_to_create= MY_MIN(target_table->s->fields, size());
- if (!(conv_table= new(thd) Virtual_conversion_table(thd)) ||
- conv_table->init(cols_to_create))
- goto err;
- for (uint col= 0 ; col < cols_to_create; ++col)
- {
- if (conv_table->add(type(col), field_metadata(col),
- target_table->field[col]))
- {
- DBUG_PRINT("debug", ("binlog_type: %d, metadata: %04X, target_field: '%s'"
- " make_conversion_table_field() failed",
- binlog_type(col), field_metadata(col),
- target_table->field[col]->field_name.str));
- goto err;
- }
- }
-
- if (conv_table->open())
- goto err; // Could not allocate record buffer?
-
- DBUG_RETURN(conv_table);
-
-err:
- if (conv_table)
- delete conv_table;
- rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(),
- ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION),
- target_table->s->db.str,
- target_table->s->table_name.str);
- DBUG_RETURN(NULL);
-}
-#endif /* MYSQL_CLIENT */
table_def::table_def(unsigned char *types, ulong size,
uchar *field_metadata, int metadata_size,
@@ -1245,67 +334,3 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, enum enum_binlog_che
}
return res;
}
-
-#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
-
-Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
-{
- my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0));
-}
-
-Deferred_log_events::~Deferred_log_events()
-{
- delete_dynamic(&array);
-}
-
-int Deferred_log_events::add(Log_event *ev)
-{
- last_added= ev;
- insert_dynamic(&array, (uchar*) &ev);
- return 0;
-}
-
-bool Deferred_log_events::is_empty()
-{
- return array.elements == 0;
-}
-
-bool Deferred_log_events::execute(rpl_group_info *rgi)
-{
- bool res= false;
- DBUG_ENTER("Deferred_log_events::execute");
- DBUG_ASSERT(rgi->deferred_events_collecting);
-
- rgi->deferred_events_collecting= false;
- for (uint i= 0; !res && i < array.elements; i++)
- {
- Log_event *ev= (* (Log_event **)
- dynamic_array_ptr(&array, i));
- res= ev->apply_event(rgi);
- }
- rgi->deferred_events_collecting= true;
- DBUG_RETURN(res);
-}
-
-void Deferred_log_events::rewind()
-{
- /*
- Reset preceding Query log event events which execution was
- deferred because of slave side filtering.
- */
- if (!is_empty())
- {
- for (uint i= 0; i < array.elements; i++)
- {
- Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
- delete ev;
- }
- last_added= NULL;
- if (array.elements > array.max_element)
- freeze_size(&array);
- reset_dynamic(&array);
- }
- last_added= NULL;
-}
-
-#endif
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index b42b11231e0..c28e8aa10eb 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -118,7 +118,9 @@ public:
return source_type;
}
-
+#ifdef MYSQL_SERVER
+ const Type_handler *field_type_handler(uint index) const;
+#endif
/*
This function allows callers to get the extra field data from the
diff --git a/sql/rpl_utility_server.cc b/sql/rpl_utility_server.cc
new file mode 100644
index 00000000000..de088be6434
--- /dev/null
+++ b/sql/rpl_utility_server.cc
@@ -0,0 +1,1171 @@
+/* Copyright (c) 2006, 2013, Oracle and/or its affiliates.
+ Copyright (c) 2011, 2013, Monty Program Ab
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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-1335 USA */
+
+#include "mariadb.h"
+#include <my_bit.h>
+#include "rpl_utility.h"
+#include "log_event.h"
+
+#if defined(MYSQL_CLIENT)
+#error MYSQL_CLIENT must not be defined here
+#endif
+
+#if !defined(MYSQL_SERVER)
+#error MYSQL_SERVER must be defined here
+#endif
+
+#if defined(HAVE_REPLICATION)
+#include "rpl_rli.h"
+#include "sql_select.h"
+#endif
+
+
+/**
+ Compute the maximum display length of a field.
+
+ @param sql_type Type of the field
+ @param metadata The metadata from the master for the field.
+ @return Maximum length of the field in bytes.
+
+ The precise values calculated by field->max_display_length() and
+ calculated by max_display_length_for_field() can differ (by +1 or -1)
+ for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT).
+ This slight difference is not important here, because we call
+ this function only for two *different* integer data types.
+ */
+static uint32
+max_display_length_for_field(const Conv_source &source)
+{
+ DBUG_PRINT("debug", ("sql_type: %s, metadata: 0x%x",
+ source.type_handler()->name().ptr(), source.metadata()));
+ return source.type_handler()->max_display_length_for_field(source);
+}
+
+
+/*
+ Compare the pack lengths of a source field (on the master) and a
+ target field (on the slave).
+
+ @param sh Source type handler
+ @param source_length Source length
+ @param th Target type hander
+ @param target_length Target length
+
+ @retval CONV_TYPE_SUBSET_TO_SUPERSET The length of the source field is
+ smaller than the target field.
+ @retval CONV_TYPE_PRECISE The length of the source and
+ the target fields are equal.
+ @retval CONV_TYPE_SUPERSET_TO_SUBSET The length of the source field is
+ greater than the target field.
+ */
+static enum_conv_type
+compare_lengths(const Type_handler *sh, uint32 source_length,
+ const Type_handler *th, uint32 target_length)
+{
+ DBUG_ENTER("compare_lengths");
+ DBUG_PRINT("debug", ("source_length: %lu, source_type: %s,"
+ " target_length: %lu, target_type: %s",
+ (unsigned long) source_length, sh->name().ptr(),
+ (unsigned long) target_length, th->name().ptr()));
+ enum_conv_type result=
+ source_length < target_length ? CONV_TYPE_SUBSET_TO_SUPERSET :
+ source_length > target_length ? CONV_TYPE_SUPERSET_TO_SUBSET :
+ CONV_TYPE_PRECISE;
+ DBUG_PRINT("result", ("%d", result));
+ DBUG_RETURN(result);
+}
+
+
+/**
+ Calculate display length for MySQL56 temporal data types from their metadata.
+ It contains fractional precision in the low 16-bit word.
+*/
+static uint32
+max_display_length_for_temporal2_field(uint32 int_display_length,
+ unsigned int metadata)
+{
+ metadata&= 0x00ff;
+ return int_display_length + metadata + (metadata ? 1 : 0);
+}
+
+
+uint32
+Type_handler_newdecimal::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata() >> 8;
+}
+
+
+uint32
+Type_handler_typelib::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ Field_enum::rpl_conv_type_from() does not use compare_lengths().
+ So we should not come here.
+ */
+ DBUG_ASSERT(0);
+ return src.metadata() & 0x00ff;
+}
+
+
+uint32
+Type_handler_string::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ ENUM and SET are transferred using as STRING,
+ with the exact type code in metadata.
+ Make sure that we previously detected ENUM/SET and
+ translated them into a proper type handler.
+ See table_def::field_type_handler() for details.
+ */
+ DBUG_ASSERT((src.metadata() >> 8) != MYSQL_TYPE_SET);
+ DBUG_ASSERT((src.metadata() >> 8) != MYSQL_TYPE_ENUM);
+ /* This is taken from Field_string::unpack. */
+ return (((src.metadata() >> 4) & 0x300) ^ 0x300) + (src.metadata() & 0x00ff);
+}
+
+
+uint32
+Type_handler_time2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MIN_TIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_timestamp2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_datetime2::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH,
+ src.metadata());
+}
+
+
+uint32
+Type_handler_bit::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ Decode the size of the bit field from the master.
+ */
+ DBUG_ASSERT((src.metadata() & 0xff) <= 7);
+ return 8 * (src.metadata() >> 8U) + (src.metadata() & 0x00ff);
+}
+
+
+uint32
+Type_handler_var_string::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata();
+}
+
+
+uint32
+Type_handler_varchar::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return src.metadata();
+}
+
+
+uint32
+Type_handler_varchar_compressed::
+ max_display_length_for_field(const Conv_source &src) const
+{
+ DBUG_ASSERT(src.metadata() > 0);
+ return src.metadata() - 1;
+}
+
+
+/*
+ The actual length for these types does not really matter since
+ they are used to calc_pack_length, which ignores the given
+ length for these types.
+
+ Since we want this to be accurate for other uses, we return the
+ maximum size in bytes of these BLOBs.
+*/
+uint32
+Type_handler_tiny_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(1 * 8);
+}
+
+
+uint32
+Type_handler_medium_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(3 * 8);
+}
+
+
+uint32
+Type_handler_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ /*
+ For the blob type, Field::real_type() lies and say that all
+ blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look
+ at the length instead to decide what the max display size is.
+ */
+ return (uint32) my_set_bits(src.metadata() * 8);
+}
+
+
+uint32
+Type_handler_blob_compressed::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(src.metadata() * 8);
+}
+
+
+uint32
+Type_handler_long_blob::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(4 * 8);
+}
+
+
+uint32
+Type_handler_olddecimal::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return ~(uint32) 0;
+}
+
+
+void Type_handler::show_binlog_type(const Conv_source &src, String *str) const
+{
+ str->set_ascii(name().ptr(), name().length());
+}
+
+
+void Type_handler_var_string::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ "varchar(%u)",
+ src.metadata() / src.mbmaxlen());
+ str->length(length);
+}
+
+
+void Type_handler_varchar::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ "varchar(%u)",
+ src.metadata() / src.mbmaxlen());
+ str->length(length);
+}
+
+
+void Type_handler_varchar_compressed::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ "varchar(%u) compressed",
+ src.metadata() / src.mbmaxlen());
+ str->length(length);
+}
+
+void Type_handler_bit::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ int bit_length= 8 * (src.metadata() >> 8) + (src.metadata() & 0xFF);
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "bit(%d)", bit_length);
+ str->length(length);
+}
+
+
+void Type_handler_olddecimal::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "decimal(%d,?)/*old*/", src.metadata());
+ str->length(length);
+
+}
+
+
+void Type_handler_newdecimal::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ CHARSET_INFO *cs= str->charset();
+ size_t length=
+ cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(),
+ "decimal(%d,%d)",
+ src.metadata() >> 8, src.metadata() & 0xff);
+ str->length(length);
+}
+
+
+void Type_handler_blob_compressed::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ /*
+ Field::real_type() lies regarding the actual type of a BLOB, so
+ it is necessary to check the pack length to figure out what kind
+ of blob it really is.
+ */
+ switch (src.metadata()) {
+ case 1:
+ str->set_ascii(STRING_WITH_LEN("tinyblob compressed"));
+ break;
+ case 2:
+ str->set_ascii(STRING_WITH_LEN("blob compressed"));
+ break;
+ case 3:
+ str->set_ascii(STRING_WITH_LEN("mediumblob compressed"));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ // Fall through
+ case 4:
+ str->set_ascii(STRING_WITH_LEN("longblob compressed"));
+ }
+}
+
+
+void Type_handler_string::show_binlog_type(const Conv_source &src,
+ String *str) const
+{
+ /*
+ This is taken from Field_string::unpack.
+ */
+ CHARSET_INFO *cs= str->charset();
+ uint bytes= (((src.metadata() >> 4) & 0x300) ^ 0x300) +
+ (src.metadata() & 0x00ff);
+ size_t length= cs->cset->snprintf(cs, (char*) str->ptr(),
+ str->alloced_length(),
+ "char(%d)", bytes / src.mbmaxlen());
+ str->length(length);
+}
+
+
+enum_conv_type
+Field::rpl_conv_type_from_same_data_type(uint16 metadata,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (metadata == 0) // Metadata can only be zero if no metadata was provided
+ {
+ /*
+ If there is no metadata, we either have an old event where no
+ metadata were supplied, or a type that does not require any
+ metadata. In either case, conversion can be done but no
+ conversion table is necessary.
+ */
+ DBUG_PRINT("debug", ("Base types are identical, but there is no metadata"));
+ return CONV_TYPE_PRECISE;
+ }
+
+ DBUG_PRINT("debug", ("Base types are identical, doing field size comparison"));
+ int order= 0;
+ if (!compatible_field_size(metadata, rli, param.table_def_flags(), &order))
+ return CONV_TYPE_IMPOSSIBLE;
+ return order == 0 ? CONV_TYPE_PRECISE :
+ order < 0 ? CONV_TYPE_SUBSET_TO_SUPERSET :
+ CONV_TYPE_SUPERSET_TO_SUBSET;
+}
+
+
+enum_conv_type
+Field_new_decimal::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_olddecimal ||
+ source.type_handler() == &type_handler_newdecimal ||
+ source.type_handler() == &type_handler_float ||
+ source.type_handler() == &type_handler_double)
+ {
+ /*
+ Then the other type is either FLOAT, DOUBLE, or old style
+ DECIMAL, so we require lossy conversion.
+ */
+ return CONV_TYPE_SUPERSET_TO_SUBSET;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/*
+ This covers FLOAT, DOUBLE and old DECIMAL
+*/
+enum_conv_type
+Field_real::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_olddecimal ||
+ source.type_handler() == &type_handler_newdecimal)
+ return CONV_TYPE_SUPERSET_TO_SUBSET; // Always require lossy conversions
+ if (source.type_handler() == &type_handler_float ||
+ source.type_handler() == &type_handler_double)
+ {
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ DBUG_ASSERT(order != CONV_TYPE_PRECISE);
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_int::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ The length comparison check will do the correct job of comparing
+ the field lengths (in bytes) of two integer types.
+ */
+ if (source.type_handler() == &type_handler_stiny ||
+ source.type_handler() == &type_handler_sshort ||
+ source.type_handler() == &type_handler_sint24 ||
+ source.type_handler() == &type_handler_slong ||
+ source.type_handler() == &type_handler_slonglong)
+ {
+ /*
+ max_display_length_for_field() is not fully precise for the integer
+ data types. So its result cannot be compared to the result of
+ max_dispay_length() when the table field and the binlog field
+ are of the same type.
+ This code should eventually be rewritten not to use
+ compare_lengths(), to detect subtype/supetype relations
+ just using the type codes.
+ */
+ DBUG_ASSERT(source.real_field_type() != real_type());
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ DBUG_ASSERT(order != CONV_TYPE_PRECISE);
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_enum::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ /*
+ For some reasons Field_enum and Field_set store MYSQL_TYPE_STRING
+ as a type code in the binary log and encode the real type in metadata.
+ So we need to test real_type() here instread of binlog_type().
+ */
+ return real_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_longstr::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ /**
+ @todo
+ Implement Field_varstring_compressed::real_type() and
+ Field_blob_compressed::real_type() properly. All occurencies
+ of Field::real_type() have to be inspected and adjusted if needed.
+
+ Until it is not ready we have to compare source_type against
+ binlog_type() when replicating from or to compressed data types.
+
+ @sa Comment for Field::binlog_type()
+ */
+ bool same_type;
+ if (source.real_field_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
+ source.real_field_type() == MYSQL_TYPE_BLOB_COMPRESSED ||
+ binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED ||
+ binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED)
+ same_type= binlog_type() == source.real_field_type();
+ else
+ same_type= type_handler() == source.type_handler();
+
+ if (same_type)
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+
+ if (source.type_handler() == &type_handler_tiny_blob ||
+ source.type_handler() == &type_handler_medium_blob ||
+ source.type_handler() == &type_handler_long_blob ||
+ source.type_handler() == &type_handler_blob ||
+ source.type_handler() == &type_handler_blob_compressed ||
+ source.type_handler() == &type_handler_string ||
+ source.type_handler() == &type_handler_var_string ||
+ source.type_handler() == &type_handler_varchar ||
+ source.type_handler() == &type_handler_varchar_compressed)
+ {
+ enum_conv_type order= compare_lengths(source.type_handler(),
+ max_display_length_for_field(source),
+ type_handler(), max_display_length());
+ /*
+ Here we know that the types are different, so if the order
+ gives that they do not require any conversion, we still need
+ to have non-lossy conversion enabled to allow conversion
+ between different (string) types of the same length.
+
+ Also, if all conversions are disabled, it is not allowed to convert
+ between these types. Since the TEXT vs. BINARY is distinguished by
+ the charset, and the charset is not replicated, we cannot
+ currently distinguish between , e.g., TEXT and BLOB.
+ */
+ if (order == CONV_TYPE_PRECISE)
+ order= CONV_TYPE_SUBSET_TO_SUPERSET;
+ return order;
+ }
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_newdate::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (real_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ if (source.type_handler() == &type_handler_datetime2)
+ return CONV_TYPE_SUPERSET_TO_SUBSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_time::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 TIME(N)' -> 'MariaDB-5.3 TIME(N)' is non-lossy
+ if (decimals() == source.metadata() &&
+ source.type_handler() == &type_handler_time2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timef::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ See comment in Field_datetimef::rpl_conv_type_from()
+ 'MariaDB-5.3 TIME(0)' to 'MySQL56 TIME(0)' is non-lossy
+ */
+ if (source.metadata() == 0 && source.type_handler() == &type_handler_time)
+ return CONV_TYPE_VARIANT;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timestamp::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 TIMESTAMP(N)' -> MariaDB-5.3 TIMESTAMP(N)' is non-lossy
+ if (source.metadata() == decimals() &&
+ source.type_handler() == &type_handler_timestamp2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_timestampf::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ See comment in Field_datetimef::rpl_conv_type_from()
+ 'MariaDB-5.3 TIMESTAMP(0)' to 'MySQL56 TIMESTAMP(0)' is non-lossy
+ */
+ if (source.metadata() == 0 &&
+ source.type_handler() == &type_handler_timestamp)
+ return CONV_TYPE_VARIANT;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_datetime::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ // 'MySQL56 DATETIME(N)' -> MariaDB-5.3 DATETIME(N) is non-lossy
+ if (source.metadata() == decimals() &&
+ source.type_handler() == &type_handler_datetime2)
+ return CONV_TYPE_VARIANT; // TODO: conversion from FSP1>FSP2
+ if (source.type_handler() == &type_handler_newdate)
+ return CONV_TYPE_SUBSET_TO_SUPERSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_datetimef::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ if (binlog_type() == source.real_field_type())
+ return rpl_conv_type_from_same_data_type(source.metadata(), rli, param);
+ /*
+ 'MariaDB-5.3 DATETIME(N)' does not provide information about fractional
+ precision in metadata. So we assume the precision on the master is equal
+ to the precision on the slave.
+ TODO: See MDEV-17394 what happend in case precisions are in case different
+ 'MariaDB-5.3 DATETIME(0)' to 'MySQL56 DATETIME(0)' is non-lossy
+ */
+ if (source.metadata() == 0 &&
+ source.type_handler() == &type_handler_datetime)
+ return CONV_TYPE_VARIANT;
+ if (source.type_handler() == &type_handler_newdate)
+ return CONV_TYPE_SUBSET_TO_SUPERSET;
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_date::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ // old DATE
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_bit::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_year::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+enum_conv_type
+Field_null::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ DBUG_ASSERT(0);
+ return CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/**********************************************************************/
+
+
+#if defined(HAVE_REPLICATION)
+
+/**
+ */
+void show_sql_type(const Conv_source &src, String *str)
+{
+ DBUG_ENTER("show_sql_type");
+ DBUG_ASSERT(src.type_handler() != NULL);
+ DBUG_PRINT("enter", ("type: %s, metadata: 0x%x",
+ src.type_handler()->name().ptr(), src.metadata()));
+ src.type_handler()->show_binlog_type(src, str);
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Check the order variable and print errors if the order is not
+ acceptable according to the current settings.
+
+ @param order The computed order of the conversion needed.
+ @param rli The relay log info data structure: for error reporting.
+ */
+static bool is_conversion_ok(enum_conv_type type, const Relay_log_info *rli,
+ ulonglong type_conversion_options)
+{
+ DBUG_ENTER("is_conversion_ok");
+ bool allow_non_lossy, allow_lossy;
+
+ allow_non_lossy= type_conversion_options &
+ (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY);
+ allow_lossy= type_conversion_options &
+ (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY);
+
+ DBUG_PRINT("enter", ("order: %d, flags:%s%s", (int) type,
+ allow_non_lossy ? " ALL_NON_LOSSY" : "",
+ allow_lossy ? " ALL_LOSSY" : ""));
+ switch (type) {
+ case CONV_TYPE_PRECISE:
+ case CONV_TYPE_VARIANT:
+ DBUG_RETURN(true);
+ case CONV_TYPE_SUBSET_TO_SUPERSET:
+ /* !!! Add error message saying that non-lossy conversions need to be allowed. */
+ DBUG_RETURN(allow_non_lossy);
+ case CONV_TYPE_SUPERSET_TO_SUBSET:
+ /* !!! Add error message saying that lossy conversions need to be allowed. */
+ DBUG_RETURN(allow_lossy);
+ case CONV_TYPE_IMPOSSIBLE:
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(false);
+}
+
+
+/**
+ Can a type potentially be converted to another type?
+
+ This function check if the types are convertible and what
+ conversion is required.
+
+ If conversion is not possible, and error is printed.
+
+ If conversion is possible:
+
+ - *order will be set to -1 if source type is smaller than target
+ type and a non-lossy conversion can be required. This includes
+ the case where the field types are different but types could
+ actually be converted in either direction.
+
+ - *order will be set to 0 if no conversion is required.
+
+ - *order will be set to 1 if the source type is strictly larger
+ than the target type and that conversion is potentially lossy.
+
+ @param[in] field Target field
+ @param[in] type Source field type
+ @param[in] metadata Source field metadata
+ @param[in] rli Relay log info (for error reporting)
+ @param[in] mflags Flags from the table map event
+ @param[out] order Order between source field and target field
+
+ @return @c true if conversion is possible according to the current
+ settings, @c false if conversion is not possible according to the
+ current setting.
+ */
+static enum_conv_type
+can_convert_field_to(Field *field, const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param)
+{
+ DBUG_ENTER("can_convert_field_to");
+#ifndef DBUG_OFF
+ char field_type_buf[MAX_FIELD_WIDTH];
+ String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1);
+ field->sql_type(field_type);
+ DBUG_PRINT("enter", ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x",
+ field_type.c_ptr_safe(), field->real_type(),
+ source.real_field_type(), source.metadata()));
+#endif
+ DBUG_RETURN(field->rpl_conv_type_from(source, rli, param));
+}
+
+
+const Type_handler *table_def::field_type_handler(uint col) const
+{
+ enum_field_types typecode= binlog_type(col);
+ uint16 metadata= field_metadata(col);
+ DBUG_ASSERT(typecode != MYSQL_TYPE_ENUM);
+ DBUG_ASSERT(typecode != MYSQL_TYPE_SET);
+
+ if (typecode == MYSQL_TYPE_BLOB)
+ {
+ switch (metadata & 0xff) {
+ case 1: return &type_handler_tiny_blob;
+ case 2: return &type_handler_blob;
+ case 3: return &type_handler_medium_blob;
+ case 4: return &type_handler_long_blob;
+ default: return NULL;
+ }
+ }
+ if (typecode == MYSQL_TYPE_STRING)
+ {
+ uchar typecode2= metadata >> 8;
+ if (typecode2 == MYSQL_TYPE_SET)
+ return &type_handler_set;
+ if (typecode2 == MYSQL_TYPE_ENUM)
+ return &type_handler_enum;
+ return &type_handler_string;
+ }
+ /*
+ This type has not been used since before row-based replication,
+ so we can safely assume that it really is MYSQL_TYPE_NEWDATE.
+ */
+ if (typecode == MYSQL_TYPE_DATE)
+ return &type_handler_newdate;
+ return Type_handler::get_handler_by_real_type(typecode);
+}
+
+
+/**
+ Is the definition compatible with a table?
+
+ This function will compare the master table with an existing table
+ on the slave and see if they are compatible with respect to the
+ current settings of @c SLAVE_TYPE_CONVERSIONS.
+
+ If the tables are compatible and conversions are required, @c
+ *tmp_table_var will be set to a virtual temporary table with field
+ pointers for the fields that require conversions. This allow simple
+ checking of whether a conversion are to be applied or not.
+
+ If tables are compatible, but no conversions are necessary, @c
+ *tmp_table_var will be set to NULL.
+
+ @param rli_arg[in]
+ Relay log info, for error reporting.
+
+ @param table[in]
+ Table to compare with
+
+ @param tmp_table_var[out]
+ Virtual temporary table for performing conversions, if necessary.
+
+ @retval true Master table is compatible with slave table.
+ @retval false Master table is not compatible with slave table.
+*/
+bool
+table_def::compatible_with(THD *thd, rpl_group_info *rgi,
+ TABLE *table, TABLE **conv_table_var)
+ const
+{
+ /*
+ We only check the initial columns for the tables.
+ */
+ uint const cols_to_check= MY_MIN(table->s->fields, size());
+ Relay_log_info *rli= rgi->rli;
+ TABLE *tmp_table= NULL;
+
+ for (uint col= 0 ; col < cols_to_check ; ++col)
+ {
+ Field *const field= table->field[col];
+ const Type_handler *h= field_type_handler(col);
+ if (!h)
+ {
+ sql_print_error("In RBR mode, Slave received unknown field type field %d "
+ " for column Name: %s.%s.%s.",
+ binlog_type(col),
+ field->table->s->db.str,
+ field->table->s->table_name.str,
+ field->field_name.str);
+ return false;
+ }
+
+ if (!h)
+ return false; // An unknown data type found in the binary log
+ Conv_source source(h, field_metadata(col), field->charset());
+ enum_conv_type convtype= can_convert_field_to(field, source, rli,
+ Conv_param(m_flags));
+ if (is_conversion_ok(convtype, rli, slave_type_conversions_options))
+ {
+ DBUG_PRINT("debug", ("Checking column %d -"
+ " field '%s' can be converted - order: %d",
+ col, field->field_name.str, convtype));
+ /*
+ If conversion type is not CONV_TYPE_RECISE, a conversion is required,
+ so we need to set up the conversion table.
+ */
+ if (convtype != CONV_TYPE_PRECISE && tmp_table == NULL)
+ {
+ /*
+ This will create the full table with all fields. This is
+ necessary to ge the correct field lengths for the record.
+ */
+ tmp_table= create_conversion_table(thd, rgi, table);
+ if (tmp_table == NULL)
+ return false;
+ /*
+ Clear all fields up to, but not including, this column.
+ */
+ for (unsigned int i= 0; i < col; ++i)
+ tmp_table->field[i]= NULL;
+ }
+
+ if (convtype == CONV_TYPE_PRECISE && tmp_table != NULL)
+ tmp_table->field[col]= NULL;
+ }
+ else
+ {
+ DBUG_PRINT("debug", ("Checking column %d -"
+ " field '%s' can not be converted",
+ col, field->field_name.str));
+ DBUG_ASSERT(col < size() && col < table->s->fields);
+ DBUG_ASSERT(table->s->db.str && table->s->table_name.str);
+ DBUG_ASSERT(table->in_use);
+ const char *db_name= table->s->db.str;
+ const char *tbl_name= table->s->table_name.str;
+ StringBuffer<MAX_FIELD_WIDTH> source_type(&my_charset_latin1);
+ StringBuffer<MAX_FIELD_WIDTH> target_type(&my_charset_latin1);
+ THD *thd= table->in_use;
+
+ show_sql_type(source, &source_type);
+ field->sql_type(target_type);
+ DBUG_ASSERT(source_type.length() > 0);
+ DBUG_ASSERT(target_type.length() > 0);
+ rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_CONVERSION_FAILED),
+ col, db_name, tbl_name,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe());
+ return false;
+ }
+ }
+
+#ifndef DBUG_OFF
+ if (tmp_table)
+ {
+ for (unsigned int col= 0; col < tmp_table->s->fields; ++col)
+ if (tmp_table->field[col])
+ {
+ char source_buf[MAX_FIELD_WIDTH];
+ char target_buf[MAX_FIELD_WIDTH];
+ String source_type(source_buf, sizeof(source_buf), &my_charset_latin1);
+ String target_type(target_buf, sizeof(target_buf), &my_charset_latin1);
+ tmp_table->field[col]->sql_type(source_type);
+ table->field[col]->sql_type(target_type);
+ DBUG_PRINT("debug", ("Field %s - conversion required."
+ " Source type: '%s', Target type: '%s'",
+ tmp_table->field[col]->field_name.str,
+ source_type.c_ptr_safe(), target_type.c_ptr_safe()));
+ }
+ }
+#endif
+
+ *conv_table_var= tmp_table;
+ return true;
+}
+
+
+/**
+ A wrapper to Virtual_tmp_table, to get access to its constructor,
+ which is protected for safety purposes (against illegal use on stack).
+*/
+class Virtual_conversion_table: public Virtual_tmp_table
+{
+public:
+ Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { }
+ /**
+ Add a new field into the virtual table.
+ @param handler - The type handler of the field.
+ @param metadata - The RBR binary log metadata for this field.
+ @param target_field - The field from the target table, to get extra
+ attributes from (e.g. typelib in case of ENUM).
+ */
+ bool add(const Type_handler *handler,
+ uint16 metadata, const Field *target_field)
+ {
+ Field *tmp= handler->make_conversion_table_field(in_use->mem_root,
+ this, metadata,
+ target_field);
+ if (!tmp)
+ return true;
+ Virtual_tmp_table::add(tmp);
+ DBUG_PRINT("debug", ("sql_type: %s, target_field: '%s', max_length: %d, decimals: %d,"
+ " maybe_null: %d, unsigned_flag: %d, pack_length: %u",
+ handler->name().ptr(), target_field->field_name.str,
+ tmp->field_length, tmp->decimals(), TRUE,
+ tmp->flags, tmp->pack_length()));
+ return false;
+ }
+};
+
+
+/**
+ Create a conversion table.
+
+ If the function is unable to create the conversion table, an error
+ will be printed and NULL will be returned.
+
+ @return Pointer to conversion table, or NULL if unable to create
+ conversion table.
+ */
+
+TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi,
+ TABLE *target_table) const
+{
+ DBUG_ENTER("table_def::create_conversion_table");
+
+ Virtual_conversion_table *conv_table;
+ Relay_log_info *rli= rgi->rli;
+ /*
+ At slave, columns may differ. So we should create
+ MY_MIN(columns@master, columns@slave) columns in the
+ conversion table.
+ */
+ uint const cols_to_create= MY_MIN(target_table->s->fields, size());
+ if (!(conv_table= new(thd) Virtual_conversion_table(thd)) ||
+ conv_table->init(cols_to_create))
+ goto err;
+ for (uint col= 0 ; col < cols_to_create; ++col)
+ {
+ const Type_handler *ha= field_type_handler(col);
+ DBUG_ASSERT(ha); // Checked at compatible_with() time
+ if (conv_table->add(ha, field_metadata(col), target_table->field[col]))
+ {
+ DBUG_PRINT("debug", ("binlog_type: %d, metadata: %04X, target_field: '%s'"
+ " make_conversion_table_field() failed",
+ binlog_type(col), field_metadata(col),
+ target_table->field[col]->field_name.str));
+ goto err;
+ }
+ }
+
+ if (conv_table->open())
+ goto err; // Could not allocate record buffer?
+
+ DBUG_RETURN(conv_table);
+
+err:
+ if (conv_table)
+ delete conv_table;
+ rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(),
+ ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION),
+ target_table->s->db.str,
+ target_table->s->table_name.str);
+ DBUG_RETURN(NULL);
+}
+
+
+
+Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
+{
+ my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0));
+}
+
+Deferred_log_events::~Deferred_log_events()
+{
+ delete_dynamic(&array);
+}
+
+int Deferred_log_events::add(Log_event *ev)
+{
+ last_added= ev;
+ insert_dynamic(&array, (uchar*) &ev);
+ return 0;
+}
+
+bool Deferred_log_events::is_empty()
+{
+ return array.elements == 0;
+}
+
+bool Deferred_log_events::execute(rpl_group_info *rgi)
+{
+ bool res= false;
+ DBUG_ENTER("Deferred_log_events::execute");
+ DBUG_ASSERT(rgi->deferred_events_collecting);
+
+ rgi->deferred_events_collecting= false;
+ for (uint i= 0; !res && i < array.elements; i++)
+ {
+ Log_event *ev= (* (Log_event **)
+ dynamic_array_ptr(&array, i));
+ res= ev->apply_event(rgi);
+ }
+ rgi->deferred_events_collecting= true;
+ DBUG_RETURN(res);
+}
+
+void Deferred_log_events::rewind()
+{
+ /*
+ Reset preceding Query log event events which execution was
+ deferred because of slave side filtering.
+ */
+ if (!is_empty())
+ {
+ for (uint i= 0; i < array.elements; i++)
+ {
+ Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
+ delete ev;
+ }
+ last_added= NULL;
+ if (array.elements > array.max_element)
+ freeze_size(&array);
+ reset_dynamic(&array);
+ }
+ last_added= NULL;
+}
+
+#endif // defined(HAVE_REPLICATION)
+
diff --git a/sql/scheduler.cc b/sql/scheduler.cc
index 5a20566c89e..7380b134f13 100644
--- a/sql/scheduler.cc
+++ b/sql/scheduler.cc
@@ -24,26 +24,11 @@
#include "mariadb.h"
#include "mysqld.h"
-#include "sql_connect.h" // init_new_connection_handler_thread
#include "scheduler.h"
#include "sql_class.h"
#include "sql_callback.h"
#include <violite.h>
-/*
- End connection, in case when we are using 'no-threads'
-*/
-
-static bool no_threads_end(THD *thd, bool put_in_cache)
-{
- if (thd)
- {
- unlink_thd(thd);
- delete thd;
- }
- return 1; // Abort handle_one_connection
-}
-
/** @internal
Helper functions to allow mysys to call the thread scheduler when
waiting for locks.
@@ -127,22 +112,16 @@ void post_kill_notification(THD *thd)
void one_thread_per_connection_scheduler(scheduler_functions *func,
ulong *arg_max_connections,
- uint *arg_connection_count)
+ Atomic_counter<uint> *arg_connection_count)
{
scheduler_init();
func->max_threads= *arg_max_connections + 1;
func->max_connections= arg_max_connections;
func->connection_count= arg_connection_count;
- func->init_new_connection_thread= init_new_connection_handler_thread;
func->add_connection= create_thread_to_handle_connection;
- func->end_thread= one_thread_per_connection_end;
func->post_kill_notification= post_kill_notification;
}
#else
-bool init_new_connection_handler_thread()
-{
- return 0;
-}
void handle_connection_in_main_thread(CONNECT *connect)
{
}
@@ -158,7 +137,5 @@ void one_thread_scheduler(scheduler_functions *func)
func->max_threads= 1;
func->max_connections= &max_connections;
func->connection_count= &connection_count;
- func->init_new_connection_thread= init_new_connection_handler_thread;
func->add_connection= handle_connection_in_main_thread;
- func->end_thread= no_threads_end;
}
diff --git a/sql/scheduler.h b/sql/scheduler.h
index 42895134c83..676262f6454 100644
--- a/sql/scheduler.h
+++ b/sql/scheduler.h
@@ -31,15 +31,14 @@ class THD;
struct scheduler_functions
{
- uint max_threads, *connection_count;
+ uint max_threads;
+ Atomic_counter<uint> *connection_count;
ulong *max_connections;
bool (*init)(void);
- bool (*init_new_connection_thread)(void);
void (*add_connection)(CONNECT *connect);
void (*thd_wait_begin)(THD *thd, int wait_type);
void (*thd_wait_end)(THD *thd);
void (*post_kill_notification)(THD *thd);
- bool (*end_thread)(THD *thd, bool cache_thread);
void (*end)(void);
};
@@ -72,7 +71,7 @@ enum scheduler_types
};
void one_thread_per_connection_scheduler(scheduler_functions *func,
- ulong *arg_max_connections, uint *arg_connection_count);
+ ulong *arg_max_connections, Atomic_counter<uint> *arg_connection_count);
void one_thread_scheduler(scheduler_functions *func);
extern void scheduler_init();
@@ -100,7 +99,7 @@ public:
#ifdef HAVE_POOL_OF_THREADS
void pool_of_threads_scheduler(scheduler_functions* func,
ulong *arg_max_connections,
- uint *arg_connection_count);
+ Atomic_counter<uint> *arg_connection_count);
#else
#define pool_of_threads_scheduler(A,B,C) \
one_thread_per_connection_scheduler(A, B, C)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 812f25949eb..f81e2753ac1 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -35,7 +35,7 @@
#include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone
#include "sql_acl.h" // SUPER_ACL
#include "sql_select.h" // free_underlaid_joins
-#include "sql_show.h"
+#include "sql_i_s.h"
#include "sql_view.h" // updatable_views_with_limit_typelib
#include "lock.h" // lock_global_read_lock,
// make_global_read_lock_block_commit,
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index c64f60f3562..0f68c726747 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7931,3 +7931,9 @@ ER_PERIOD_CONSTRAINT_DROP
eng "Can't DROP CONSTRAINT `%s`. Use DROP PERIOD `%s` for this"
ER_TOO_LONG_KEYPART 42000 S1009
eng "Specified key part was too long; max key part length is %u bytes"
+ER_TOO_LONG_DATABASE_COMMENT
+ eng "Comment for database '%-.64s' is too long (max = %u)"
+ER_UNKNOWN_DATA_TYPE
+ eng "Unknown data type: '%-.64s'"
+ER_UNKNOWN_OPERATOR
+ eng "Operator does not exists: '%-.128s'"
diff --git a/sql/slave.cc b/sql/slave.cc
index 509b8b02f24..6a0eee1d205 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1646,6 +1646,40 @@ const char *print_slave_db_safe(const char* db)
#endif /* HAVE_REPLICATION */
+bool Sql_cmd_show_slave_status::execute(THD *thd)
+{
+#ifndef HAVE_REPLICATION
+ my_ok(thd);
+ return false;
+#else
+ DBUG_ENTER("Sql_cmd_show_slave_status::execute");
+ bool res= true;
+
+ /* Accept one of two privileges */
+ if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
+ goto error;
+ if (is_show_all_slaves_stat())
+ {
+ mysql_mutex_lock(&LOCK_active_mi);
+ res= show_all_master_info(thd);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
+ else
+ {
+ LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
+ Master_info *mi;
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
+ {
+ res= show_master_info(thd, mi, 0);
+ mi->release();
+ }
+ }
+error:
+ DBUG_RETURN(res);
+#endif
+}
+
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
diff --git a/sql/sp.cc b/sql/sp.cc
index 8568bc16c00..c9d1e2e3c4a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -683,7 +683,7 @@ Sp_handler::db_find_routine(THD *thd,
longlong modified;
Sp_chistics chistics;
bool saved_time_zone_used= thd->time_zone_used;
- sql_mode_t sql_mode, saved_mode= thd->variables.sql_mode;
+ sql_mode_t sql_mode;
Open_tables_backup open_tables_state_backup;
Stored_program_creation_ctx *creation_ctx;
AUTHID definer;
@@ -698,7 +698,7 @@ Sp_handler::db_find_routine(THD *thd,
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
/* Reset sql_mode during data dictionary operations. */
- thd->variables.sql_mode= 0;
+ Sql_mode_instant_set sms(thd, 0);
if ((ret= db_find_routine_aux(thd, name, table)) != SP_OK)
goto done;
@@ -755,7 +755,6 @@ Sp_handler::db_find_routine(THD *thd,
thd->time_zone_used= saved_time_zone_used;
if (table)
close_system_tables(thd, &open_tables_state_backup);
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(ret);
}
@@ -1524,8 +1523,7 @@ Sp_handler_package::show_create_sp(THD *thd, String *buf,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const
{
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= sql_mode;
+ Sql_mode_instant_set sms(thd, sql_mode);
bool rc=
buf->append(STRING_WITH_LEN("CREATE ")) ||
(ddl_options.or_replace() &&
@@ -1542,7 +1540,6 @@ Sp_handler_package::show_create_sp(THD *thd, String *buf,
append_package_chistics(buf, chistics) ||
buf->append(" ", 1) ||
buf->append(body.str, body.length);
- thd->variables.sql_mode= old_sql_mode;
return rc;
}
@@ -2914,7 +2911,6 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
const DDL_options_st ddl_options,
sql_mode_t sql_mode) const
{
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
size_t agglen= (chistics.agg_type == GROUP_AGGREGATE)? 10 : 0;
LEX_CSTRING tmp;
@@ -2925,7 +2921,7 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
agglen + USER_HOST_BUFF_SIZE))
return true;
- thd->variables.sql_mode= sql_mode;
+ Sql_mode_instant_set sms(thd, sql_mode);
buf->append(STRING_WITH_LEN("CREATE "));
if (ddl_options.or_replace())
buf->append(STRING_WITH_LEN("OR REPLACE "));
@@ -2976,7 +2972,6 @@ Sp_handler::show_create_sp(THD *thd, String *buf,
append_suid(buf, chistics.suid);
append_comment(buf, chistics.comment);
buf->append(body.str, body.length); // Not \0 terminated
- thd->variables.sql_mode= old_sql_mode;
return false;
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index dfbfde64029..90fb288cc3c 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2333,11 +2333,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
break;
}
- Send_field *out_param_info= new (thd->mem_root) Send_field();
- nctx->get_parameter(i)->make_send_field(thd, out_param_info);
- out_param_info->db_name= m_db.str;
- out_param_info->table_name= m_name.str;
- out_param_info->org_table_name= m_name.str;
+ Send_field *out_param_info= new (thd->mem_root) Send_field(thd, nctx->get_parameter(i));
+ out_param_info->db_name= m_db;
+ out_param_info->table_name= m_name;
+ out_param_info->org_table_name= m_name;
out_param_info->col_name= spvar->name;
out_param_info->org_col_name= spvar->name;
@@ -3820,10 +3819,8 @@ sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
int
sp_instr_set_trigger_field::exec_core(THD *thd, uint *nextp)
{
- bool sav_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= thd->is_strict_mode() && !thd->lex->ignore;
+ Abort_on_warning_instant_set aws(thd, thd->is_strict_mode() && !thd->lex->ignore);
const int res= (trigger_field->set_value(thd, &value) ? -1 : 0);
- thd->abort_on_warning= sav_abort_on_warning;
*nextp = m_ip+1;
return res;
}
diff --git a/sql/spatial.cc b/sql/spatial.cc
index bba9ae45f58..ebec280a5eb 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -185,6 +185,33 @@ Geometry *Geometry::construct(Geometry_buffer *buffer,
}
+uint Geometry::get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length)
+{
+ const char *dummy;
+ MBR mbr;
+ Geometry_buffer buffer;
+ Geometry *gobj;
+ const uint image_length= SIZEOF_STORED_DOUBLE*4;
+
+ if (src.length < SRID_SIZE)
+ {
+ bzero(buff, image_length);
+ return image_length;
+ }
+ gobj= Geometry::construct(&buffer, (char*) src.str, (uint32) src.length);
+ if (!gobj || gobj->get_mbr(&mbr, &dummy))
+ bzero(buff, image_length);
+ else
+ {
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ }
+ return image_length;
+}
+
+
Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer,
Gis_read_stream *trs, String *wkt,
bool init_stream)
diff --git a/sql/spatial.h b/sql/spatial.h
index fa4e40b5aa5..7817fd041cd 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -322,6 +322,7 @@ public:
bool er_on_3D, String *res);
static Geometry *create_from_opresult(Geometry_buffer *g_buf,
String *res, Gcalc_result_receiver &rr);
+ static uint get_key_image_itMBR(LEX_CSTRING &src, uchar *buff, uint length);
int as_wkt(String *wkt, const char **end);
int as_json(String *wkt, uint max_dec_digits, const char **end);
int bbox_as_json(String *wkt);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 847d2bd777b..6537f5ad1bc 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -2244,7 +2244,7 @@ bool acl_init(bool dont_read_acl_tables)
acl_cache= new Hash_filo<acl_entry>(ACL_CACHE_SIZE, 0, 0,
(my_hash_get_key) acl_entry_get_key,
(my_hash_free_key) free,
- &my_charset_utf8_bin);
+ &my_charset_utf8mb3_bin);
/*
cache built-in native authentication plugins,
@@ -2681,10 +2681,10 @@ bool acl_reload(THD *thd)
my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0));
acl_dbs.init(50, 100);
my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0));
- my_hash_init2(&acl_roles,50, &my_charset_utf8_bin,
+ my_hash_init2(&acl_roles,50, &my_charset_utf8mb3_bin,
0, 0, 0, (my_hash_get_key) acl_role_get_key, 0,
(void (*)(void *))free_acl_role, 0);
- my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0,
+ my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8mb3_bin, 0, 0, 0,
(my_hash_get_key) acl_role_map_get_key, 0, 0, 0);
old_mem= acl_memroot;
delete_dynamic(&acl_wild_hosts);
@@ -7568,21 +7568,20 @@ static bool grant_load(THD *thd,
TABLE *t_table, *c_table, *p_table;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
MEM_ROOT *save_mem_root= thd->mem_root;
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("grant_load");
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
- (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
+ (void) my_hash_init(&column_priv_hash, &my_charset_utf8mb3_bin,
0,0,0, (my_hash_get_key) get_grant_table,
(my_hash_free_key) free_grant_table,0);
- (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
+ (void) my_hash_init(&proc_priv_hash, &my_charset_utf8mb3_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
+ (void) my_hash_init(&func_priv_hash, &my_charset_utf8mb3_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8_bin,
+ (void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8mb3_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
- (void) my_hash_init(&package_body_priv_hash, &my_charset_utf8_bin,
+ (void) my_hash_init(&package_body_priv_hash, &my_charset_utf8mb3_bin,
0,0,0, (my_hash_get_key) get_grant_table, 0,0);
init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0));
@@ -7696,7 +7695,6 @@ end_unlock:
t_table->file->ha_index_end();
thd->mem_root= save_mem_root;
end_index_init:
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(return_val);
}
@@ -10683,7 +10681,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
LEX_USER *user_name, *tmp_user_name;
List_iterator <LEX_USER> user_list(list);
bool binlog= false;
- sql_mode_t old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("mysql_drop_user");
DBUG_PRINT("entry", ("Handle as %s", handle_as_role ? "role" : "user"));
@@ -10695,7 +10692,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
if ((result= tables.open_and_lock(thd, tables_to_open, TL_WRITE)))
DBUG_RETURN(result != 1);
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
mysql_rwlock_wrlock(&LOCK_grant);
mysql_mutex_lock(&acl_cache->lock);
@@ -10770,7 +10767,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role)
result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
mysql_rwlock_unlock(&LOCK_grant);
- thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(result);
}
@@ -11309,7 +11305,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{
GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
- if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) &&
+ if (!my_strcasecmp(&my_charset_utf8mb3_bin, grant_proc->db, sp_db) &&
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
{
LEX_USER lex_user;
@@ -13920,11 +13916,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
if (command == COM_CONNECT &&
!(thd->main_security_ctx.master_access & SUPER_ACL))
{
- mysql_mutex_lock(&LOCK_connection_count);
- bool count_ok= (*thd->scheduler->connection_count <=
- *thd->scheduler->max_connections);
- mysql_mutex_unlock(&LOCK_connection_count);
- if (!count_ok)
+ if (*thd->scheduler->connection_count > *thd->scheduler->max_connections)
{ // too many connections
my_error(ER_CON_COUNT_ERROR, MYF(0));
DBUG_RETURN(1);
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 0230ee1df12..75d792523c7 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -239,7 +239,8 @@ bool Alter_info::vers_prohibited(THD *thd) const
Alter_table_ctx::Alter_table_ctx()
- : datetime_field(NULL), error_if_not_empty(false),
+ : implicit_default_value_error_field(NULL),
+ error_if_not_empty(false),
tables_opened(0),
db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str),
@@ -260,7 +261,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
uint tables_opened_arg,
const LEX_CSTRING *new_db_arg,
const LEX_CSTRING *new_name_arg)
- : datetime_field(NULL), error_if_not_empty(false),
+ : implicit_default_value_error_field(NULL), error_if_not_empty(false),
tables_opened(tables_opened_arg),
new_db(*new_db_arg), new_name(*new_name_arg),
fk_error_if_delete_row(false), fk_error_id(NULL),
@@ -352,6 +353,19 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
}
+void Alter_table_ctx::report_implicit_default_value_error(THD *thd,
+ const TABLE_SHARE *s)
+ const
+{
+ Create_field *error_field= implicit_default_value_error_field;
+ const Type_handler *h= error_field->type_handler();
+ thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
+ h->name().ptr(),
+ h->default_value().ptr(),
+ s, error_field->field_name.str);
+}
+
+
bool Sql_cmd_alter_table::execute(THD *thd)
{
LEX *lex= thd->lex;
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 10aafe1ab37..41408a91836 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -287,8 +287,9 @@ public:
fk_error_table= fk->foreign_table->str;
}
+ void report_implicit_default_value_error(THD *thd, const TABLE_SHARE *) const;
public:
- Create_field *datetime_field;
+ Create_field *implicit_default_value_error_field;
bool error_if_not_empty;
uint tables_opened;
LEX_CSTRING db;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 4cf9b152940..7ac0dcad596 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -5790,8 +5790,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
the replacing item.
*/
if (*ref && !(*ref)->is_autogenerated_name)
- item->set_name(thd, (*ref)->name.str, (*ref)->name.length,
- system_charset_info);
+ item->set_name(thd, (*ref)->name);
if (register_tree_change)
thd->change_item_tree(ref, item);
else
@@ -5882,8 +5881,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, si
the replacing item.
*/
if (*ref && !(*ref)->is_autogenerated_name)
- item->set_name(thd, (*ref)->name.str, (*ref)->name.length,
- system_charset_info);
+ item->set_name(thd, (*ref)->name);
if (register_tree_change && arena)
thd->restore_active_arena(arena, &backup);
@@ -6299,8 +6297,8 @@ find_field_in_tables(THD *thd, Item_ident *item,
bool check_privileges, bool register_tree_change)
{
Field *found=0;
- const char *db= item->db_name;
- const char *table_name= item->table_name;
+ const char *db= item->db_name.str;
+ const char *table_name= item->table_name.str;
const char *name= item->field_name.str;
size_t length= item->field_name.length;
char name_buff[SAFE_NAME_LEN+1];
@@ -6576,8 +6574,8 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
if (is_ref_by_name)
{
field_name= &((Item_ident*) find)->field_name;
- table_name= ((Item_ident*) find)->table_name;
- db_name= ((Item_ident*) find)->db_name;
+ table_name= ((Item_ident*) find)->table_name.str;
+ db_name= ((Item_ident*) find)->db_name.str;
}
for (uint i= 0; i < n_items; i++)
@@ -6617,13 +6615,13 @@ find_item_in_list(Item *find, List<Item> &items, uint *counter,
item_field->field_name and item_field->table_name can be 0x0 if
item is not fix_field()'ed yet.
*/
- if (item_field->field_name.str && item_field->table_name &&
+ if (item_field->field_name.str && item_field->table_name.str &&
!lex_string_cmp(system_charset_info, &item_field->field_name,
field_name) &&
- !my_strcasecmp(table_alias_charset, item_field->table_name,
+ !my_strcasecmp(table_alias_charset, item_field->table_name.str,
table_name) &&
- (!db_name || (item_field->db_name &&
- !strcmp(item_field->db_name, db_name))))
+ (!db_name || (item_field->db_name.str &&
+ !strcmp(item_field->db_name.str, db_name))))
{
if (found_unaliased)
{
@@ -7520,8 +7518,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
MY_INT64_NUM_DECIMAL_DIGITS));
}
else if (insert_fields(thd, ((Item_field*) item)->context,
- ((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name, &it,
+ ((Item_field*) item)->db_name.str,
+ ((Item_field*) item)->table_name.str, &it,
any_privileges, hidden_bit_fields))
{
if (arena)
diff --git a/sql/sql_basic_types.h b/sql/sql_basic_types.h
index 170e93741ef..3200228618f 100644
--- a/sql/sql_basic_types.h
+++ b/sql/sql_basic_types.h
@@ -23,6 +23,8 @@
typedef ulonglong sql_mode_t;
typedef int64 query_id_t;
+enum enum_nullability { NOT_NULL, NULLABLE };
+
/*
"fuzzydate" with strict data type control.
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index cce80ce2bc8..02dc8198c7c 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -28,9 +28,26 @@
#include <my_bit.h>
-template <uint width> class Bitmap
+/* An iterator to quickly walk over bits in ulonglong bitmap. */
+class Table_map_iterator
{
+ ulonglong bmp;
+public:
+ Table_map_iterator(ulonglong t): bmp(t){}
+ uint next_bit()
+ {
+ if (!bmp)
+ return BITMAP_END;
+ uint bit= my_find_first_bit(bmp);
+ bmp &= ~(1ULL << bit);
+ return bit;
+ }
+ int operator++(int) { return next_bit(); }
+ enum { BITMAP_END= 64 };
+};
+template <uint width> class Bitmap
+{
/*
Workaround GCC optimizer bug (generating SSE instuctions on unaligned data)
*/
@@ -43,12 +60,38 @@ template <uint width> class Bitmap
#pragma GCC target ("no-sse")
#endif
- uint32 buffer[(width + 31) / 32];
-public:
- Bitmap()
+private:
+ static const int BITS_PER_ELEMENT= sizeof(ulonglong) * 8;
+ static const int ARRAY_ELEMENTS= (width + BITS_PER_ELEMENT - 1) / BITS_PER_ELEMENT;
+ static const ulonglong ALL_BITS_SET= ULLONG_MAX;
+
+ ulonglong buffer[ARRAY_ELEMENTS];
+
+ uint bit_index(uint n) const
+ {
+ DBUG_ASSERT(n < width);
+ return ARRAY_ELEMENTS == 1 ? 0 : n / BITS_PER_ELEMENT;
+ }
+ ulonglong bit_mask(uint n) const
{
- clear_all();
+ DBUG_ASSERT(n < width);
+ return ARRAY_ELEMENTS == 1 ? 1ULL << n : 1ULL << (n % BITS_PER_ELEMENT);
+ }
+ ulonglong last_element_mask(int n) const
+ {
+ DBUG_ASSERT(n % BITS_PER_ELEMENT != 0);
+ return bit_mask(n) - 1;
}
+
+public:
+ /*
+ The default constructor does nothing.
+ The caller is supposed to either zero the memory
+ or to call set_all()/clear_all()/set_prefix()
+ to initialize bitmap.
+ */
+ Bitmap() { }
+
explicit Bitmap(uint prefix)
{
set_prefix(prefix);
@@ -57,50 +100,76 @@ public:
{
set_prefix(prefix);
}
-
uint length() const
{
return width;
}
void set_bit(uint n)
{
- DBUG_ASSERT(n < width);
- ((uchar*)buffer)[n / 8] |= (1 << (n & 7));
+ buffer[bit_index(n)] |= bit_mask(n);
}
void clear_bit(uint n)
{
- DBUG_ASSERT(n < width);
- ((uchar*)buffer)[n / 8] &= ~(1 << (n & 7));
+ buffer[bit_index(n)] &= ~bit_mask(n);
+ }
+ bool is_set(uint n) const
+ {
+ return buffer[bit_index(n)] & bit_mask(n);
}
void set_prefix(uint prefix_size)
{
set_if_smaller(prefix_size, width);
- uint prefix_bytes, prefix_bits, d;
- uchar* m = (uchar*)buffer;
- if ((prefix_bytes = prefix_size / 8))
- memset(m, 0xff, prefix_bytes);
- m += prefix_bytes;
- if ((prefix_bits = prefix_size & 7))
- {
- *(m++) = (1 << prefix_bits) - 1;
- // As the prefix bits are set, lets count this byte too as a prefix byte.
- prefix_bytes++;
- }
- if ((d = (width + 7) / 8 - prefix_bytes))
- memset(m, 0, d);
+ size_t idx= prefix_size / BITS_PER_ELEMENT;
+
+ for (size_t i= 0; i < idx; i++)
+ buffer[i]= ALL_BITS_SET;
+
+ if (prefix_size % BITS_PER_ELEMENT)
+ buffer[idx++]= last_element_mask(prefix_size);
+
+ for (size_t i= idx; i < ARRAY_ELEMENTS; i++)
+ buffer[i]= 0;
+ }
+ bool is_prefix(uint prefix_size) const
+ {
+ DBUG_ASSERT(prefix_size <= width);
+
+ size_t idx= prefix_size / BITS_PER_ELEMENT;
+
+ for (size_t i= 0; i < idx; i++)
+ if (buffer[i] != ALL_BITS_SET)
+ return false;
+
+ if (prefix_size % BITS_PER_ELEMENT)
+ if (buffer[idx++] != last_element_mask(prefix_size))
+ return false;
+
+ for (size_t i= idx; i < ARRAY_ELEMENTS; i++)
+ if (buffer[i] != 0)
+ return false;
+
+ return true;
}
void set_all()
{
- set_prefix(width);
+ if (width % BITS_PER_ELEMENT)
+ set_prefix(width);
+ else if (ARRAY_ELEMENTS > 1)
+ memset(buffer, 0xff, sizeof(buffer));
+ else
+ buffer[0] = ALL_BITS_SET;
}
void clear_all()
{
- memset(buffer, 0x00, sizeof(buffer));
+ if (ARRAY_ELEMENTS > 1)
+ memset(buffer, 0, sizeof(buffer));
+ else
+ buffer[0]= 0;
}
- void intersect(Bitmap & map2)
+ void intersect(const Bitmap& map2)
{
- for (uint i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] &= map2.buffer[i];
}
@@ -112,27 +181,13 @@ private:
*/
void intersect_and_pad(ulonglong map2buff, bool pad_with_ones)
{
- compile_time_assert(sizeof(ulonglong) == 8);
- uint32 tmp[2];
- int8store(tmp, map2buff);
+ buffer[0] &= map2buff;
- buffer[0] &= tmp[0];
- if (array_elements(buffer) > 1)
- buffer[1] &= tmp[1];
-
- if (array_elements(buffer) <= 2)
- return;
- if (pad_with_ones)
- {
- memset((char*)buffer + 8, 0xff , sizeof(buffer) - 8);
- if (width != sizeof(buffer) * 8)
- {
- ((uchar*)buffer)[sizeof(buffer)-1] = last_byte_mask(width);
- }
- }
- else
- memset((char*)buffer + 8, 0 , sizeof(buffer) - 8);
+ for (size_t i= 1; i < ARRAY_ELEMENTS; i++)
+ buffer[i]= pad_with_ones ? ALL_BITS_SET : 0;
+ if (ARRAY_ELEMENTS > 1 && (width % BITS_PER_ELEMENT) && pad_with_ones)
+ buffer[ARRAY_ELEMENTS - 1]= last_element_mask(width);
}
public:
@@ -140,141 +195,110 @@ public:
{
intersect_and_pad(map2buff, 0);
}
- /* Use highest bit for all bits above sizeof(ulonglong)*8. */
+ /* Use highest bit for all bits above first element. */
void intersect_extended(ulonglong map2buff)
{
intersect_and_pad(map2buff, (map2buff & (1ULL << 63)));
}
- void subtract(Bitmap & map2)
+ void subtract(const Bitmap& map2)
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] &= ~(map2.buffer[i]);
}
- void merge(Bitmap & map2)
+ void merge(const Bitmap& map2)
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
buffer[i] |= map2.buffer[i];
}
- bool is_set(uint n) const
- {
- DBUG_ASSERT(n < width);
- return ((uchar*)buffer)[n / 8] & (1 << (n & 7));
- }
- bool is_prefix(uint prefix_size) const
- {
- uint prefix_mask = last_byte_mask(prefix_size);
- uchar* m = (uchar*)buffer;
- uchar* end_prefix = m + (prefix_size - 1) / 8;
- uchar* end;
- DBUG_ASSERT(prefix_size <= width);
-
- /* Empty prefix is always true */
- if (!prefix_size)
- return true;
-
- while (m < end_prefix)
- if (*m++ != 0xff)
- return false;
-
- end = ((uchar*)buffer) + (width + 7) / 8 - 1;
- if (m == end)
- return ((*m & last_byte_mask(width)) == prefix_mask);
-
- if (*m != prefix_mask)
- return false;
-
- while (++m < end)
- if (*m != 0)
- return false;
- return ((*m & last_byte_mask(width)) == 0);
- }
bool is_clear_all() const
{
- for (size_t i= 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i])
return false;
return true;
}
- bool is_set_all() const
- {
- if (width == sizeof(buffer) * 8)
- {
- for (size_t i = 0; i < array_elements(buffer); i++)
- if (buffer[i] != 0xFFFFFFFFU)
- return false;
- return true;
- }
- else
- return is_prefix(width);
- }
-
- bool is_subset(const Bitmap & map2) const
+ bool is_subset(const Bitmap& map2) const
{
- for (size_t i= 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i] & ~(map2.buffer[i]))
return false;
return true;
}
- bool is_overlapping(const Bitmap & map2) const
+ bool is_overlapping(const Bitmap& map2) const
{
- for (size_t i = 0; i < array_elements(buffer); i++)
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
if (buffer[i] & map2.buffer[i])
return true;
return false;
}
- bool operator==(const Bitmap & map2) const
+ bool operator==(const Bitmap& map2) const
{
- return memcmp(buffer, map2.buffer, sizeof(buffer)) == 0;
+ if (ARRAY_ELEMENTS > 1)
+ return !memcmp(buffer,map2.buffer,sizeof(buffer));
+ return buffer[0] == map2.buffer[0];
}
- bool operator!=(const Bitmap & map2) const
+ bool operator!=(const Bitmap& map2) const
{
return !(*this == map2);
}
+ /*
+ Print hexadecimal representation of bitmap.
+ Truncate trailing zeros.
+ */
char *print(char *buf) const
{
- char *s=buf;
- const uchar *e=(uchar *)buffer, *b=e+sizeof(buffer)-1;
- while (!*b && b>e)
- b--;
- if ((*s=_dig_vec_upper[*b >> 4]) != '0')
- s++;
- *s++=_dig_vec_upper[*b & 15];
- while (--b>=e)
+ size_t last; /*index of the last non-zero element, or 0. */
+
+ for (last= ARRAY_ELEMENTS - 1; last && !buffer[last]; last--){}
+
+ const int HEX_DIGITS_PER_ELEMENT= BITS_PER_ELEMENT / 4;
+ for (size_t i= 0; i < last; i++)
{
- *s++=_dig_vec_upper[*b >> 4];
- *s++=_dig_vec_upper[*b & 15];
+ ulonglong num = buffer[i];
+ uint shift = BITS_PER_ELEMENT - 4;
+ size_t pos= i * HEX_DIGITS_PER_ELEMENT;
+ for (size_t j= 0; j < HEX_DIGITS_PER_ELEMENT; j++)
+ {
+ buf[pos + j]= _dig_vec_upper[(num >> shift) & 0xf];
+ shift += 4;
+ }
}
- *s=0;
+ longlong2str(buffer[last], buf, 16);
return buf;
}
ulonglong to_ulonglong() const
{
- DBUG_ASSERT(sizeof(buffer) >= 4);
- uchar *b=(uchar *)buffer;
- if (sizeof(buffer) >= 8)
- return uint8korr(b);
- return (ulonglong) uint4korr(b);
+ return buffer[0];
}
uint bits_set()
{
- uint res = 0;
- for (size_t i = 0; i < array_elements(buffer); i++)
- res += my_count_bits_uint32(buffer[i]);
+ uint res= 0;
+ for (size_t i= 0; i < ARRAY_ELEMENTS; i++)
+ res += my_count_bits(buffer[i]);
return res;
}
class Iterator
{
- Bitmap &map;
- uint no;
+ const Bitmap& map;
+ uint offset;
+ Table_map_iterator tmi;
public:
- Iterator(Bitmap<width> &map2): map(map2), no(0) {}
- int operator++(int) {
- if (no == width) return BITMAP_END;
- while (!map.is_set(no))
+ Iterator(const Bitmap<width>& map2) : map(map2), offset(0), tmi(map2.buffer[0]) {}
+ int operator++(int)
+ {
+ for (;;)
{
- if ((++no) == width) return BITMAP_END;
+ int nextbit= tmi++;
+
+ if (nextbit != Table_map_iterator::BITMAP_END)
+ return offset + nextbit;
+
+ if (offset + BITS_PER_ELEMENT >= map.length())
+ return BITMAP_END;
+
+ offset += BITS_PER_ELEMENT;
+ tmi= Table_map_iterator(map.buffer[offset / BITS_PER_ELEMENT]);
}
- return no++;
}
enum { BITMAP_END = width };
};
@@ -283,98 +307,8 @@ public:
#pragma GCC pop_options
#undef NEED_GCC_NO_SSE_WORKAROUND
#endif
-
};
-
-/* An iterator to quickly walk over bits in ulonglong bitmap. */
-class Table_map_iterator
-{
- ulonglong bmp;
- uint no;
-public:
- Table_map_iterator(ulonglong t) : bmp(t), no(0) {}
- uint next_bit()
- {
- static const uchar last_bit[16]= {32, 0, 1, 0,
- 2, 0, 1, 0,
- 3, 0, 1, 0,
- 2, 0, 1, 0};
- uint bit;
- while ((bit= last_bit[bmp & 0xF]) == 32)
- {
- no += 4;
- bmp= bmp >> 4;
- if (!bmp)
- return BITMAP_END;
- }
- bmp &= ~(1ULL << bit);
- return no + bit;
- }
- uint operator++(int) { return next_bit(); }
- enum { BITMAP_END= 64 };
-};
-
-template <> class Bitmap<64>
-{
- ulonglong map;
-public:
- Bitmap<64>() { }
- explicit Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); }
- void init(uint prefix_to_set) { set_prefix(prefix_to_set); }
- uint length() const { return 64; }
- void set_bit(uint n) { map|= ((ulonglong)1) << n; }
- void clear_bit(uint n) { map&= ~(((ulonglong)1) << n); }
- void set_prefix(uint n)
- {
- if (n >= length())
- set_all();
- else
- map= (((ulonglong)1) << n)-1;
- }
- void set_all() { map=~(ulonglong)0; }
- void clear_all() { map=(ulonglong)0; }
- void intersect(Bitmap<64>& map2) { map&= map2.map; }
- void intersect(ulonglong map2) { map&= map2; }
- void intersect_extended(ulonglong map2) { map&= map2; }
- void subtract(Bitmap<64>& map2) { map&= ~map2.map; }
- void merge(Bitmap<64>& map2) { map|= map2.map; }
- bool is_set(uint n) const { return MY_TEST(map & (((ulonglong) 1) << n)); }
- bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
- bool is_clear_all() const { return map == (ulonglong)0; }
- bool is_set_all() const { return map == ~(ulonglong)0; }
- bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
- bool is_overlapping(const Bitmap<64>& map2) const { return (map & map2.map)!= 0; }
- bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
- char *print(char *buf) const {
- longlong2str(longlong(map), buf, 16);
- return buf;
- }
- ulonglong to_ulonglong() const { return map; }
- class Iterator : public Table_map_iterator
- {
- public:
- Iterator(Bitmap<64> &map2) : Table_map_iterator(map2.map) {}
- };
- uint bits_set()
- {
- //TODO: use my_count_bits()
- uint res= 0, i= 0;
- for (; i < 64 ; i++)
- {
- if (map & ((ulonglong)1<<i))
- res++;
- }
- return res;
- }
-};
-
-#if MAX_INDEXES <= 64
-typedef Bitmap<64> key_map; /* Used for finding keys */
-#elif MAX_INDEXES > 128
-#error "MAX_INDEXES values greater than 128 is not supported."
-#else
-typedef Bitmap<((MAX_INDEXES+7)/8*8)> key_map; /* Used for finding keys */
-#endif
+typedef Bitmap<MAX_INDEXES> key_map; /* Used for finding keys */
#endif /* SQL_BITMAP_INCLUDED */
diff --git a/sql/sql_builtin.cc.in b/sql/sql_builtin.cc.in
index 5ac044afd5d..810f98a876c 100644
--- a/sql/sql_builtin.cc.in
+++ b/sql/sql_builtin.cc.in
@@ -32,9 +32,6 @@ extern
builtin_maria_plugin
@mysql_mandatory_plugins@ @mysql_optional_plugins@
builtin_maria_binlog_plugin,
-#ifdef WITH_WSREP
- builtin_maria_wsrep_plugin,
-#endif /* WITH_WSREP */
builtin_maria_mysql_password_plugin;
struct st_maria_plugin *mysql_optional_plugins[]=
@@ -45,8 +42,5 @@ struct st_maria_plugin *mysql_optional_plugins[]=
struct st_maria_plugin *mysql_mandatory_plugins[]=
{
builtin_maria_binlog_plugin, builtin_maria_mysql_password_plugin,
-#ifdef WITH_WSREP
- builtin_maria_wsrep_plugin,
-#endif /* WITH_WSREP */
@mysql_mandatory_plugins@ 0
};
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 363c5d35499..4eab241232b 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -129,6 +129,39 @@ bool Key_part_spec::operator==(const Key_part_spec& other) const
&other.field_name);
}
+
+bool Key_part_spec::check_key_for_blob(const handler *file) const
+{
+ if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
+ {
+ my_error(ER_BLOB_USED_AS_KEY, MYF(0), field_name.str, file->table_type());
+ return true;
+ }
+ return false;
+}
+
+
+bool Key_part_spec::check_key_length_for_blob() const
+{
+ if (!length)
+ {
+ my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), field_name.str);
+ return true;
+ }
+ return false;
+}
+
+
+bool Key_part_spec::init_multiple_key_for_blob(const handler *file)
+{
+ if (check_key_for_blob(file))
+ return true;
+ if (!length)
+ length= file->max_key_length() + 1;
+ return false;
+}
+
+
/**
Construct an (almost) deep copy of this key. Only those
elements that are known to never change are not copied.
@@ -420,12 +453,6 @@ void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage,
}
extern "C"
-void **thd_ha_data(const THD *thd, const struct handlerton *hton)
-{
- return (void **) &thd->ha_data[hton->slot].ha_ptr;
-}
-
-extern "C"
void thd_storage_lock_wait(THD *thd, long long value)
{
thd->utime_after_lock+= value;
@@ -437,7 +464,7 @@ void thd_storage_lock_wait(THD *thd, long long value)
extern "C"
void *thd_get_ha_data(const THD *thd, const struct handlerton *hton)
{
- return *thd_ha_data(thd, hton);
+ return thd->ha_data[hton->slot].ha_ptr;
}
@@ -450,6 +477,7 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
const void *ha_data)
{
plugin_ref *lock= &thd->ha_data[hton->slot].lock;
+ thd->ha_data[hton->slot].ha_ptr= const_cast<void*>(ha_data);
if (ha_data && !*lock)
*lock= ha_lock_engine(NULL, (handlerton*) hton);
else if (!ha_data && *lock)
@@ -457,7 +485,6 @@ void thd_set_ha_data(THD *thd, const struct handlerton *hton,
plugin_unlock(NULL, *lock);
*lock= NULL;
}
- *thd_ha_data(thd, hton)= (void*) ha_data;
}
@@ -728,7 +755,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
event_scheduler.data= 0;
event_scheduler.m_psi= 0;
skip_wait_timeout= false;
- extra_port= 0;
catalog= (char*)"std"; // the only catalog we have for now
main_security_ctx.init();
security_ctx= &main_security_ctx;
@@ -2524,8 +2550,7 @@ THD::make_string_literal_charset(const Lex_string_with_metadata_st &str,
{
if (!str.length && (variables.sql_mode & MODE_EMPTY_STRING_IS_NULL))
return new (mem_root) Item_null(this, 0, cs);
- return new (mem_root) Item_string_with_introducer(this,
- str.str, (uint)str.length, cs);
+ return new (mem_root) Item_string_with_introducer(this, str, cs);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 2b46fc69365..152bf0617cd 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -289,6 +289,17 @@ public:
*/
Key_part_spec *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Key_part_spec(*this); }
+ bool check_key_for_blob(const class handler *file) const;
+ bool check_key_length_for_blob() const;
+ bool check_primary_key_for_blob(const class handler *file) const
+ {
+ return check_key_for_blob(file) || check_key_length_for_blob();
+ }
+ bool check_foreign_key_for_blob(const class handler *file) const
+ {
+ return check_key_for_blob(file) || check_key_length_for_blob();
+ }
+ bool init_multiple_key_for_blob(const class handler *file);
};
@@ -3060,7 +3071,6 @@ public:
uint8 password; /* 0, 1 or 2 */
uint8 failed_com_change_user;
bool slave_thread;
- bool extra_port; /* If extra connection */
bool no_errors;
/**
@@ -3628,6 +3638,18 @@ public:
return alloc_root(&transaction.mem_root,size);
}
+ LEX_CSTRING strmake_lex_cstring(const char *str, size_t length)
+ {
+ const char *tmp= strmake_root(mem_root, str, length);
+ if (!tmp)
+ return {0,0};
+ return {tmp, length};
+ }
+ LEX_CSTRING strmake_lex_cstring(const LEX_CSTRING &from)
+ {
+ return strmake_lex_cstring(from.str, from.length);
+ }
+
LEX_STRING *make_lex_string(LEX_STRING *lex_str, const char* str, size_t length)
{
if (!(lex_str->str= strmake_root(mem_root, str, length)))
@@ -6678,6 +6700,45 @@ class Sql_mode_save
};
+class Sql_mode_instant_set: public Sql_mode_save
+{
+public:
+ Sql_mode_instant_set(THD *thd, sql_mode_t temporary_value)
+ :Sql_mode_save(thd)
+ {
+ thd->variables.sql_mode= temporary_value;
+ }
+};
+
+
+class Sql_mode_instant_remove: public Sql_mode_save
+{
+public:
+ Sql_mode_instant_remove(THD *thd, sql_mode_t temporary_remove_flags)
+ :Sql_mode_save(thd)
+ {
+ thd->variables.sql_mode&= ~temporary_remove_flags;
+ }
+};
+
+
+class Abort_on_warning_instant_set
+{
+ THD *m_thd;
+ bool m_save_abort_on_warning;
+public:
+ Abort_on_warning_instant_set(THD *thd, bool temporary_value)
+ :m_thd(thd), m_save_abort_on_warning(thd->abort_on_warning)
+ {
+ thd->abort_on_warning= temporary_value;
+ }
+ ~Abort_on_warning_instant_set()
+ {
+ m_thd->abort_on_warning= m_save_abort_on_warning;
+ }
+};
+
+
/**
This class resembles the SQL Standard schema qualified object name:
<schema qualified name> ::= [ <schema name> <period> ] <qualified identifier>
@@ -6705,8 +6766,8 @@ public:
bool eq(const Database_qualified_name *other) const
{
CHARSET_INFO *cs= lower_case_table_names ?
- &my_charset_utf8_general_ci :
- &my_charset_utf8_bin;
+ &my_charset_utf8mb3_general_ci :
+ &my_charset_utf8mb3_bin;
return
m_db.length == other->m_db.length &&
m_name.length == other->m_name.length &&
@@ -6791,10 +6852,9 @@ public:
class Type_holder: public Sql_alloc,
public Item_args,
public Type_handler_hybrid_field_type,
- public Type_all_attributes,
- public Type_geometry_attributes
+ public Type_all_attributes
{
- TYPELIB *m_typelib;
+ const TYPELIB *m_typelib;
bool m_maybe_null;
public:
Type_holder()
@@ -6817,19 +6877,11 @@ public:
DBUG_ASSERT(0);
return 0;
}
- void set_geometry_type(uint type)
- {
- Type_geometry_attributes::set_geometry_type(type);
- }
- uint uint_geometry_type() const
- {
- return Type_geometry_attributes::get_geometry_type();
- }
- void set_typelib(TYPELIB *typelib)
+ void set_typelib(const TYPELIB *typelib)
{
m_typelib= typelib;
}
- TYPELIB *get_typelib() const
+ const TYPELIB *get_typelib() const
{
return m_typelib;
}
diff --git a/sql/sql_cmd.h b/sql/sql_cmd.h
index 7f1fd06aa46..1f8f2dcabc9 100644
--- a/sql/sql_cmd.h
+++ b/sql/sql_cmd.h
@@ -208,6 +208,26 @@ protected:
}
};
+class Sql_cmd_show_slave_status: public Sql_cmd
+{
+protected:
+ bool show_all_slaves_status;
+public:
+ Sql_cmd_show_slave_status()
+ :show_all_slaves_status(false)
+ {}
+
+ Sql_cmd_show_slave_status(bool status_all)
+ :show_all_slaves_status(status_all)
+ {}
+
+ enum_sql_command sql_command_code() const { return SQLCOM_SHOW_SLAVE_STAT; }
+
+ bool execute(THD *thd);
+ bool is_show_all_slaves_stat() { return show_all_slaves_status; }
+};
+
+
class Sql_cmd_create_table_like: public Sql_cmd,
public Storage_engine_name
{
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index b8fff8c864a..37c4c27c08b 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -43,6 +43,7 @@
#include "wsrep_mysqld.h"
#endif /* WITH_WSREP */
#include "proxy_protocol.h"
+#include <ssl_compat.h>
HASH global_user_stats, global_client_stats, global_table_stats;
HASH global_index_stats;
@@ -1112,7 +1113,6 @@ bool setup_connection_thread_globals(THD *thd)
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
- thd->scheduler->end_thread(thd, 0);
return 1; // Error
}
return 0;
@@ -1303,7 +1303,16 @@ pthread_handler_t handle_one_connection(void *arg)
mysql_thread_set_psi_id(connect->thread_id);
- do_handle_one_connection(connect);
+ if (init_new_connection_handler_thread())
+ connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES);
+ else
+ do_handle_one_connection(connect, true);
+
+ DBUG_PRINT("info", ("killing thread"));
+#if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
+ ERR_remove_state(0);
+#endif
+ my_thread_end();
return 0;
}
@@ -1336,16 +1345,13 @@ bool thd_is_connection_alive(THD *thd)
}
-void do_handle_one_connection(CONNECT *connect)
+void do_handle_one_connection(CONNECT *connect, bool put_in_cache)
{
ulonglong thr_create_utime= microsecond_interval_timer();
THD *thd;
- if (connect->scheduler->init_new_connection_thread() ||
- !(thd= connect->create_thd(NULL)))
+ if (!(thd= connect->create_thd(NULL)))
{
- scheduler_functions *scheduler= connect->scheduler;
- connect->close_with_error(0, 0, ER_OUT_OF_RESOURCES);
- scheduler->end_thread(0, 0);
+ connect->close_and_delete();
return;
}
@@ -1381,7 +1387,11 @@ void do_handle_one_connection(CONNECT *connect)
*/
thd->thread_stack= (char*) &thd;
if (setup_connection_thread_globals(thd))
+ {
+ unlink_thd(thd);
+ delete thd;
return;
+ }
for (;;)
{
@@ -1416,16 +1426,40 @@ end_thread:
if (thd->userstat_running)
update_global_user_stats(thd, create_user, time(NULL));
- if (thd->scheduler->end_thread(thd, 1))
- return; // Probably no-threads
+ unlink_thd(thd);
+ if (IF_WSREP(thd->wsrep_applier, false) || !put_in_cache ||
+ !(connect= cache_thread(thd)))
+ break;
+
+ if (!(connect->create_thd(thd)))
+ {
+ /* Out of resources. Free thread to get more resources */
+ connect->close_and_delete();
+ break;
+ }
+ delete connect;
+
+ /*
+ We have to call store_globals to update mysys_var->id and lock_info
+ with the new thread_id
+ */
+ thd->store_globals();
/*
- If end_thread() returns, this thread has been schedule to
- handle the next connection.
+ Create new instrumentation for the new THD job,
+ and attach it to this running pthread.
*/
- thd= current_thd;
- thd->thread_stack= (char*) &thd;
+ PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection,
+ thd, thd->thread_id));
+
+ /* reset abort flag for the thread */
+ thd->mysys_var->abort= 0;
+ thd->thr_create_utime= microsecond_interval_timer();
+ thd->start_utime= thd->thr_create_utime;
+
+ server_threads.insert(thd);
}
+ delete thd;
}
#endif /* EMBEDDED_LIBRARY */
@@ -1442,10 +1476,16 @@ void CONNECT::close_and_delete()
{
DBUG_ENTER("close_and_delete");
- if (vio)
- vio_close(vio);
- if (thread_count_incremented)
- dec_connection_count(scheduler);
+#if _WIN32
+ if (vio_type == VIO_TYPE_NAMEDPIPE)
+ CloseHandle(pipe);
+ else
+#endif
+ if (vio_type != VIO_CLOSED)
+ mysql_socket_close(sock);
+ vio_type= VIO_CLOSED;
+
+ --*scheduler->connection_count;
statistic_increment(connection_errors_internal, &LOCK_status);
statistic_increment(aborted_connects,&LOCK_status);
@@ -1474,18 +1514,12 @@ void CONNECT::close_with_error(uint sql_errno,
}
-CONNECT::~CONNECT()
-{
- if (vio)
- vio_delete(vio);
-}
-
-
/* Reuse or create a THD based on a CONNECT object */
THD *CONNECT::create_thd(THD *thd)
{
bool res, thd_reused= thd != 0;
+ Vio *vio;
DBUG_ENTER("create_thd");
DBUG_EXECUTE_IF("simulate_failed_connection_2", DBUG_RETURN(0); );
@@ -1504,9 +1538,23 @@ THD *CONNECT::create_thd(THD *thd)
else if (!(thd= new THD(thread_id)))
DBUG_RETURN(0);
+#if _WIN32
+ if (vio_type == VIO_TYPE_NAMEDPIPE)
+ vio= vio_new_win32pipe(pipe);
+ else
+#endif
+ vio= mysql_socket_vio_new(sock, vio_type, vio_type == VIO_TYPE_SOCKET ?
+ VIO_LOCALHOST : 0);
+ if (!vio)
+ {
+ if (!thd_reused)
+ delete thd;
+ DBUG_RETURN(0);
+ }
+
set_current_thd(thd);
res= my_net_init(&thd->net, vio, thd, MYF(MY_THREAD_SPECIFIC));
- vio= 0; // Vio now handled by thd
+ vio_type= VIO_CLOSED; // Vio now handled by thd
if (unlikely(res || thd->is_error()))
{
@@ -1518,9 +1566,11 @@ THD *CONNECT::create_thd(THD *thd)
init_net_server_extension(thd);
- thd->security_ctx->host= host;
- thd->extra_port= extra_port;
+ thd->security_ctx->host= thd->net.vio->type == VIO_TYPE_NAMEDPIPE ||
+ thd->net.vio->type == VIO_TYPE_SOCKET ?
+ my_localhost : 0;
+
thd->scheduler= scheduler;
- thd->real_id= real_id;
+ thd->real_id= pthread_self(); /* Duplicates THD::store_globals() setting. */
DBUG_RETURN(thd);
}
diff --git a/sql/sql_connect.h b/sql/sql_connect.h
index 82ab4423b37..4d62834a6f9 100644
--- a/sql/sql_connect.h
+++ b/sql/sql_connect.h
@@ -21,6 +21,7 @@
#include "structs.h"
#include <mysql/psi/mysql_socket.h>
#include <hash.h>
+#include "violite.h"
/*
Object to hold connect information to be given to the newly created thread
@@ -30,25 +31,24 @@ struct scheduler_functions;
class CONNECT : public ilink {
public:
- /* To be copied to THD */
- Vio *vio; /* Copied to THD with my_net_init() */
- const char *host;
+ MYSQL_SOCKET sock;
+#ifdef _WIN32
+ HANDLE pipe;
+ CONNECT(HANDLE pipe_arg): pipe(pipe_arg), vio_type(VIO_TYPE_NAMEDPIPE),
+ scheduler(thread_scheduler), thread_id(0), prior_thr_create_utime(0) {}
+#endif
+ enum enum_vio_type vio_type;
scheduler_functions *scheduler;
my_thread_id thread_id;
- pthread_t real_id;
- bool extra_port;
/* Own variables */
- bool thread_count_incremented;
ulonglong prior_thr_create_utime;
- CONNECT()
- :vio(0), host(0), scheduler(thread_scheduler), thread_id(0), real_id(0),
- extra_port(0),
- thread_count_incremented(0), prior_thr_create_utime(0)
- {
- };
- ~CONNECT();
+ CONNECT(MYSQL_SOCKET sock_arg, enum enum_vio_type vio_type_arg,
+ scheduler_functions *scheduler_arg): sock(sock_arg),
+ vio_type(vio_type_arg), scheduler(scheduler_arg), thread_id(0),
+ prior_thr_create_utime(0) {}
+ ~CONNECT() { DBUG_ASSERT(vio_type == VIO_CLOSED); }
void close_and_delete();
void close_with_error(uint sql_errno,
const char *message, uint close_error);
@@ -71,7 +71,7 @@ void free_global_index_stats(void);
void free_global_client_stats(void);
pthread_handler_t handle_one_connection(void *arg);
-void do_handle_one_connection(CONNECT *connect);
+void do_handle_one_connection(CONNECT *connect, bool put_in_cache);
bool init_new_connection_handler_thread();
void reset_mqh(LEX_USER *lu, bool get_them);
bool check_mqh(THD *thd, uint check_command);
diff --git a/sql/sql_cte.cc b/sql/sql_cte.cc
index d9141d9a801..eb39cb94cef 100644
--- a/sql/sql_cte.cc
+++ b/sql/sql_cte.cc
@@ -972,7 +972,7 @@ With_element::rename_columns_of_derived_unit(THD *thd,
/* Rename the columns of the first select in the unit */
while ((item= it++, name= nm++))
{
- item->set_name(thd, name->str, (uint) name->length, system_charset_info);
+ item->set_name(thd, *name);
item->is_autogenerated_name= false;
}
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 8f41fe7c70d..b995a841a74 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -284,12 +284,11 @@ int Materialized_cursor::send_result_set_metadata(
*/
while ((item_dst= it_dst++, item_org= it_org++))
{
- Send_field send_field;
Item_ident *ident= static_cast<Item_ident *>(item_dst);
- item_org->make_send_field(thd, &send_field);
+ Send_field send_field(thd, item_org);
- ident->db_name= thd->strdup(send_field.db_name);
- ident->table_name= thd->strdup(send_field.table_name);
+ ident->db_name= thd->strmake_lex_cstring(send_field.db_name);
+ ident->table_name= thd->strmake_lex_cstring(send_field.table_name);
}
/*
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index ddc5234fa01..756955c6f94 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -26,6 +26,7 @@
#include "lock.h" // lock_schema_name
#include "sql_table.h" // build_table_filename,
// filename_to_tablename
+ // validate_comment_length
#include "sql_rename.h" // mysql_rename_tables
#include "sql_acl.h" // SELECT_ACL, DB_ACLS,
// acl_get, check_grant_db
@@ -77,6 +78,7 @@ typedef struct my_dbopt_st
char *name; /* Database name */
uint name_length; /* Database length name */
CHARSET_INFO *charset; /* Database default character set */
+ LEX_STRING comment; /* Database comment */
} my_dbopt_t;
@@ -235,7 +237,8 @@ void my_dbopt_cleanup(void)
1 on error.
*/
-static my_bool get_dbopt(const char *dbname, Schema_specification_st *create)
+static my_bool get_dbopt(THD *thd, const char *dbname,
+ Schema_specification_st *create)
{
my_dbopt_t *opt;
uint length;
@@ -247,6 +250,11 @@ static my_bool get_dbopt(const char *dbname, Schema_specification_st *create)
if ((opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname, length)))
{
create->default_table_charset= opt->charset;
+ if (opt->comment.length)
+ {
+ create->schema_comment= thd->make_clex_string(opt->comment.str,
+ opt->comment.length);
+ }
error= 0;
}
mysql_rwlock_unlock(&LOCK_dboptions);
@@ -274,15 +282,17 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
DBUG_ENTER("put_dbopt");
length= (uint) strlen(dbname);
-
+
mysql_rwlock_wrlock(&LOCK_dboptions);
if (!(opt= (my_dbopt_t*) my_hash_search(&dboptions, (uchar*) dbname,
length)))
{
/* Options are not in the hash, insert them */
char *tmp_name;
+ char *tmp_comment= NULL;
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
+ &tmp_comment, (uint) DATABASE_COMMENT_MAXLEN+1,
NullS))
{
error= 1;
@@ -292,7 +302,7 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
opt->name= tmp_name;
strmov(opt->name, dbname);
opt->name_length= length;
-
+ opt->comment.str= tmp_comment;
if (unlikely((error= my_hash_insert(&dboptions, (uchar*) opt))))
{
my_free(opt);
@@ -303,6 +313,12 @@ static my_bool put_dbopt(const char *dbname, Schema_specification_st *create)
/* Update / write options in hash */
opt->charset= create->default_table_charset;
+ if (create->schema_comment)
+ {
+ strmov(opt->comment.str, create->schema_comment->str);
+ opt->comment.length= create->schema_comment->length;
+ }
+
end:
mysql_rwlock_unlock(&LOCK_dboptions);
DBUG_RETURN(error);
@@ -328,7 +344,8 @@ static void del_dbopt(const char *path)
Create database options file:
DESCRIPTION
- Currently database default charset is only stored there.
+ Currently database default charset, default collation
+ and comment are stored there.
RETURN VALUES
0 ok
@@ -339,9 +356,34 @@ static bool write_db_opt(THD *thd, const char *path,
Schema_specification_st *create)
{
File file;
- char buf[256]; // Should be enough for one option
+ char buf[256+DATABASE_COMMENT_MAXLEN];
bool error=1;
+ if (create->schema_comment)
+ {
+ if (validate_comment_length(thd, create->schema_comment,
+ DATABASE_COMMENT_MAXLEN,
+ ER_TOO_LONG_DATABASE_COMMENT,
+ thd->lex->name.str))
+ return error;
+ }
+
+ if (thd->lex->sql_command == SQLCOM_ALTER_DB &&
+ (!create->schema_comment || !create->default_table_charset))
+ {
+ /* Use existing values of schema_comment and charset for
+ ALTER DATABASE queries */
+ Schema_specification_st tmp;
+ tmp.init();
+ load_db_opt(thd, path, &tmp);
+
+ if (!create->schema_comment)
+ create->schema_comment= tmp.schema_comment;
+
+ if (!create->default_table_charset)
+ create->default_table_charset= tmp.default_table_charset;
+ }
+
if (!create->default_table_charset)
create->default_table_charset= thd->variables.collation_server;
@@ -358,6 +400,11 @@ static bool write_db_opt(THD *thd, const char *path,
create->default_table_charset->name,
"\n", NullS) - buf);
+ if (create->schema_comment)
+ length= (ulong) (strxnmov(buf+length, sizeof(buf)-1-length,
+ "comment=", create->schema_comment->str,
+ "\n", NullS) - buf);
+
/* Error is written by mysql_file_write */
if (!mysql_file_write(file, (uchar*) buf, length, MYF(MY_NABP+MY_WME)))
error=0;
@@ -385,7 +432,7 @@ static bool write_db_opt(THD *thd, const char *path,
bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
{
File file;
- char buf[256];
+ char buf[256+DATABASE_COMMENT_MAXLEN];
DBUG_ENTER("load_db_opt");
bool error=1;
size_t nbytes;
@@ -394,7 +441,7 @@ bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
create->default_table_charset= thd->variables.collation_server;
/* Check if options for this database are already in the hash */
- if (!get_dbopt(path, create))
+ if (!get_dbopt(thd, path, create))
DBUG_RETURN(0);
/* Otherwise, load options from the .opt file */
@@ -444,6 +491,8 @@ bool load_db_opt(THD *thd, const char *path, Schema_specification_st *create)
create->default_table_charset= default_charset_info;
}
}
+ else if (!strncmp(buf, "comment", (pos-buf)))
+ create->schema_comment= thd->make_clex_string(pos+1, strlen(pos+1));
}
}
/*
@@ -544,7 +593,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
Create a database
SYNOPSIS
- mysql_create_db_iternal()
+ mysql_create_db_internal()
thd Thread handler
db Name of database to create
Function assumes that this is already validated.
diff --git a/sql/sql_digest.cc b/sql/sql_digest.cc
index 10a9547d80f..5ca855c9608 100644
--- a/sql/sql_digest.cc
+++ b/sql/sql_digest.cc
@@ -188,7 +188,7 @@ void compute_digest_text(const sql_digest_storage* digest_storage,
/* Convert text to utf8 */
const CHARSET_INFO *from_cs= get_charset(digest_storage->m_charset_number, MYF(0));
- const CHARSET_INFO *to_cs= &my_charset_utf8_bin;
+ const CHARSET_INFO *to_cs= &my_charset_utf8mb3_bin;
if (from_cs == NULL)
{
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index a11a0f454a2..e6dcfed0412 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -744,7 +744,7 @@ void push_warning_printf(THD *thd, Sql_condition::enum_warning_level level,
DBUG_ASSERT(format != NULL);
va_start(args,format);
- my_vsnprintf_ex(&my_charset_utf8_general_ci, warning,
+ my_vsnprintf_ex(&my_charset_utf8mb3_general_ci, warning,
sizeof(warning), format, args);
va_end(args);
push_warning(thd, level, code, warning);
@@ -1009,3 +1009,13 @@ bool is_sqlstate_valid(const LEX_CSTRING *sqlstate)
return true;
}
+
+
+void convert_error_to_warning(THD *thd)
+{
+ DBUG_ASSERT(thd->is_error());
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ thd->get_stmt_da()->sql_errno(),
+ thd->get_stmt_da()->message());
+ thd->clear_error();
+}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index bb83d8af800..a0497af78cb 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -307,16 +307,16 @@ protected:
String m_cursor_name;
Sql_condition_items()
- :m_class_origin((const char*) NULL, 0, & my_charset_utf8_bin),
- m_subclass_origin((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_schema((const char*) NULL, 0, & my_charset_utf8_bin),
- m_constraint_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_catalog_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_schema_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_table_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_column_name((const char*) NULL, 0, & my_charset_utf8_bin),
- m_cursor_name((const char*) NULL, 0, & my_charset_utf8_bin)
+ :m_class_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_subclass_origin((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_catalog((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_schema((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_constraint_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_catalog_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_schema_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_table_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_column_name((const char*) NULL, 0, & my_charset_utf8mb3_bin),
+ m_cursor_name((const char*) NULL, 0, & my_charset_utf8mb3_bin)
{ }
void clear()
@@ -1260,6 +1260,7 @@ private:
///////////////////////////////////////////////////////////////////////////
+void convert_error_to_warning(THD *thd);
void push_warning(THD *thd, Sql_condition::enum_warning_level level,
uint code, const char *msg);
diff --git a/sql/sql_get_diagnostics.cc b/sql/sql_get_diagnostics.cc
index b3ae423b914..197bf5e7a00 100644
--- a/sql/sql_get_diagnostics.cc
+++ b/sql/sql_get_diagnostics.cc
@@ -266,8 +266,8 @@ Condition_information::aggregate(THD *thd, const Diagnostics_area *da)
Item *
Condition_information_item::make_utf8_string_item(THD *thd, const String *str)
{
- /* Default is utf8 character set and utf8_general_ci collation. */
- CHARSET_INFO *to_cs= &my_charset_utf8_general_ci;
+ /* Default is utf8 character set and utf8mb3_general_ci collation. */
+ CHARSET_INFO *to_cs= &my_charset_utf8mb3_general_ci;
/* If a charset was not set, assume that no conversion is needed. */
CHARSET_INFO *from_cs= str->charset() ? str->charset() : to_cs;
String tmp(str->ptr(), str->length(), from_cs);
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index e5f1e958d99..c9307b578fc 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -92,14 +92,12 @@ static bool init_fields(THD *thd, TABLE_LIST *tables,
context->resolve_in_table_list_only(tables);
for (; count-- ; find_fields++)
{
- LEX_CSTRING field_name= {find_fields->field_name,
- strlen(find_fields->field_name) };
/* We have to use 'new' here as field will be re_linked on free */
Item_field *field= (new (thd->mem_root)
Item_field(thd, context,
- "mysql",
- find_fields->table_name,
- &field_name));
+ {STRING_WITH_LEN("mysql")},
+ Lex_cstring_strlen(find_fields->table_name),
+ Lex_cstring_strlen(find_fields->field_name)));
if (!(find_fields->field= find_field_in_tables(thd, field, tables, NULL,
0, REPORT_ALL_ERRORS, 1,
TRUE)))
@@ -858,9 +856,7 @@ error2:
bool mysqld_help(THD *thd, const char *mask)
{
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
bool rc= mysqld_help_internal(thd, mask);
- thd->variables.sql_mode= sql_mode_backup;
return rc;
}
diff --git a/sql/sql_i_s.h b/sql/sql_i_s.h
new file mode 100644
index 00000000000..4ca669a5610
--- /dev/null
+++ b/sql/sql_i_s.h
@@ -0,0 +1,327 @@
+#ifndef SQL_I_S_INCLUDED
+#define SQL_I_S_INCLUDED
+/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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-1335 USA */
+
+#include "sql_const.h" // MAX_FIELD_VARCHARLENGTH
+#include "sql_basic_types.h" // enum_nullability
+#include "sql_string.h" // strlen, MY_CS_NAME_SIZE
+#include "lex_string.h" // LEX_CSTRING
+#include "mysql_com.h" // enum_field_types
+#include "my_time.h" // TIME_SECOND_PART_DIGITS
+#include "sql_type.h" // Type_handler_xxx
+
+struct TABLE_LIST;
+struct TABLE;
+typedef class Item COND;
+
+#ifdef MYSQL_CLIENT
+#error MYSQL_CLIENT must not be defined
+#endif // MYSQL_CLIENT
+
+
+bool schema_table_store_record(THD *thd, TABLE *table);
+COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table);
+
+
+enum enum_show_open_table
+{
+ SKIP_OPEN_TABLE= 0U, // do not open table
+ OPEN_FRM_ONLY= 1U, // open FRM file only
+ OPEN_FULL_TABLE= 2U // open FRM,MYD, MYI files
+};
+
+
+namespace Show {
+class Type
+{
+ /**
+ This denotes data type for the column. For the most part, there seems to
+ be one entry in the enum for each SQL data type, although there seem to
+ be a number of additional entries in the enum.
+ */
+ const Type_handler *m_type_handler;
+ /**
+ For string-type columns, this is the maximum number of
+ characters. Otherwise, it is the 'display-length' for the column.
+ */
+ uint m_char_length;
+ uint m_unsigned_flag;
+ const Typelib *m_typelib;
+public:
+ Type(const Type_handler *th, uint length, uint unsigned_flag,
+ const Typelib *typelib= NULL)
+ :m_type_handler(th), m_char_length(length), m_unsigned_flag(unsigned_flag),
+ m_typelib(typelib)
+ { }
+ const Type_handler *type_handler() const { return m_type_handler; }
+ uint char_length() const { return m_char_length; }
+ uint decimal_precision() const { return (m_char_length / 100) % 100; }
+ uint decimal_scale() const { return m_char_length % 10; }
+ uint fsp() const
+ {
+ DBUG_ASSERT(m_char_length <= TIME_SECOND_PART_DIGITS);
+ return m_char_length;
+ }
+ uint unsigned_flag() const { return m_unsigned_flag; }
+ const Typelib *typelib() const { return m_typelib; }
+};
+} // namespace Show
+
+
+
+class ST_FIELD_INFO: public Show::Type
+{
+protected:
+ LEX_CSTRING m_name; // I_S column name
+ enum_nullability m_nullability; // NULLABLE or NOT NULL
+ LEX_CSTRING m_old_name; // SHOW column name
+ enum_show_open_table m_open_method;
+public:
+ ST_FIELD_INFO(const LEX_CSTRING &name, const Type &type,
+ enum_nullability nullability,
+ LEX_CSTRING &old_name,
+ enum_show_open_table open_method)
+ :Type(type), m_name(name), m_nullability(nullability), m_old_name(old_name),
+ m_open_method(open_method)
+ { }
+ ST_FIELD_INFO(const char *name, const Type &type,
+ enum_nullability nullability,
+ const char *old_name,
+ enum_show_open_table open_method)
+ :Type(type), m_nullability(nullability), m_open_method(open_method)
+ {
+ m_name.str= name;
+ m_name.length= safe_strlen(name);
+ m_old_name.str= old_name;
+ m_old_name.length= safe_strlen(old_name);
+ }
+ const LEX_CSTRING &name() const { return m_name; }
+ bool nullable() const { return m_nullability == NULLABLE; }
+ const LEX_CSTRING &old_name() const { return m_old_name; }
+ enum_show_open_table open_method() const { return m_open_method; }
+ bool end_marker() const { return m_name.str == NULL; }
+};
+
+
+namespace Show
+{
+
+
+class Enum: public Type
+{
+public:
+ Enum(const Typelib *typelib) :Type(&type_handler_enum, 0, false, typelib) { }
+};
+
+
+class Blob: public Type
+{
+public:
+ Blob(uint length) :Type(&type_handler_blob, length, false) { }
+};
+
+
+class Varchar: public Type
+{
+public:
+ Varchar(uint length) :Type(&type_handler_varchar, length, false)
+ {
+ DBUG_ASSERT(length * 3 <= MAX_FIELD_VARCHARLENGTH);
+ }
+};
+
+
+class Longtext: public Type
+{
+public:
+ Longtext(uint length) :Type(&type_handler_varchar, length, false) { }
+};
+
+
+class Yesno: public Varchar
+{
+public:
+ Yesno(): Varchar(3) { }
+};
+
+
+class Catalog: public Varchar
+{
+public:
+ Catalog(): Varchar(FN_REFLEN) { }
+};
+
+
+class Name: public Varchar
+{
+public:
+ Name(): Varchar(NAME_CHAR_LEN) { }
+};
+
+
+class Definer: public Varchar
+{
+public:
+ Definer(): Varchar(DEFINER_CHAR_LENGTH) { }
+};
+
+
+class Userhost: public Varchar
+{
+public:
+ Userhost(): Varchar(USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2) { }
+};
+
+
+class CSName: public Varchar
+{
+public:
+ CSName(): Varchar(MY_CS_NAME_SIZE) { }
+};
+
+
+class SQLMode: public Varchar
+{
+public:
+ SQLMode(): Varchar(32*256) { }
+};
+
+
+class Datetime: public Type
+{
+public:
+ Datetime(uint dec) :Type(&type_handler_datetime2, dec, false) { }
+};
+
+
+class Decimal: public Type
+{
+public:
+ Decimal(uint length) :Type(&type_handler_newdecimal, length, false) { }
+};
+
+
+class ULonglong: public Type
+{
+public:
+ ULonglong(uint length) :Type(&type_handler_ulonglong, length, true) { }
+ ULonglong() :ULonglong(MY_INT64_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class ULong: public Type
+{
+public:
+ ULong(uint length) :Type(&type_handler_ulong, length, true) { }
+ ULong() :ULong(MY_INT32_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SLonglong: public Type
+{
+public:
+ SLonglong(uint length) :Type(&type_handler_slonglong, length, false) { }
+ SLonglong() :SLonglong(MY_INT64_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SLong: public Type
+{
+public:
+ SLong(uint length) :Type(&type_handler_slong, length, false) { }
+ SLong() :SLong(MY_INT32_NUM_DECIMAL_DIGITS) { }
+};
+
+
+class SShort: public Type
+{
+public:
+ SShort(uint length) :Type(&type_handler_sshort, length, false) { }
+};
+
+
+class STiny: public Type
+{
+public:
+ STiny(uint length) :Type(&type_handler_stiny, length, false) { }
+};
+
+
+class Double: public Type
+{
+public:
+ Double(uint length) :Type(&type_handler_double, length, false) { }
+};
+
+
+class Float: public Type
+{
+public:
+ Float(uint length) :Type(&type_handler_float, length, false) { }
+};
+
+
+
+class Column: public ST_FIELD_INFO
+{
+public:
+ Column(const char *name, const Type &type, enum_nullability nullability,
+ const char *old_name,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :ST_FIELD_INFO(name, type, nullability, old_name, open_method)
+ { }
+ Column(const char *name, const Type &type, enum_nullability nullability,
+ enum_show_open_table open_method= SKIP_OPEN_TABLE)
+ :Column(name, type, nullability, NullS, open_method)
+ { }
+};
+
+
+// End marker
+class CEnd: public Column
+{
+public:
+ CEnd() :Column(NullS, Varchar(0), NOT_NULL, NullS, SKIP_OPEN_TABLE) { }
+};
+
+
+} // namespace Show
+
+
+struct TABLE_LIST;
+typedef class Item COND;
+
+typedef struct st_schema_table
+{
+ const char *table_name;
+ ST_FIELD_INFO *fields_info;
+ /* for FLUSH table_name */
+ int (*reset_table) ();
+ /* Fill table with data */
+ int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond);
+ /* Handle fileds for old SHOW */
+ int (*old_format) (THD *thd, struct st_schema_table *schema_table);
+ int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table,
+ bool res, const LEX_CSTRING *db_name,
+ const LEX_CSTRING *table_name);
+ int idx_field1, idx_field2;
+ bool hidden;
+ uint i_s_requested_object; /* the object we need to open(TABLE | VIEW) */
+} ST_SCHEMA_TABLE;
+
+
+#endif // SQL_I_S_INCLUDED
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 7825a7742ef..e8e320e8439 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3659,10 +3659,8 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
if (!res && fields->elements)
{
- bool saved_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= !info.ignore && thd->is_strict_mode();
+ Abort_on_warning_instant_set aws(thd, !info.ignore && thd->is_strict_mode());
res= check_that_all_fields_are_given_values(thd, table_list->table, table_list);
- thd->abort_on_warning= saved_abort_on_warning;
}
if (info.handle_duplicates == DUP_UPDATE && !res)
@@ -4134,11 +4132,11 @@ void select_insert::abort_result_set() {
CREATE TABLE (SELECT) ...
***************************************************************************/
-Field *Item::create_field_for_create_select(TABLE *table)
+Field *Item::create_field_for_create_select(MEM_ROOT *root, TABLE *table)
{
static Tmp_field_param param(false, false, false, false);
Tmp_field_src src;
- return create_tmp_field_ex(table, &src, &param);
+ return create_tmp_field_ex(root, table, &src, &param);
}
@@ -4209,7 +4207,8 @@ TABLE *select_create::create_table_from_items(THD *thd, List<Item> *items,
while ((item=it++))
{
- Field *tmp_field= item->create_field_for_create_select(&tmp_table);
+ Field *tmp_field= item->create_field_for_create_select(thd->mem_root,
+ &tmp_table);
if (!tmp_field)
DBUG_RETURN(NULL);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index a1ee99f29ec..8f6e86fdb48 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -349,7 +349,7 @@ size_t Lex_input_stream::get_body_utf8_maximum_length(THD *thd)
"2" should be a reasonable multiplier that safely covers escaping needs.
*/
return (m_buf_length / thd->variables.character_set_client->mbminlen) *
- my_charset_utf8_bin.mbmaxlen * 2/*for escaping*/;
+ my_charset_utf8mb3_bin.mbmaxlen * 2/*for escaping*/;
}
@@ -454,14 +454,14 @@ extern "C" {
@param end - the end of the destination string
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
+ uchar *str, uchar *end)
{
DBUG_ASSERT(escape > 0);
if (str + 1 >= end)
return MY_CS_TOOSMALL2; // Not enough space, need at least two bytes.
*str= (uchar)escape;
- int cnvres= my_charset_utf8_handler.wc_mb(cs, wc, str + 1, end);
+ int cnvres= my_charset_utf8mb3_handler.wc_mb(cs, wc, str + 1, end);
if (cnvres > 0)
return cnvres + 1; // The character was normally put
if (cnvres == MY_CS_ILUNI)
@@ -483,12 +483,12 @@ int my_wc_mb_utf8_with_escape(CHARSET_INFO *cs, my_wc_t escape, my_wc_t wc,
@param end - the end of the destination string
@returns - a code according to the wc_mb() conversion.
*/
-int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
- my_wc_t wc, my_wc_t escape, my_wc_t ewc,
- uchar *str, uchar *end)
+int my_wc_mb_utf8mb3_opt_escape(CHARSET_INFO *cs,
+ my_wc_t wc, my_wc_t escape, my_wc_t ewc,
+ uchar *str, uchar *end)
{
- return escape ? my_wc_mb_utf8_with_escape(cs, escape, ewc, str, end) :
- my_charset_utf8_handler.wc_mb(cs, wc, str, end);
+ return escape ? my_wc_mb_utf8mb3_with_escape(cs, escape, ewc, str, end) :
+ my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end);
}
/**
@@ -507,54 +507,55 @@ int my_wc_mb_utf8_opt_escape(CHARSET_INFO *cs,
@param escape - the escape character (backslash, or 0)
@returns - a code according to the wc_mb() convension.
*/
-int my_wc_mb_utf8_escape(CHARSET_INFO *cs, my_wc_t wc, uchar *str, uchar *end,
- my_wc_t sep, my_wc_t escape)
+int my_wc_mb_utf8mb3_escape(CHARSET_INFO *cs, my_wc_t wc,
+ uchar *str, uchar *end,
+ my_wc_t sep, my_wc_t escape)
{
DBUG_ASSERT(escape == 0 || escape == '\\');
DBUG_ASSERT(sep == '"' || sep == '\'');
switch (wc) {
- case 0: return my_wc_mb_utf8_opt_escape(cs, wc, escape, '0', str, end);
- case '\t': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 't', str, end);
- case '\r': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'r', str, end);
- case '\n': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'n', str, end);
- case '\032': return my_wc_mb_utf8_opt_escape(cs, wc, escape, 'Z', str, end);
+ case 0: return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, '0', str, end);
+ case '\t': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 't', str, end);
+ case '\r': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'r', str, end);
+ case '\n': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'n', str, end);
+ case '\032': return my_wc_mb_utf8mb3_opt_escape(cs, wc, escape, 'Z', str, end);
case '\'':
case '\"':
if (wc == sep)
- return my_wc_mb_utf8_with_escape(cs, wc, wc, str, end);
+ return my_wc_mb_utf8mb3_with_escape(cs, wc, wc, str, end);
}
- return my_charset_utf8_handler.wc_mb(cs, wc, str, end); // No escaping needed
+ return my_charset_utf8mb3_handler.wc_mb(cs, wc, str, end); // No escaping needed
}
/** wc_mb() compatible routines for all sql_mode and delimiter combinations */
-int my_wc_mb_utf8_escape_single_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_single_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', '\\');
}
-int my_wc_mb_utf8_escape_double_quote_and_backslash(CHARSET_INFO *cs,
+int my_wc_mb_utf8mb3_escape_double_quote_and_backslash(CHARSET_INFO *cs,
my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', '\\');
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', '\\');
}
-int my_wc_mb_utf8_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_single_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '\'', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '\'', 0);
}
-int my_wc_mb_utf8_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
+int my_wc_mb_utf8mb3_escape_double_quote(CHARSET_INFO *cs, my_wc_t wc,
uchar *str, uchar *end)
{
- return my_wc_mb_utf8_escape(cs, wc, str, end, '"', 0);
+ return my_wc_mb_utf8mb3_escape(cs, wc, str, end, '"', 0);
}
}; // End of extern "C"
@@ -568,10 +569,10 @@ my_charset_conv_wc_mb
Lex_input_stream::get_escape_func(THD *thd, my_wc_t sep) const
{
return thd->backslash_escapes() ?
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote_and_backslash:
- my_wc_mb_utf8_escape_single_quote_and_backslash) :
- (sep == '"' ? my_wc_mb_utf8_escape_double_quote:
- my_wc_mb_utf8_escape_single_quote);
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote_and_backslash:
+ my_wc_mb_utf8mb3_escape_single_quote_and_backslash) :
+ (sep == '"' ? my_wc_mb_utf8mb3_escape_double_quote:
+ my_wc_mb_utf8mb3_escape_single_quote);
}
@@ -611,7 +612,7 @@ void Lex_input_stream::body_utf8_append_escape(THD *thd,
DBUG_ASSERT(m_body_utf8 + get_body_utf8_maximum_length(thd) >=
m_body_utf8_ptr + txt->length * 2);
uint32 cnv_length= my_convert_using_func(m_body_utf8_ptr, txt->length * 2,
- &my_charset_utf8_general_ci,
+ &my_charset_utf8mb3_general_ci,
get_escape_func(thd, sep),
txt->str, txt->length,
cs, cs->cset->mb_wc,
@@ -944,6 +945,9 @@ bool is_native_function(THD *thd, const LEX_CSTRING *name)
if (is_lex_native_function(name))
return true;
+ if (Type_handler::handler_by_name(*name))
+ return true;
+
return false;
}
@@ -2024,7 +2028,7 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
next_state= MY_LEX_HOSTNAME;
break;
}
- yylval->lex_str.str= (char*) get_ptr();
+ yylval->lex_str.str= (char*) get_ptr() - 1;
yylval->lex_str.length= 1;
return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname
@@ -5400,8 +5404,7 @@ LEX::wrap_unit_into_derived(SELECT_LEX_UNIT *unit)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5463,8 +5466,7 @@ SELECT_LEX *LEX::wrap_select_chain_into_derived(SELECT_LEX *sel)
/* add SELECT list*/
{
- Item *item= new (thd->mem_root)
- Item_field(thd, context, NULL, NULL, &star_clex_str);
+ Item *item= new (thd->mem_root) Item_field(thd, context, star_clex_str);
if (item == NULL)
goto err;
if (add_item_to_list(thd, item))
@@ -5597,6 +5599,7 @@ void LEX::set_stmt_init()
mysql_init_select(this);
option_type= OPT_SESSION;
autocommit= 0;
+ var_list.empty();
};
@@ -5976,9 +5979,9 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_CSTRING *name,
sp_variable *spvar= spcont->add_variable(thd, name);
spcont->declare_var_boundary(1);
spvar->field_def.field_name= spvar->name;
- spvar->field_def.set_handler(&type_handler_longlong);
- type_handler_longlong.Column_definition_prepare_stage2(&spvar->field_def,
- NULL, HA_CAN_GEOMETRY);
+ spvar->field_def.set_handler(&type_handler_slonglong);
+ type_handler_slonglong.Column_definition_prepare_stage2(&spvar->field_def,
+ NULL, HA_CAN_GEOMETRY);
if (!value && unlikely(!(value= new (thd->mem_root) Item_null(thd))))
return NULL;
@@ -6021,7 +6024,7 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd,
SELECT rec.a, rec.b;
END FOR;
*/
- if (!(item= new (thd->mem_root) Item_field(thd, NULL, NullS, NullS, &name)))
+ if (!(item= new (thd->mem_root) Item_field(thd, NULL, name)))
return true;
bounds->m_index->set_item_and_free_list(item, NULL);
if (thd->lex->sphead->restore_lex(thd))
@@ -6174,7 +6177,7 @@ bool LEX::sp_for_loop_cursor_declarations(THD *thd,
name= item_splocal->m_name;
else if ((item_field= item->type() == Item::FIELD_ITEM ?
static_cast<Item_field *>(item) : NULL) &&
- item_field->table_name == NULL)
+ item_field->table_name.str == NULL)
name= item_field->field_name;
else if (item->type() == Item::FUNC_ITEM &&
static_cast<Item_func*>(item)->functype() == Item_func::FUNC_SP &&
@@ -7030,7 +7033,7 @@ Item *LEX::create_and_link_Item_trigger_field(THD *thd,
new_row ?
Item_trigger_field::NEW_ROW:
Item_trigger_field::OLD_ROW,
- name, SELECT_ACL, tmp_read_only);
+ *name, SELECT_ACL, tmp_read_only);
/*
Let us add this item to list of all Item_trigger_field objects
in trigger.
@@ -7179,7 +7182,7 @@ Item *LEX::create_item_for_loop_bound(THD *thd,
Pass NULL as the name resolution context.
This is OK, fix_fields() won't be called for this Item_field.
*/
- return new (thd->mem_root) Item_field(thd, NULL, a->str, b->str, c);
+ return new (thd->mem_root) Item_field(thd, NULL, *a, *b, *c);
}
@@ -7217,7 +7220,7 @@ Item *LEX::create_item_ident_nospvar(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, a, b);
- return create_item_ident_field(thd, NullS, a->str, b);
+ return create_item_ident_field(thd, Lex_ident_sys(), *a, *b);
}
@@ -7409,9 +7412,8 @@ Item *LEX::create_item_ident(THD *thd,
const Lex_ident_sys_st *b,
const Lex_ident_sys_st *c)
{
- const char *schema= (thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str);
-
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if ((thd->variables.sql_mode & MODE_ORACLE) && c->length == 7)
{
if (!my_strnncoll(system_charset_info,
@@ -7433,7 +7435,7 @@ Item *LEX::create_item_ident(THD *thd,
if (current_select->parsing_place == FOR_LOOP_BOUND)
return create_item_for_loop_bound(thd, &null_clex_str, b, c);
- return create_item_ident_field(thd, schema, b->str, c);
+ return create_item_ident_field(thd, schema, *b, *c);
}
@@ -7519,11 +7521,12 @@ bool LEX::set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val)
}
-Item *LEX::create_item_ident_field(THD *thd, const char *db,
- const char *table,
- const Lex_ident_sys_st *name)
+Item *LEX::create_item_ident_field(THD *thd,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &table,
+ const Lex_ident_sys_st &name)
{
- if (check_expr_allows_fields_or_error(thd, name->str))
+ if (check_expr_allows_fields_or_error(thd, name.str))
return NULL;
if (current_select->parsing_place != IN_HAVING ||
@@ -7592,7 +7595,7 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
-bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
+bool LEX::set_variable(const Lex_ident_sys_st *name, Item *item)
{
sp_pcontext *ctx;
const Sp_rcontext_handler *rh;
@@ -7606,8 +7609,8 @@ bool LEX::set_variable(const LEX_CSTRING *name, Item *item)
Generate instructions for:
SET x.y= expr;
*/
-bool LEX::set_variable(const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+bool LEX::set_variable(const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *item)
{
const Sp_rcontext_handler *rh;
@@ -7637,10 +7640,10 @@ bool LEX::set_variable(const LEX_CSTRING *name1,
bool LEX::set_default_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
- static LEX_CSTRING default_base_name= {STRING_WITH_LEN("default")};
+ static Lex_ident_sys default_base_name= {STRING_WITH_LEN("default")};
sys_var *var= find_sys_var(thd, name->str, name->length);
if (!var)
return true;
@@ -7654,18 +7657,19 @@ bool LEX::set_default_system_variable(enum_var_type var_type,
bool LEX::set_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val)
{
sys_var *var= find_sys_var(thd, name->str, name->length);
DBUG_ASSERT(thd->is_error() || var != NULL);
- return likely(var) ? set_system_variable(var_type, var, &null_clex_str, val) : true;
+ static Lex_ident_sys null_str;
+ return likely(var) ? set_system_variable(var_type, var, &null_str, val) : true;
}
bool LEX::set_system_variable(THD *thd, enum_var_type var_type,
- const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+ const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *val)
{
sys_var *tmp;
@@ -8347,15 +8351,15 @@ bool LEX::call_statement_start(THD *thd, sp_name *name)
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name)
{
sp_name *spname= make_sp_name(thd, name);
return unlikely(!spname) || call_statement_start(thd, spname);
}
-bool LEX::call_statement_start(THD *thd, const LEX_CSTRING *name1,
- const LEX_CSTRING *name2)
+bool LEX::call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2)
{
sp_name *spname= make_sp_name(thd, name1, name2);
return unlikely(!spname) || call_statement_start(thd, spname);
@@ -8504,9 +8508,9 @@ bool SELECT_LEX::vers_push_field(THD *thd, TABLE_LIST *table,
{
DBUG_ASSERT(field_name.str);
Item_field *fld= new (thd->mem_root) Item_field(thd, &context,
- table->db.str,
- table->alias.str,
- &field_name);
+ table->db,
+ table->alias,
+ field_name);
if (unlikely(!fld) || unlikely(item_list.push_back(fld)))
return true;
@@ -8619,13 +8623,27 @@ Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
}
+Item *LEX::make_item_func_call_native_or_parse_error(THD *thd,
+ Lex_ident_cli_st &name,
+ List<Item> *args)
+{
+ Create_func *builder= find_native_function_builder(thd, &name);
+ DBUG_EXECUTE_IF("make_item_func_call_native_simulate_not_found",
+ builder= NULL;);
+ if (builder)
+ return builder->create_func(thd, &name, args);
+ thd->parse_error(ER_SYNTAX_ERROR, name.end());
+ return NULL;
+}
+
+
Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *name)
{
Item *item;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- NullS, name->str,
- &star_clex_str)))
+ null_clex_str, *name,
+ star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -8637,11 +8655,10 @@ Item *LEX::create_item_qualified_asterisk(THD *thd,
const Lex_ident_sys_st *b)
{
Item *item;
- const char* schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
- NullS : a->str;
+ Lex_ident_sys_st schema= thd->client_capabilities & CLIENT_NO_SCHEMA ?
+ Lex_ident_sys() : *a;
if (!(item= new (thd->mem_root) Item_field(thd, current_context(),
- schema, b->str,
- &star_clex_str)))
+ schema, *b, star_clex_str)))
return NULL;
current_select->with_wild++;
return item;
@@ -10461,3 +10478,32 @@ Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
init_last_field(res, &name, thd->variables.collation_database);
return res;
}
+
+
+Item *
+Lex_cast_type_st::create_typecast_item_or_error(THD *thd, Item *item,
+ CHARSET_INFO *cs) const
+{
+ Item *tmp= create_typecast_item(thd, item, cs);
+ if (!tmp)
+ {
+ Name name= m_type_handler->name();
+ char buf[128];
+ size_t length= my_snprintf(buf, sizeof(buf), "CAST(expr AS %.*s)",
+ (int) name.length(), name.ptr());
+ my_error(ER_UNKNOWN_OPERATOR, MYF(0),
+ ErrConvString(buf, length, system_charset_info).ptr());
+ }
+ return tmp;
+}
+
+
+void Lex_field_type_st::set_handler_length_flags(const Type_handler *handler,
+ const char *length,
+ uint32 flags)
+{
+ DBUG_ASSERT(!handler->is_unsigned());
+ if (flags & UNSIGNED_FLAG)
+ handler= handler->type_handler_unsigned();
+ set(handler, length, NULL);
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index d351378a9a6..b916d07ba7c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -3728,15 +3728,15 @@ public:
bool set_trigger_field(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
Item *val);
bool set_system_variable(enum_var_type var_type, sys_var *var,
- const LEX_CSTRING *base_name, Item *val);
- bool set_system_variable(enum_var_type var_type, const LEX_CSTRING *name,
- Item *val);
+ const Lex_ident_sys_st *base_name, Item *val);
+ bool set_system_variable(enum_var_type var_type,
+ const Lex_ident_sys_st *name, Item *val);
bool set_system_variable(THD *thd, enum_var_type var_type,
- const LEX_CSTRING *name1,
- const LEX_CSTRING *name2,
+ const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2,
Item *val);
bool set_default_system_variable(enum_var_type var_type,
- const LEX_CSTRING *name,
+ const Lex_ident_sys_st *name,
Item *val);
bool set_user_variable(THD *thd, const LEX_CSTRING *name, Item *val);
void set_stmt_init();
@@ -3766,9 +3766,9 @@ public:
const char *body_start,
const char *body_end);
bool call_statement_start(THD *thd, sp_name *name);
- bool call_statement_start(THD *thd, const LEX_CSTRING *name);
- bool call_statement_start(THD *thd, const LEX_CSTRING *name1,
- const LEX_CSTRING *name2);
+ bool call_statement_start(THD *thd, const Lex_ident_sys_st *name);
+ bool call_statement_start(THD *thd, const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2);
sp_variable *find_variable(const LEX_CSTRING *name,
sp_pcontext **ctx,
const Sp_rcontext_handler **rh) const;
@@ -3778,9 +3778,9 @@ public:
sp_pcontext *not_used_ctx;
return find_variable(name, &not_used_ctx, rh);
}
- bool set_variable(const LEX_CSTRING *name, Item *item);
- bool set_variable(const LEX_CSTRING *name1, const LEX_CSTRING *name2,
- Item *item);
+ bool set_variable(const Lex_ident_sys_st *name, Item *item);
+ bool set_variable(const Lex_ident_sys_st *name1,
+ const Lex_ident_sys_st *name2, Item *item);
void sp_variable_declarations_init(THD *thd, int nvars);
bool sp_variable_declarations_finalize(THD *thd, int nvars,
const Column_definition *cdef,
@@ -3845,11 +3845,13 @@ public:
return create_item_qualified_asterisk(thd, &a, &b);
}
- Item *create_item_ident_field(THD *thd, const char *db, const char *table,
- const Lex_ident_sys_st *name);
+ Item *create_item_ident_field(THD *thd,
+ const Lex_ident_sys_st &db,
+ const Lex_ident_sys_st &table,
+ const Lex_ident_sys_st &name);
Item *create_item_ident_nosp(THD *thd, Lex_ident_sys_st *name)
{
- return create_item_ident_field(thd, NullS, NullS, name);
+ return create_item_ident_field(thd, Lex_ident_sys(), Lex_ident_sys(), *name);
}
Item *create_item_ident_sp(THD *thd, Lex_ident_sys_st *name,
const char *start, const char *end);
@@ -3997,6 +3999,9 @@ public:
Item *make_item_func_substr(THD *thd, Item *a, Item *b);
Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db,
Lex_ident_cli_st *name, List<Item> *args);
+ Item *make_item_func_call_native_or_parse_error(THD *thd,
+ Lex_ident_cli_st &name,
+ List<Item> *args);
my_var *create_outvar(THD *thd, const LEX_CSTRING *name);
/*
@@ -4424,6 +4429,12 @@ public:
SELECT_LEX_UNIT *create_unit(SELECT_LEX*);
SELECT_LEX *wrap_unit_into_derived(SELECT_LEX_UNIT *unit);
SELECT_LEX *wrap_select_chain_into_derived(SELECT_LEX *sel);
+ void init_select()
+ {
+ current_select->init_select();
+ wild= 0;
+ exchange= 0;
+ }
bool main_select_push();
bool insert_select_hack(SELECT_LEX *sel);
SELECT_LEX *create_priority_nest(SELECT_LEX *first_in_nest);
@@ -4735,6 +4746,22 @@ public:
};
+class sp_lex_set_var: public sp_lex_local
+{
+public:
+ sp_lex_set_var(THD *thd, const LEX *oldlex)
+ :sp_lex_local(thd, oldlex)
+ {
+ // Set new LEX as if we at start of set rule
+ init_select();
+ sql_command= SQLCOM_SET_OPTION;
+ var_list.empty();
+ autocommit= 0;
+ option_type= oldlex->option_type; // Inherit from the outer lex
+ }
+};
+
+
/**
An assignment specific LEX, which additionally has an Item (an expression)
and an associated with the Item free_list, which is usually freed
@@ -4814,8 +4841,9 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr);
Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
Item *expr);
-void sp_create_assignment_lex(THD *thd, bool no_lookahead);
-bool sp_create_assignment_instr(THD *thd, bool no_lookahead);
+bool sp_create_assignment_lex(THD *thd, const char *pos);
+bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
+ bool need_set_keyword= true);
void mark_or_conds_to_avoid_pushdown(Item *cond);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index ccc180607ed..a030f547d59 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4095,31 +4095,7 @@ mysql_execute_command(THD *thd)
mysql_mutex_unlock(&LOCK_active_mi);
break;
}
- case SQLCOM_SHOW_SLAVE_STAT:
- {
- /* Accept one of two privileges */
- if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
- goto error;
- if (lex->verbose)
- {
- mysql_mutex_lock(&LOCK_active_mi);
- res= show_all_master_info(thd);
- mysql_mutex_unlock(&LOCK_active_mi);
- }
- else
- {
- LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
- Master_info *mi;
- if ((mi= get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR)))
- {
- res= show_master_info(thd, mi, 0);
- mi->release();
- }
- }
- break;
- }
case SQLCOM_SHOW_MASTER_STAT:
{
/* Accept one of two privileges */
@@ -6090,12 +6066,15 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(first_table == all_tables && first_table != 0);
/* fall through */
case SQLCOM_ALTER_SEQUENCE:
+ case SQLCOM_SHOW_SLAVE_STAT:
case SQLCOM_SIGNAL:
case SQLCOM_RESIGNAL:
case SQLCOM_GET_DIAGNOSTICS:
case SQLCOM_CALL:
DBUG_ASSERT(lex->m_sql_cmd != NULL);
res= lex->m_sql_cmd->execute(thd);
+ DBUG_PRINT("result", ("res: %d killed: %d is_error: %d",
+ res, thd->killed, thd->is_error()));
break;
default:
@@ -7502,10 +7481,7 @@ void THD::reset_for_next_command(bool do_clear_error)
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex= lex->current_select;
- select_lex->init_select();
- lex->wild= 0;
- lex->exchange= 0;
+ lex->init_select();
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 811d7fd2529..e24a8962dcd 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -2584,11 +2584,9 @@ char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info,
HA_CREATE_INFO *create_info,
Alter_info *alter_info)
{
- sql_mode_t old_mode= thd->variables.sql_mode;
- thd->variables.sql_mode &= ~MODE_ANSI_QUOTES;
+ Sql_mode_instant_remove sms(thd, MODE_ANSI_QUOTES);
char *res= generate_partition_syntax(thd, part_info, buf_length,
true, create_info, alter_info);
- thd->variables.sql_mode= old_mode;
return res;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 8088b6923f2..5a4e13603a1 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -739,6 +739,8 @@ void Item_param::setup_conversion(THD *thd, uchar param_type)
*/
if (!h)
h= &type_handler_string;
+ else if (unsigned_flag)
+ h= h->type_handler_unsigned();
set_handler(h);
h->Item_param_setup_conversion(thd, this);
}
@@ -1933,14 +1935,15 @@ static int mysql_test_show_grants(Prepared_statement *stmt)
TRUE error, error message is set in THD
*/
-static int mysql_test_show_slave_status(Prepared_statement *stmt)
+static int mysql_test_show_slave_status(Prepared_statement *stmt,
+ bool show_all_slaves_stat)
{
DBUG_ENTER("mysql_test_show_slave_status");
THD *thd= stmt->thd;
List<Item> fields;
- show_master_info_get_fields(thd, &fields, thd->lex->verbose, 0);
-
+ show_master_info_get_fields(thd, &fields, show_all_slaves_stat, 0);
+
DBUG_RETURN(send_stmt_metadata(thd, stmt, &fields));
}
@@ -2393,12 +2396,20 @@ static bool check_prepared_statement(Prepared_statement *stmt)
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_SLAVE_STAT:
- if ((res= mysql_test_show_slave_status(stmt)) == 2)
{
- /* Statement and field info has already been sent */
- DBUG_RETURN(FALSE);
+ DBUG_ASSERT(thd->lex->m_sql_cmd);
+ Sql_cmd_show_slave_status *cmd;
+ cmd= dynamic_cast<Sql_cmd_show_slave_status*>(thd->lex->m_sql_cmd);
+ DBUG_ASSERT(cmd);
+ if ((res= mysql_test_show_slave_status(stmt,
+ cmd->is_show_all_slaves_stat()))
+ == 2)
+ {
+ /* Statement and field info has already been sent */
+ DBUG_RETURN(FALSE);
+ }
+ break;
}
- break;
case SQLCOM_SHOW_MASTER_STAT:
if ((res= mysql_test_show_master_status(stmt)) == 2)
{
@@ -4499,12 +4510,11 @@ Prepared_statement::reprepare()
TRUE, &cur_db_changed)))
return TRUE;
- sql_mode_t save_sql_mode= thd->variables.sql_mode;
- thd->variables.sql_mode= m_sql_mode;
+ Sql_mode_instant_set sms(thd, m_sql_mode);
+
error= ((name.str && copy.set_name(&name)) ||
copy.prepare(query(), query_length()) ||
validate_metadata(&copy));
- thd->variables.sql_mode= save_sql_mode;
if (cur_db_changed)
mysql_change_db(thd, (LEX_CSTRING*) &saved_cur_db_name, TRUE);
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index f36805012b2..5949287ea8d 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -32,7 +32,7 @@
#include "mariadb.h"
#include "sql_priv.h"
#include "sql_profile.h"
-#include "sql_show.h" // schema_table_store_record
+#include "sql_i_s.h" // schema_table_store_record
#include "sql_class.h" // THD
#ifdef _WIN32
@@ -60,30 +60,32 @@ int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables,
#endif
}
+namespace Show {
+
ST_FIELD_INFO query_profile_statistics_info[]=
{
- /* name, length, type, value, maybe_null, old_name, open_method */
- {"QUERY_ID", 20, MYSQL_TYPE_LONG, 0, false, "Query_id", SKIP_OPEN_TABLE},
- {"SEQ", 20, MYSQL_TYPE_LONG, 0, false, "Seq", SKIP_OPEN_TABLE},
- {"STATE", 30, MYSQL_TYPE_STRING, 0, false, "Status", SKIP_OPEN_TABLE},
- {"DURATION", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, false, "Duration", SKIP_OPEN_TABLE},
- {"CPU_USER", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, true, "CPU_user", SKIP_OPEN_TABLE},
- {"CPU_SYSTEM", TIME_I_S_DECIMAL_SIZE, MYSQL_TYPE_DECIMAL, 0, true, "CPU_system", SKIP_OPEN_TABLE},
- {"CONTEXT_VOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_voluntary", SKIP_OPEN_TABLE},
- {"CONTEXT_INVOLUNTARY", 20, MYSQL_TYPE_LONG, 0, true, "Context_involuntary", SKIP_OPEN_TABLE},
- {"BLOCK_OPS_IN", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_in", SKIP_OPEN_TABLE},
- {"BLOCK_OPS_OUT", 20, MYSQL_TYPE_LONG, 0, true, "Block_ops_out", SKIP_OPEN_TABLE},
- {"MESSAGES_SENT", 20, MYSQL_TYPE_LONG, 0, true, "Messages_sent", SKIP_OPEN_TABLE},
- {"MESSAGES_RECEIVED", 20, MYSQL_TYPE_LONG, 0, true, "Messages_received", SKIP_OPEN_TABLE},
- {"PAGE_FAULTS_MAJOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_major", SKIP_OPEN_TABLE},
- {"PAGE_FAULTS_MINOR", 20, MYSQL_TYPE_LONG, 0, true, "Page_faults_minor", SKIP_OPEN_TABLE},
- {"SWAPS", 20, MYSQL_TYPE_LONG, 0, true, "Swaps", SKIP_OPEN_TABLE},
- {"SOURCE_FUNCTION", 30, MYSQL_TYPE_STRING, 0, true, "Source_function", SKIP_OPEN_TABLE},
- {"SOURCE_FILE", 20, MYSQL_TYPE_STRING, 0, true, "Source_file", SKIP_OPEN_TABLE},
- {"SOURCE_LINE", 20, MYSQL_TYPE_LONG, 0, true, "Source_line", SKIP_OPEN_TABLE},
- {NULL, 0, MYSQL_TYPE_STRING, 0, true, NULL, 0}
+ Column("QUERY_ID", SLong(20), NOT_NULL, "Query_id"),
+ Column("SEQ", SLong(20), NOT_NULL, "Seq"),
+ Column("STATE", Varchar(30), NOT_NULL, "Status"),
+ Column("DURATION", Decimal(TIME_I_S_DECIMAL_SIZE), NOT_NULL, "Duration"),
+ Column("CPU_USER", Decimal(TIME_I_S_DECIMAL_SIZE), NULLABLE, "CPU_user"),
+ Column("CPU_SYSTEM", Decimal(TIME_I_S_DECIMAL_SIZE), NULLABLE, "CPU_system"),
+ Column("CONTEXT_VOLUNTARY", SLong(20), NULLABLE, "Context_voluntary"),
+ Column("CONTEXT_INVOLUNTARY", SLong(20), NULLABLE, "Context_involuntary"),
+ Column("BLOCK_OPS_IN", SLong(20), NULLABLE, "Block_ops_in"),
+ Column("BLOCK_OPS_OUT", SLong(20), NULLABLE, "Block_ops_out"),
+ Column("MESSAGES_SENT", SLong(20), NULLABLE, "Messages_sent"),
+ Column("MESSAGES_RECEIVED", SLong(20), NULLABLE, "Messages_received"),
+ Column("PAGE_FAULTS_MAJOR", SLong(20), NULLABLE, "Page_faults_major"),
+ Column("PAGE_FAULTS_MINOR", SLong(20), NULLABLE, "Page_faults_minor"),
+ Column("SWAPS", SLong(20), NULLABLE, "Swaps"),
+ Column("SOURCE_FUNCTION", Varchar(30), NULLABLE, "Source_function"),
+ Column("SOURCE_FILE", Varchar(20), NULLABLE, "Source_file"),
+ Column("SOURCE_LINE", SLong(20), NULLABLE, "Source_line"),
+ CEnd()
};
+} // namespace Show
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
@@ -113,21 +115,17 @@ int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table)
Name_resolution_context *context= &thd->lex->first_select_lex()->context;
int i;
- for (i= 0; schema_table->fields_info[i].field_name != NULL; i++)
+ for (i= 0; !schema_table->fields_info[i].end_marker(); i++)
{
if (! fields_include_condition_truth_values[i])
continue;
field_info= &schema_table->fields_info[i];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- (uint) strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index 5b03acf59c0..b0b1642ee02 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -19,10 +19,13 @@
class Item;
struct TABLE_LIST;
class THD;
-typedef struct st_field_info ST_FIELD_INFO;
+class ST_FIELD_INFO;
typedef struct st_schema_table ST_SCHEMA_TABLE;
+namespace Show {
extern ST_FIELD_INFO query_profile_statistics_info[];
+} // namespace Show
+
int fill_query_profile_statistics_info(THD *thd, TABLE_LIST *tables, Item *cond);
int make_profile_table_for_show(THD *thd, ST_SCHEMA_TABLE *schema_table);
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index 0e166b169aa..5562de8d8d5 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -133,7 +133,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
logger.flush_general_log();
if (options & REFRESH_ENGINE_LOG)
- if (ha_flush_logs(NULL))
+ if (ha_flush_logs())
result= 1;
if (options & REFRESH_BINARY_LOG)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e79e96bf210..0e8f331f2cf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -566,9 +566,9 @@ fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
new_ref= direct_ref ?
new (thd->mem_root) Item_direct_ref(thd, ref->context, item_ref, ref->table_name,
- &ref->field_name, ref->alias_name_used) :
+ ref->field_name, ref->alias_name_used) :
new (thd->mem_root) Item_ref(thd, ref->context, item_ref, ref->table_name,
- &ref->field_name, ref->alias_name_used);
+ ref->field_name, ref->alias_name_used);
if (!new_ref)
return TRUE;
ref->outer_ref= new_ref;
@@ -774,11 +774,11 @@ Item* period_get_condition(THD *thd, TABLE_LIST *table, SELECT_LEX *select,
const LEX_CSTRING &fend= period->end_field(share)->field_name;
conds->field_start= newx Item_field(thd, &select->context,
- table->db.str, table->alias.str,
- thd->make_clex_string(fstart));
+ table->db, table->alias,
+ thd->strmake_lex_cstring(fstart));
conds->field_end= newx Item_field(thd, &select->context,
- table->db.str, table->alias.str,
- thd->make_clex_string(fend));
+ table->db, table->alias,
+ thd->strmake_lex_cstring(fend));
Item *cond1= NULL, *cond2= NULL, *cond3= NULL, *curr= NULL;
if (timestamp)
@@ -6917,7 +6917,6 @@ void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
}
}
-
/**
Check for the presence of AGGFN(DISTINCT a) queries that may be subject
to loose index scan.
@@ -6955,7 +6954,6 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
{
Item_sum **sum_item_ptr;
bool result= false;
- Field_map first_aggdistinct_fields;
if (join->table_count != 1 || /* reference more than 1 table */
join->select_distinct || /* or a DISTINCT */
@@ -6965,10 +6963,11 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
if (join->make_sum_func_list(join->all_fields, join->fields_list, true))
return false;
+ Bitmap<MAX_FIELDS> first_aggdistinct_fields;
+ bool first_aggdistinct_fields_initialized= false;
for (sum_item_ptr= join->sum_funcs; *sum_item_ptr; sum_item_ptr++)
{
Item_sum *sum_item= *sum_item_ptr;
- Field_map cur_aggdistinct_fields;
Item *expr;
/* aggregate is not AGGFN(DISTINCT) or more than 1 argument to it */
switch (sum_item->sum_func())
@@ -6991,6 +6990,8 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
We don't worry about duplicates as these will be sorted out later in
get_best_group_min_max
*/
+ Bitmap<MAX_FIELDS> cur_aggdistinct_fields;
+ cur_aggdistinct_fields.clear_all();
for (uint i= 0; i < sum_item->get_arg_count(); i++)
{
expr= sum_item->get_arg(i);
@@ -7009,8 +7010,11 @@ is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args)
If there are multiple aggregate functions, make sure that they all
refer to exactly the same set of columns.
*/
- if (first_aggdistinct_fields.is_clear_all())
- first_aggdistinct_fields.merge(cur_aggdistinct_fields);
+ if (!first_aggdistinct_fields_initialized)
+ {
+ first_aggdistinct_fields= cur_aggdistinct_fields;
+ first_aggdistinct_fields_initialized=true;
+ }
else if (first_aggdistinct_fields != cur_aggdistinct_fields)
return false;
}
@@ -17527,16 +17531,20 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
Create internal temporary table
****************************************************************************/
-Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
+Field *Item::create_tmp_field_int(MEM_ROOT *root, TABLE *table,
+ uint convert_int_length)
{
- const Type_handler *h= &type_handler_long;
+ const Type_handler *h= &type_handler_slong;
if (max_char_length() > convert_int_length)
- h= &type_handler_longlong;
- return h->make_and_init_table_field(&name, Record_addr(maybe_null),
+ h= &type_handler_slonglong;
+ if (unsigned_flag)
+ h= h->type_handler_unsigned();
+ return h->make_and_init_table_field(root, &name, Record_addr(maybe_null),
*this, table);
}
-Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
+Field *Item::tmp_table_field_from_field_type_maybe_null(MEM_ROOT *root,
+ TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param,
bool is_explicit_null)
@@ -17548,7 +17556,7 @@ Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
DBUG_ASSERT(!param->make_copy_field() || type() == CONST_ITEM);
DBUG_ASSERT(!is_result_field());
Field *result;
- if ((result= tmp_table_field_from_field_type(table)))
+ if ((result= tmp_table_field_from_field_type(root, table)))
{
if (result && is_explicit_null)
result->is_created_from_null_item= true;
@@ -17557,15 +17565,14 @@ Field *Item::tmp_table_field_from_field_type_maybe_null(TABLE *table,
}
-Field *Item_sum::create_tmp_field(bool group, TABLE *table)
+Field *Item_sum::create_tmp_field(MEM_ROOT *root, bool group, TABLE *table)
{
Field *UNINIT_VAR(new_field);
- MEM_ROOT *mem_root= table->in_use->mem_root;
switch (cmp_type()) {
case REAL_RESULT:
{
- new_field= new (mem_root)
+ new_field= new (root)
Field_double(max_char_length(), maybe_null, &name, decimals, TRUE);
break;
}
@@ -17573,7 +17580,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
case TIME_RESULT:
case DECIMAL_RESULT:
case STRING_RESULT:
- new_field= tmp_table_field_from_field_type(table);
+ new_field= tmp_table_field_from_field_type(root, table);
break;
case ROW_RESULT:
// This case should never be choosen
@@ -17588,47 +17595,11 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
/**
- Create field for information schema table.
-
- @param thd Thread handler
- @param table Temporary table
- @param item Item to create a field for
-
- @retval
- 0 on error
- @retval
- new_created field
-*/
-
-Field *Item::create_field_for_schema(THD *thd, TABLE *table)
-{
- if (field_type() == MYSQL_TYPE_VARCHAR)
- {
- Field *field;
- if (max_length > MAX_FIELD_VARCHARLENGTH)
- field= new (thd->mem_root) Field_blob(max_length, maybe_null, &name,
- collation.collation);
- else if (max_length > 0)
- field= new (thd->mem_root) Field_varstring(max_length, maybe_null, &name,
- table->s,
- collation.collation);
- else
- field= new Field_null((uchar*) 0, 0, Field::NONE, &name,
- collation.collation);
- if (field)
- field->init(table);
- return field;
- }
- return tmp_table_field_from_field_type(table);
-}
-
-
-/**
Create a temporary field for Item_field (or its descendant),
either direct or referenced by an Item_ref.
*/
Field *
-Item_field::create_tmp_field_from_item_field(TABLE *new_table,
+Item_field::create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param)
{
@@ -17652,14 +17623,16 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null);
const Type_handler *handler= type_handler()->
type_handler_for_tmp_table(this);
- result= handler->make_and_init_table_field(orig_item ? &orig_item->name : &name,
+ result= handler->make_and_init_table_field(root,
+ orig_item ? &orig_item->name : &name,
rec, *this, new_table);
}
else if (param->table_cant_handle_bit_fields() &&
field->type() == MYSQL_TYPE_BIT)
{
- const Type_handler *handler= type_handler_long_or_longlong();
- result= handler->make_and_init_table_field(&name,
+ const Type_handler *handler=
+ Type_handler::type_handler_long_or_longlong(max_char_length(), true);
+ result= handler->make_and_init_table_field(root, &name,
Record_addr(maybe_null),
*this, new_table);
}
@@ -17668,8 +17641,7 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name;
bool tmp_maybe_null= param->modify_item() ? maybe_null :
field->maybe_null();
- result= field->create_tmp_field(new_table->in_use->mem_root, new_table,
- tmp_maybe_null);
+ result= field->create_tmp_field(root, new_table, tmp_maybe_null);
if (result)
result->field_name= *tmp;
}
@@ -17679,14 +17651,14 @@ Item_field::create_tmp_field_from_item_field(TABLE *new_table,
}
-Field *Item_field::create_tmp_field_ex(TABLE *table,
+Field *Item_field::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!is_result_field());
Field *result;
src->set_field(field);
- if (!(result= create_tmp_field_from_item_field(table, NULL, param)))
+ if (!(result= create_tmp_field_from_item_field(root, table, NULL, param)))
return NULL;
/*
Fields that are used as arguments to the DEFAULT() function already have
@@ -17699,7 +17671,7 @@ Field *Item_field::create_tmp_field_ex(TABLE *table,
}
-Field *Item_ref::create_tmp_field_ex(TABLE *table,
+Field *Item_ref::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -17712,13 +17684,14 @@ Field *Item_ref::create_tmp_field_ex(TABLE *table,
Tmp_field_param prm2(*param);
prm2.set_modify_item(false);
src->set_field(field->field);
- if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2)))
+ if (!(result= field->create_tmp_field_from_item_field(root, table,
+ this, &prm2)))
return NULL;
if (param->modify_item())
result_field= result;
return result;
}
- return Item_result_field::create_tmp_field_ex(table, src, param);
+ return Item_result_field::create_tmp_field_ex(root, table, src, param);
}
@@ -17737,7 +17710,7 @@ void Item_result_field::get_tmp_field_src(Tmp_field_src *src,
}
-Field *Item_result_field::create_tmp_field_ex(TABLE *table,
+Field *Item_result_field::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -17751,13 +17724,14 @@ Field *Item_result_field::create_tmp_field_ex(TABLE *table,
DBUG_ASSERT(type() != NULL_ITEM);
get_tmp_field_src(src, param);
Field *result;
- if ((result= tmp_table_field_from_field_type(table)) && param->modify_item())
+ if ((result= tmp_table_field_from_field_type(root, table)) &&
+ param->modify_item())
result_field= result;
return result;
}
-Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
+Field *Item_func_user_var::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
@@ -17765,20 +17739,20 @@ Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
DBUG_ASSERT(type() != NULL_ITEM);
get_tmp_field_src(src, param);
Field *result;
- if ((result= create_table_field_from_handler(table)) && param->modify_item())
+ if ((result= create_table_field_from_handler(root, table)) &&
+ param->modify_item())
result_field= result;
return result;
}
-Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
+Field *Item_func_sp::create_tmp_field_ex(MEM_ROOT *root, TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
Field *result;
get_tmp_field_src(src, param);
- if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root,
- table)))
+ if ((result= sp_result_field->create_tmp_field(root, table)))
{
result->field_name= name;
if (param->modify_item())
@@ -17824,7 +17798,8 @@ Field *create_tmp_field(TABLE *table, Item *item,
Tmp_field_src src;
Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields,
make_copy_field);
- Field *result= item->create_tmp_field_ex(table, &src, &prm);
+ Field *result= item->create_tmp_field_ex(table->in_use->mem_root,
+ table, &src, &prm);
*from_field= src.field();
*default_field= src.default_field();
if (src.item_result_field())
@@ -17876,6 +17851,91 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
}
+class Create_tmp_table: public Data_type_statistics
+{
+ // The following members are initialized only in start()
+ Field **m_from_field, **m_default_field;
+ KEY_PART_INFO *m_key_part_info;
+ uchar *m_group_buff, *m_bitmaps;
+ // The following members are initialized in ctor
+ uint m_alloced_field_count;
+ bool m_using_unique_constraint;
+ uint m_temp_pool_slot;
+ ORDER *m_group;
+ bool m_distinct;
+ bool m_save_sum_fields;
+ ulonglong m_select_options;
+ ha_rows m_rows_limit;
+ uint m_hidden_field_count; // Remove this eventually
+ uint m_group_null_items;
+ uint m_null_count;
+ uint m_hidden_uneven_bit_length;
+ uint m_hidden_null_count;
+public:
+ Create_tmp_table(const TMP_TABLE_PARAM *param,
+ ORDER *group, bool distinct, bool save_sum_fields,
+ ulonglong select_options, ha_rows rows_limit)
+ :m_alloced_field_count(0),
+ m_using_unique_constraint(false),
+ m_temp_pool_slot(MY_BIT_NONE),
+ m_group(group),
+ m_distinct(distinct),
+ m_save_sum_fields(save_sum_fields),
+ m_select_options(select_options),
+ m_rows_limit(rows_limit),
+ m_hidden_field_count(param->hidden_field_count),
+ m_group_null_items(0),
+ m_null_count(0),
+ m_hidden_uneven_bit_length(0),
+ m_hidden_null_count(0)
+ { }
+
+ void add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols);
+
+ TABLE *start(THD *thd,
+ TMP_TABLE_PARAM *param,
+ const LEX_CSTRING *table_alias);
+
+ bool add_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param, List<Item> &fields);
+
+ bool add_schema_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap);
+
+ bool finalize(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ bool do_not_open, bool keep_row_order);
+ void cleanup_on_failure(THD *thd, TABLE *table);
+};
+
+
+void Create_tmp_table::add_field(TABLE *table, Field *field, uint fieldnr, bool force_not_null_cols)
+{
+ DBUG_ASSERT(!field->field_name.str || strlen(field->field_name.str) == field->field_name.length);
+
+ if (force_not_null_cols)
+ {
+ field->flags|= NOT_NULL_FLAG;
+ field->null_ptr= NULL;
+ }
+
+ if (!(field->flags & NOT_NULL_FLAG))
+ m_null_count++;
+
+ table->s->reclength+= field->pack_length();
+
+ // Assign it here, before update_data_type_statistics() changes m_blob_count
+ if (field->flags & BLOB_FLAG)
+ table->s->blob_field[m_blob_count]= fieldnr;
+
+ table->field[fieldnr]= field;
+ field->field_index= fieldnr;
+
+ field->update_data_type_statistics(this);
+}
+
+
/**
Create a temp table according to a field list.
@@ -17910,61 +17970,36 @@ setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps)
inserted, the engine should preserve this order
*/
-TABLE *
-create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
- ORDER *group, bool distinct, bool save_sum_fields,
- ulonglong select_options, ha_rows rows_limit,
- const LEX_CSTRING *table_alias, bool do_not_open,
- bool keep_row_order)
+TABLE *Create_tmp_table::start(THD *thd,
+ TMP_TABLE_PARAM *param,
+ const LEX_CSTRING *table_alias)
{
MEM_ROOT *mem_root_save, own_root;
TABLE *table;
TABLE_SHARE *share;
- uint i,field_count,null_count,null_pack_length;
uint copy_func_count= param->func_count;
- uint hidden_null_count, hidden_null_pack_length, hidden_field_count;
- uint blob_count,group_null_items, string_count;
- uint temp_pool_slot=MY_BIT_NONE;
- uint fieldnr= 0;
- ulong reclength, string_total_length;
- bool using_unique_constraint= false;
- bool use_packed_rows= false;
- bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
char *tmpname,path[FN_REFLEN];
- uchar *pos, *group_buff, *bitmaps;
- uchar *null_flags;
- Field **reg_field, **from_field, **default_field;
+ Field **reg_field;
uint *blob_field;
- Copy_field *copy=0;
- KEY *keyinfo;
- KEY_PART_INFO *key_part_info;
- Item **copy_func;
- TMP_ENGINE_COLUMNDEF *recinfo;
- /*
- total_uneven_bit_length is uneven bit length for visible fields
- hidden_uneven_bit_length is uneven bit length for hidden fields
- */
- uint total_uneven_bit_length= 0, hidden_uneven_bit_length= 0;
- bool force_copy_fields= param->force_copy_fields;
/* Treat sum functions as normal ones when loose index scan is used. */
- save_sum_fields|= param->precomputed_group_by;
- DBUG_ENTER("create_tmp_table");
+ m_save_sum_fields|= param->precomputed_group_by;
+ DBUG_ENTER("Create_tmp_table::start");
DBUG_PRINT("enter",
("table_alias: '%s' distinct: %d save_sum_fields: %d "
"rows_limit: %lu group: %d", table_alias->str,
- (int) distinct, (int) save_sum_fields,
- (ulong) rows_limit, MY_TEST(group)));
+ (int) m_distinct, (int) m_save_sum_fields,
+ (ulong) m_rows_limit, MY_TEST(m_group)));
if (use_temp_pool && !(test_flags & TEST_KEEP_TMP_TABLES))
- temp_pool_slot = bitmap_lock_set_next(&temp_pool);
+ m_temp_pool_slot = bitmap_lock_set_next(&temp_pool);
- if (temp_pool_slot != MY_BIT_NONE) // we got a slot
- sprintf(path, "%s_%lx_%i", tmp_file_prefix,
- current_pid, temp_pool_slot);
+ if (m_temp_pool_slot != MY_BIT_NONE) // we got a slot
+ sprintf(path, "%s-%lx-%i", tmp_file_prefix,
+ current_pid, m_temp_pool_slot);
else
{
/* if we run out of slots or we are not using tempool */
- sprintf(path, "%s%lx_%lx_%x", tmp_file_prefix,current_pid,
+ sprintf(path, "%s-%lx-%lx-%x", tmp_file_prefix,current_pid,
(ulong) thd->thread_id, thd->tmp_table++);
}
@@ -17975,12 +18010,12 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
fn_format(path, path, mysql_tmpdir, "",
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
- if (group)
+ if (m_group)
{
- ORDER **prev= &group;
+ ORDER **prev= &m_group;
if (!param->quick_group)
- group=0; // Can't use group key
- else for (ORDER *tmp=group ; tmp ; tmp=tmp->next)
+ m_group= 0; // Can't use group key
+ else for (ORDER *tmp= m_group ; tmp ; tmp= tmp->next)
{
/* Exclude found constant from the list */
if ((*tmp->item)->const_item())
@@ -17999,16 +18034,17 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
(*tmp->item)->marker=4; // Store null in key
if ((*tmp->item)->too_big_for_varchar())
- using_unique_constraint= true;
+ m_using_unique_constraint= true;
}
if (param->group_length >= MAX_BLOB_WIDTH)
- using_unique_constraint= true;
- if (group)
- distinct=0; // Can't use distinct
+ m_using_unique_constraint= true;
+ if (m_group)
+ m_distinct= 0; // Can't use distinct
}
- field_count=param->field_count+param->func_count+param->sum_func_count;
- hidden_field_count=param->hidden_field_count;
+ m_alloced_field_count= param->field_count+param->func_count+param->sum_func_count;
+ DBUG_ASSERT(m_alloced_field_count);
+ const uint field_count= m_alloced_field_count;
/*
When loose index scan is employed as access method, it already
@@ -18027,41 +18063,37 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
&table, sizeof(*table),
&share, sizeof(*share),
&reg_field, sizeof(Field*) * (field_count+1),
- &default_field, sizeof(Field*) * (field_count),
+ &m_default_field, sizeof(Field*) * (field_count),
&blob_field, sizeof(uint)*(field_count+1),
- &from_field, sizeof(Field*)*field_count,
- &copy_func, sizeof(*copy_func)*(copy_func_count+1),
+ &m_from_field, sizeof(Field*)*field_count,
+ &param->items_to_copy,
+ sizeof(param->items_to_copy[0])*(copy_func_count+1),
&param->keyinfo, sizeof(*param->keyinfo),
- &key_part_info,
- sizeof(*key_part_info)*(param->group_parts+1),
+ &m_key_part_info,
+ sizeof(*m_key_part_info)*(param->group_parts+1),
&param->start_recinfo,
sizeof(*param->recinfo)*(field_count*2+4),
&tmpname, (uint) strlen(path)+1,
- &group_buff, (group && ! using_unique_constraint ?
+ &m_group_buff, (m_group && ! m_using_unique_constraint ?
param->group_length : 0),
- &bitmaps, bitmap_buffer_size(field_count)*6,
+ &m_bitmaps, bitmap_buffer_size(field_count)*6,
NullS))
{
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
DBUG_RETURN(NULL); /* purecov: inspected */
}
/* Copy_field belongs to TMP_TABLE_PARAM, allocate it in THD mem_root */
- if (!(param->copy_field= copy= new (thd->mem_root) Copy_field[field_count]))
+ if (!(param->copy_field= new (thd->mem_root) Copy_field[field_count]))
{
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
free_root(&own_root, MYF(0)); /* purecov: inspected */
DBUG_RETURN(NULL); /* purecov: inspected */
}
- param->items_to_copy= copy_func;
strmov(tmpname, path);
/* make table according to fields */
bzero((char*) table,sizeof(*table));
- bzero((char*) reg_field,sizeof(Field*)*(field_count+1));
- bzero((char*) default_field, sizeof(Field*) * (field_count));
- bzero((char*) from_field,sizeof(Field*)*field_count);
+ bzero((char*) reg_field, sizeof(Field*) * (field_count+1));
+ bzero((char*) m_default_field, sizeof(Field*) * (field_count));
+ bzero((char*) m_from_field, sizeof(Field*) * field_count);
table->mem_root= own_root;
mem_root_save= thd->mem_root;
@@ -18072,7 +18104,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
table->map=1;
- table->temp_pool_slot = temp_pool_slot;
+ table->temp_pool_slot= m_temp_pool_slot;
table->copy_blobs= 1;
table->in_use= thd;
table->no_rows_with_nulls= param->force_not_null_cols;
@@ -18087,15 +18119,36 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (param->schema_table)
share->db= INFORMATION_SCHEMA_NAME;
- /* Calculate which type of fields we will store in the temporary table */
-
- reclength= string_total_length= 0;
- blob_count= string_count= null_count= hidden_null_count= group_null_items= 0;
param->using_outer_summary_function= 0;
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(table);
+}
+
+
+bool Create_tmp_table::add_fields(THD *thd,
+ TABLE *table,
+ TMP_TABLE_PARAM *param,
+ List<Item> &fields)
+{
+ DBUG_ENTER("Create_tmp_table::add_fields");
+ DBUG_ASSERT(table);
+ DBUG_ASSERT(table->field);
+ DBUG_ASSERT(table->s->blob_field);
+ DBUG_ASSERT(table->s->reclength == 0);
+ DBUG_ASSERT(table->s->fields == 0);
+ DBUG_ASSERT(table->s->blob_fields == 0);
+
+ const bool not_all_columns= !(m_select_options & TMP_TABLE_ALL_COLUMNS);
+ uint fieldnr= 0;
+ TABLE_SHARE *share= table->s;
+ Item **copy_func= param->items_to_copy;
+
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
List_iterator_fast<Item> li(fields);
Item *item;
- Field **tmp_from_field=from_field;
+ Field **tmp_from_field= m_from_field;
while ((item=li++))
{
Item::Type type= item->type();
@@ -18122,14 +18175,14 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
continue;
}
}
- if (item->const_item() && (int) hidden_field_count <= 0)
+ if (item->const_item() && (int) m_hidden_field_count <= 0)
continue; // We don't have to store this
}
- if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
+ if (type == Item::SUM_FUNC_ITEM && !m_group && !m_save_sum_fields)
{ /* Can't calc group yet */
Item_sum *sum_item= (Item_sum *) item;
sum_item->result_field=0;
- for (i=0 ; i < sum_item->get_arg_count() ; i++)
+ for (uint i= 0 ; i < sum_item->get_arg_count() ; i++)
{
Item *arg= sum_item->get_arg(i);
if (!arg->const_item())
@@ -18137,49 +18190,30 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
Item *tmp_item;
Field *new_field=
create_tmp_field(table, arg, &copy_func,
- tmp_from_field, &default_field[fieldnr],
- group != 0,not_all_columns,
- distinct, false);
+ tmp_from_field, &m_default_field[fieldnr],
+ m_group != 0, not_all_columns,
+ m_distinct, false);
if (!new_field)
goto err; // Should be OOM
- DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
tmp_from_field++;
- reclength+=new_field->pack_length();
- if (new_field->flags & BLOB_FLAG)
- {
- *blob_field++= fieldnr;
- blob_count++;
- }
- if (new_field->type() == MYSQL_TYPE_BIT)
- total_uneven_bit_length+= new_field->field_length & 7;
- *(reg_field++)= new_field;
- if (new_field->real_type() == MYSQL_TYPE_STRING ||
- new_field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- string_count++;
- string_total_length+= new_field->pack_length();
- }
+
thd->mem_root= mem_root_save;
if (!(tmp_item= new (thd->mem_root)
Item_temptable_field(thd, new_field)))
goto err;
arg= sum_item->set_arg(i, thd, tmp_item);
thd->mem_root= &table->mem_root;
- if (param->force_not_null_cols)
- {
- new_field->flags|= NOT_NULL_FLAG;
- new_field->null_ptr= NULL;
- }
+
+ add_field(table, new_field, fieldnr++, param->force_not_null_cols);
+
if (!(new_field->flags & NOT_NULL_FLAG))
{
- null_count++;
/*
new_field->maybe_null() is still false, it will be
changed below. But we have to setup Item_field correctly
*/
arg->maybe_null=1;
}
- new_field->field_index= fieldnr++;
}
}
}
@@ -18198,13 +18232,13 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
The test for item->marker == 4 is ensure we don't create a group-by
key over a bit field as heap tables can't handle that.
*/
- Field *new_field= (param->schema_table) ?
- item->create_field_for_schema(thd, table) :
+ DBUG_ASSERT(!param->schema_table);
+ Field *new_field=
create_tmp_field(table, item, &copy_func,
- tmp_from_field, &default_field[fieldnr],
- group != 0,
- !force_copy_fields &&
- (not_all_columns || group !=0),
+ tmp_from_field, &m_default_field[fieldnr],
+ m_group != 0,
+ !param->force_copy_fields &&
+ (not_all_columns || m_group !=0),
/*
If item->marker == 4 then we force create_tmp_field
to create a 64-bit longs for BIT fields because HEAP
@@ -18213,14 +18247,13 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
to be usable in this case too.
*/
item->marker == 4 || param->bit_fields_as_long,
- force_copy_fields);
+ param->force_copy_fields);
if (!new_field)
{
if (unlikely(thd->is_fatal_error))
goto err; // Got OOM
continue; // Some kind of const item
}
- DBUG_ASSERT(!new_field->field_name.str || strlen(new_field->field_name.str) == new_field->field_name.length);
if (type == Item::SUM_FUNC_ITEM)
{
Item_sum *agg_item= (Item_sum *) item;
@@ -18247,82 +18280,92 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
agg_item->result_field= new_field;
}
tmp_from_field++;
- if (param->force_not_null_cols)
- {
- new_field->flags|= NOT_NULL_FLAG;
- new_field->null_ptr= NULL;
- }
- reclength+=new_field->pack_length();
- if (!(new_field->flags & NOT_NULL_FLAG))
- null_count++;
- if (new_field->type() == MYSQL_TYPE_BIT)
- total_uneven_bit_length+= new_field->field_length & 7;
- if (new_field->flags & BLOB_FLAG)
- {
- *blob_field++= fieldnr;
- blob_count++;
- }
- if (new_field->real_type() == MYSQL_TYPE_STRING ||
- new_field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- string_count++;
- string_total_length+= new_field->pack_length();
- }
+ add_field(table, new_field, fieldnr++, param->force_not_null_cols);
if (item->marker == 4 && item->maybe_null)
{
- group_null_items++;
+ m_group_null_items++;
new_field->flags|= GROUP_FLAG;
}
- new_field->field_index= fieldnr++;
- *(reg_field++)= new_field;
}
- if (!--hidden_field_count)
+ if (!--m_hidden_field_count)
{
/*
This was the last hidden field; Remember how many hidden fields could
have null
*/
- hidden_null_count=null_count;
+ m_hidden_null_count= m_null_count;
/*
We need to update hidden_field_count as we may have stored group
functions with constant arguments
*/
param->hidden_field_count= fieldnr;
- null_count= 0;
+ m_null_count= 0;
/*
On last hidden field we store uneven bit length in
- hidden_uneven_bit_length and proceed calculation of
- uneven bits for visible fields into
- total_uneven_bit_length variable.
+ m_hidden_uneven_bit_length and proceed calculation of
+ uneven bits for visible fields into m_uneven_bit_length.
*/
- hidden_uneven_bit_length= total_uneven_bit_length;
- total_uneven_bit_length= 0;
+ m_hidden_uneven_bit_length= m_uneven_bit_length;
+ m_uneven_bit_length= 0;
}
}
- DBUG_ASSERT(fieldnr == (uint) (reg_field - table->field));
- DBUG_ASSERT(field_count >= (uint) (reg_field - table->field));
- field_count= fieldnr;
- *reg_field= 0;
- *blob_field= 0; // End marker
- share->fields= field_count;
+ share->fields= fieldnr;
+ share->blob_fields= m_blob_count;
+ table->field[fieldnr]= 0; // End marker
+ share->blob_field[m_blob_count]= 0; // End marker
+ copy_func[0]= 0; // End marker
+ param->func_count= (uint) (copy_func - param->items_to_copy);
share->column_bitmap_size= bitmap_buffer_size(share->fields);
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(false);
+
+err:
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(true);
+}
+
+
+bool Create_tmp_table::finalize(THD *thd,
+ TABLE *table,
+ TMP_TABLE_PARAM *param,
+ bool do_not_open, bool keep_row_order)
+{
+ DBUG_ENTER("Create_tmp_table::finalize");
+ DBUG_ASSERT(table);
+
+ uint hidden_null_pack_length;
+ uint null_pack_length;
+ bool use_packed_rows= false;
+ uchar *pos;
+ uchar *null_flags;
+ KEY *keyinfo;
+ TMP_ENGINE_COLUMNDEF *recinfo;
+ TABLE_SHARE *share= table->s;
+ Copy_field *copy= param->copy_field;
+
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+
+ DBUG_ASSERT(m_alloced_field_count >= share->fields);
+ DBUG_ASSERT(m_alloced_field_count >= share->blob_fields);
+
/* If result table is small; use a heap */
/* future: storage engine selection can be made dynamic? */
- if (blob_count || using_unique_constraint
- || (thd->variables.big_tables && !(select_options & SELECT_SMALL_RESULT))
- || (select_options & TMP_TABLE_FORCE_MYISAM)
+ if (share->blob_fields || m_using_unique_constraint
+ || (thd->variables.big_tables && !(m_select_options & SELECT_SMALL_RESULT))
+ || (m_select_options & TMP_TABLE_FORCE_MYISAM)
|| thd->variables.tmp_memory_table_size == 0)
{
share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
- if (group &&
+ if (m_group &&
(param->group_parts > table->file->max_key_parts() ||
param->group_length > table->file->max_key_length()))
- using_unique_constraint= true;
+ m_using_unique_constraint= true;
}
else
{
@@ -18339,35 +18382,33 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
goto err;
}
- if (!using_unique_constraint)
- reclength+= group_null_items; // null flag is stored separately
+ if (!m_using_unique_constraint)
+ share->reclength+= m_group_null_items; // null flag is stored separately
- share->blob_fields= blob_count;
- if (blob_count == 0)
+ if (share->blob_fields == 0)
{
/* We need to ensure that first byte is not 0 for the delete link */
if (param->hidden_field_count)
- hidden_null_count++;
+ m_hidden_null_count++;
else
- null_count++;
+ m_null_count++;
}
- hidden_null_pack_length= (hidden_null_count + 7 +
- hidden_uneven_bit_length) / 8;
+ hidden_null_pack_length= (m_hidden_null_count + 7 +
+ m_hidden_uneven_bit_length) / 8;
null_pack_length= (hidden_null_pack_length +
- (null_count + total_uneven_bit_length + 7) / 8);
- reclength+=null_pack_length;
- if (!reclength)
- reclength=1; // Dummy select
+ (m_null_count + m_uneven_bit_length + 7) / 8);
+ share->reclength+= null_pack_length;
+ if (!share->reclength)
+ share->reclength= 1; // Dummy select
/* Use packed rows if there is blobs or a lot of space to gain */
- if (blob_count ||
- (string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
- (reclength / string_total_length <= RATIO_TO_PACK_ROWS ||
- string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
+ if (share->blob_fields ||
+ (string_total_length() >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
+ (share->reclength / string_total_length() <= RATIO_TO_PACK_ROWS ||
+ string_total_length() / string_count() >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
use_packed_rows= 1;
- share->reclength= reclength;
{
- uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1);
+ uint alloc_length= ALIGN_SIZE(share->reclength + MI_UNIQUE_HASH_LENGTH+1);
share->rec_buff_length= alloc_length;
if (!(table->record[0]= (uchar*)
alloc_root(&table->mem_root, alloc_length*3)))
@@ -18375,10 +18416,8 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
table->record[1]= table->record[0]+alloc_length;
share->default_values= table->record[1]+alloc_length;
}
- copy_func[0]=0; // End marker
- param->func_count= (uint)(copy_func - param->items_to_copy);
- setup_tmp_table_column_bitmaps(table, bitmaps);
+ setup_tmp_table_column_bitmaps(table, m_bitmaps);
recinfo=param->start_recinfo;
null_flags=(uchar*) table->record[0];
@@ -18392,33 +18431,33 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
bfill(null_flags,null_pack_length,255); // Set null fields
table->null_flags= (uchar*) table->record[0];
- share->null_fields= null_count+ hidden_null_count;
+ share->null_fields= m_null_count + m_hidden_null_count;
share->null_bytes= share->null_bytes_for_compare= null_pack_length;
}
- null_count= (blob_count == 0) ? 1 : 0;
- hidden_field_count=param->hidden_field_count;
- for (i=0,reg_field=table->field; i < field_count; i++,reg_field++,recinfo++)
+ m_null_count= (share->blob_fields == 0) ? 1 : 0;
+ m_hidden_field_count= param->hidden_field_count;
+ for (uint i= 0; i < share->fields; i++, recinfo++)
{
- Field *field= *reg_field;
+ Field *field= table->field[i];
uint length;
bzero((uchar*) recinfo,sizeof(*recinfo));
if (!(field->flags & NOT_NULL_FLAG))
{
- recinfo->null_bit= (uint8)1 << (null_count & 7);
- recinfo->null_pos= null_count/8;
- field->move_field(pos,null_flags+null_count/8,
- (uint8)1 << (null_count & 7));
- null_count++;
+ recinfo->null_bit= (uint8)1 << (m_null_count & 7);
+ recinfo->null_pos= m_null_count/8;
+ field->move_field(pos, null_flags + m_null_count/8,
+ (uint8)1 << (m_null_count & 7));
+ m_null_count++;
}
else
field->move_field(pos,(uchar*) 0,0);
if (field->type() == MYSQL_TYPE_BIT)
{
/* We have to reserve place for extra bits among null bits */
- ((Field_bit*) field)->set_bit_ptr(null_flags + null_count / 8,
- null_count & 7);
- null_count+= (field->field_length & 7);
+ ((Field_bit*) field)->set_bit_ptr(null_flags + m_null_count / 8,
+ m_null_count & 7);
+ m_null_count+= (field->field_length & 7);
}
field->reset();
@@ -18426,14 +18465,14 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
Test if there is a default field value. The test for ->ptr is to skip
'offset' fields generated by initalize_tables
*/
- if (default_field[i] && default_field[i]->ptr)
+ if (m_default_field[i] && m_default_field[i]->ptr)
{
/*
default_field[i] is set only in the cases when 'field' can
inherit the default value that is defined for the field referred
by the Item_field object from which 'field' has been created.
*/
- const Field *orig_field= default_field[i];
+ const Field *orig_field= m_default_field[i];
/* Get the value from default_values */
if (orig_field->is_null_in_record(orig_field->table->s->default_values))
field->set_null();
@@ -18446,9 +18485,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
}
- if (from_field[i])
+ if (m_from_field[i])
{ /* Not a table Item */
- copy->set(field,from_field[i],save_sum_fields);
+ copy->set(field, m_from_field[i], m_save_sum_fields);
copy++;
}
length=field->pack_length();
@@ -18456,25 +18495,15 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
/* Make entry for create table */
recinfo->length=length;
- if (field->flags & BLOB_FLAG)
- recinfo->type= FIELD_BLOB;
- else if (use_packed_rows &&
- field->real_type() == MYSQL_TYPE_STRING &&
- length >= MIN_STRING_LENGTH_TO_PACK_ROWS)
- recinfo->type= FIELD_SKIP_ENDSPACE;
- else if (field->real_type() == MYSQL_TYPE_VARCHAR)
- recinfo->type= FIELD_VARCHAR;
- else
- recinfo->type= FIELD_NORMAL;
-
- if (!--hidden_field_count)
- null_count=(null_count+7) & ~7; // move to next byte
+ recinfo->type= field->tmp_engine_column_type(use_packed_rows);
+ if (!--m_hidden_field_count)
+ m_null_count= (m_null_count + 7) & ~7; // move to next byte
// fix table name in field entry
field->set_table_name(&table->alias);
}
- param->copy_field_end=copy;
+ param->copy_field_end= copy;
param->recinfo= recinfo; // Pointer to after last field
store_record(table,s->default_values); // Make empty default record
@@ -18491,22 +18520,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
Push the LIMIT clause to the temporary table creation, so that we
materialize only up to 'rows_limit' records instead of all result records.
*/
- set_if_smaller(share->max_rows, rows_limit);
- param->end_write_records= rows_limit;
+ set_if_smaller(share->max_rows, m_rows_limit);
+ param->end_write_records= m_rows_limit;
keyinfo= param->keyinfo;
- if (group)
+ if (m_group)
{
DBUG_PRINT("info",("Creating group key in temporary table"));
- table->group=group; /* Table is grouped by key */
- param->group_buff=group_buff;
+ table->group= m_group; /* Table is grouped by key */
+ param->group_buff= m_group_buff;
share->keys=1;
- share->uniques= MY_TEST(using_unique_constraint);
+ share->uniques= MY_TEST(m_using_unique_constraint);
table->key_info= table->s->key_info= keyinfo;
table->keys_in_use_for_query.set_bit(0);
share->keys_in_use.set_bit(0);
- keyinfo->key_part=key_part_info;
+ keyinfo->key_part= m_key_part_info;
keyinfo->flags=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->usable_key_parts=keyinfo->user_defined_key_parts= param->group_parts;
@@ -18518,29 +18547,29 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
keyinfo->is_statistics_from_stat_tables= FALSE;
keyinfo->name= group_key;
- ORDER *cur_group= group;
- for (; cur_group ; cur_group= cur_group->next, key_part_info++)
+ ORDER *cur_group= m_group;
+ for (; cur_group ; cur_group= cur_group->next, m_key_part_info++)
{
Field *field=(*cur_group->item)->get_tmp_table_field();
DBUG_ASSERT(field->table == table);
bool maybe_null=(*cur_group->item)->maybe_null;
- key_part_info->null_bit=0;
- key_part_info->field= field;
- key_part_info->fieldnr= field->field_index + 1;
- if (cur_group == group)
+ m_key_part_info->null_bit=0;
+ m_key_part_info->field= field;
+ m_key_part_info->fieldnr= field->field_index + 1;
+ if (cur_group == m_group)
field->key_start.set_bit(0);
- key_part_info->offset= field->offset(table->record[0]);
- key_part_info->length= (uint16) field->key_length();
- key_part_info->type= (uint8) field->key_type();
- key_part_info->key_type =
- ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
+ m_key_part_info->offset= field->offset(table->record[0]);
+ m_key_part_info->length= (uint16) field->key_length();
+ m_key_part_info->type= (uint8) field->key_type();
+ m_key_part_info->key_type =
+ ((ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
- key_part_info->key_part_flag= 0;
- if (!using_unique_constraint)
+ m_key_part_info->key_part_flag= 0;
+ if (!m_using_unique_constraint)
{
- cur_group->buff=(char*) group_buff;
+ cur_group->buff=(char*) m_group_buff;
if (maybe_null && !field->null_bit)
{
@@ -18555,9 +18584,9 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
if (!(cur_group->field= field->new_key_field(thd->mem_root,table,
- group_buff +
+ m_group_buff +
MY_TEST(maybe_null),
- key_part_info->length,
+ m_key_part_info->length,
field->null_ptr,
field->null_bit)))
goto err; /* purecov: inspected */
@@ -18571,26 +18600,28 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
The NULL flag is updated in 'end_update()' and 'end_write()'
*/
keyinfo->flags|= HA_NULL_ARE_EQUAL; // def. that NULL == NULL
- key_part_info->null_bit=field->null_bit;
- key_part_info->null_offset= (uint) (field->null_ptr -
+ m_key_part_info->null_bit=field->null_bit;
+ m_key_part_info->null_offset= (uint) (field->null_ptr -
(uchar*) table->record[0]);
cur_group->buff++; // Pointer to field data
- group_buff++; // Skipp null flag
+ m_group_buff++; // Skipp null flag
}
- group_buff+= cur_group->field->pack_length();
+ m_group_buff+= cur_group->field->pack_length();
}
- keyinfo->key_length+= key_part_info->length;
+ keyinfo->key_length+= m_key_part_info->length;
}
/*
Ensure we didn't overrun the group buffer. The < is only true when
some maybe_null fields was changed to be not null fields.
*/
- DBUG_ASSERT(using_unique_constraint ||
- group_buff <= param->group_buff + param->group_length);
+ DBUG_ASSERT(m_using_unique_constraint ||
+ m_group_buff <= param->group_buff + param->group_length);
}
- if (distinct && field_count != param->hidden_field_count)
+ if (m_distinct && share->fields != param->hidden_field_count)
{
+ uint i;
+ Field **reg_field;
/*
Create an unique key or an unique constraint over all columns
that should be in the result. In the temporary table, there are
@@ -18599,7 +18630,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
DBUG_PRINT("info",("hidden_field_count: %d", param->hidden_field_count));
- if (blob_count)
+ if (share->blob_fields)
{
/*
Special mode for index creation in MyISAM used to support unique
@@ -18610,21 +18641,21 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
}
null_pack_length-=hidden_null_pack_length;
keyinfo->user_defined_key_parts=
- ((field_count-param->hidden_field_count)+
+ ((share->fields - param->hidden_field_count)+
(share->uniques ? MY_TEST(null_pack_length) : 0));
keyinfo->ext_key_parts= keyinfo->user_defined_key_parts;
keyinfo->usable_key_parts= keyinfo->user_defined_key_parts;
table->distinct= 1;
share->keys= 1;
- if (!(key_part_info= (KEY_PART_INFO*)
+ if (!(m_key_part_info= (KEY_PART_INFO*)
alloc_root(&table->mem_root,
keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO))))
goto err;
- bzero((void*) key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
+ bzero((void*) m_key_part_info, keyinfo->user_defined_key_parts * sizeof(KEY_PART_INFO));
table->keys_in_use_for_query.set_bit(0);
share->keys_in_use.set_bit(0);
table->key_info= table->s->key_info= keyinfo;
- keyinfo->key_part=key_part_info;
+ keyinfo->key_part= m_key_part_info;
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL | HA_BINARY_PACK_KEY | HA_PACK_KEY;
keyinfo->ext_key_flags= keyinfo->flags;
keyinfo->key_length= 0; // Will compute the sum of the parts below.
@@ -18656,39 +18687,39 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
if (null_pack_length && share->uniques)
{
- key_part_info->null_bit=0;
- key_part_info->offset=hidden_null_pack_length;
- key_part_info->length=null_pack_length;
- key_part_info->field= new Field_string(table->record[0],
- (uint32) key_part_info->length,
+ m_key_part_info->null_bit=0;
+ m_key_part_info->offset=hidden_null_pack_length;
+ m_key_part_info->length=null_pack_length;
+ m_key_part_info->field= new Field_string(table->record[0],
+ (uint32) m_key_part_info->length,
(uchar*) 0,
(uint) 0,
Field::NONE,
&null_clex_str, &my_charset_bin);
- if (!key_part_info->field)
+ if (!m_key_part_info->field)
goto err;
- key_part_info->field->init(table);
- key_part_info->key_type=FIELDFLAG_BINARY;
- key_part_info->type= HA_KEYTYPE_BINARY;
- key_part_info->fieldnr= key_part_info->field->field_index + 1;
- key_part_info++;
+ m_key_part_info->field->init(table);
+ m_key_part_info->key_type=FIELDFLAG_BINARY;
+ m_key_part_info->type= HA_KEYTYPE_BINARY;
+ m_key_part_info->fieldnr= m_key_part_info->field->field_index + 1;
+ m_key_part_info++;
}
/* Create a distinct key over the columns we are going to return */
- for (i=param->hidden_field_count, reg_field=table->field + i ;
- i < field_count;
- i++, reg_field++, key_part_info++)
+ for (i= param->hidden_field_count, reg_field= table->field + i ;
+ i < share->fields;
+ i++, reg_field++, m_key_part_info++)
{
- key_part_info->field= *reg_field;
+ m_key_part_info->field= *reg_field;
(*reg_field)->flags |= PART_KEY_FLAG;
- if (key_part_info == keyinfo->key_part)
+ if (m_key_part_info == keyinfo->key_part)
(*reg_field)->key_start.set_bit(0);
- key_part_info->null_bit= (*reg_field)->null_bit;
- key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
+ m_key_part_info->null_bit= (*reg_field)->null_bit;
+ m_key_part_info->null_offset= (uint) ((*reg_field)->null_ptr -
(uchar*) table->record[0]);
- key_part_info->offset= (*reg_field)->offset(table->record[0]);
- key_part_info->length= (uint16) (*reg_field)->pack_length();
- key_part_info->fieldnr= (*reg_field)->field_index + 1;
+ m_key_part_info->offset= (*reg_field)->offset(table->record[0]);
+ m_key_part_info->length= (uint16) (*reg_field)->pack_length();
+ m_key_part_info->fieldnr= (*reg_field)->field_index + 1;
/* TODO:
The below method of computing the key format length of the
key part is a copy/paste from opt_range.cc, and table.cc.
@@ -18697,33 +18728,22 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
methods is supposed to compute the same length. If so, it
might be reused.
*/
- key_part_info->store_length= key_part_info->length;
+ m_key_part_info->store_length= m_key_part_info->length;
if ((*reg_field)->real_maybe_null())
{
- key_part_info->store_length+= HA_KEY_NULL_LENGTH;
- key_part_info->key_part_flag |= HA_NULL_PART;
- }
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->real_type() == MYSQL_TYPE_VARCHAR ||
- (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
- {
- if ((*reg_field)->type() == MYSQL_TYPE_BLOB ||
- (*reg_field)->type() == MYSQL_TYPE_GEOMETRY)
- key_part_info->key_part_flag|= HA_BLOB_PART;
- else
- key_part_info->key_part_flag|= HA_VAR_LENGTH_PART;
-
- key_part_info->store_length+=HA_KEY_BLOB_LENGTH;
+ m_key_part_info->store_length+= HA_KEY_NULL_LENGTH;
+ m_key_part_info->key_part_flag |= HA_NULL_PART;
}
+ m_key_part_info->key_part_flag|= (*reg_field)->key_part_flag();
+ m_key_part_info->store_length+= (*reg_field)->key_part_length_bytes();
+ keyinfo->key_length+= m_key_part_info->store_length;
- keyinfo->key_length+= key_part_info->store_length;
-
- key_part_info->type= (uint8) (*reg_field)->key_type();
- key_part_info->key_type =
- ((ha_base_keytype) key_part_info->type == HA_KEYTYPE_TEXT ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
- (ha_base_keytype) key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
+ m_key_part_info->type= (uint8) (*reg_field)->key_type();
+ m_key_part_info->key_type =
+ ((ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_TEXT ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT1 ||
+ (ha_base_keytype) m_key_part_info->type == HA_KEYTYPE_VARTEXT2) ?
0 : FIELDFLAG_BINARY;
}
}
@@ -18738,7 +18758,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
if (!do_not_open)
{
if (instantiate_tmp_table(table, param->keyinfo, param->start_recinfo,
- &param->recinfo, select_options))
+ &param->recinfo, m_select_options))
goto err;
}
@@ -18747,14 +18767,109 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
thd->mem_root= mem_root_save;
- DBUG_RETURN(table);
+ DBUG_RETURN(false);
err:
thd->mem_root= mem_root_save;
- free_tmp_table(thd,table); /* purecov: inspected */
- if (temp_pool_slot != MY_BIT_NONE)
- bitmap_lock_clear_bit(&temp_pool, temp_pool_slot);
- DBUG_RETURN(NULL); /* purecov: inspected */
+ DBUG_RETURN(true); /* purecov: inspected */
+}
+
+
+bool Create_tmp_table::add_schema_fields(THD *thd, TABLE *table,
+ TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap)
+{
+ DBUG_ENTER("Create_tmp_table::add_schema_fields");
+ DBUG_ASSERT(table);
+ DBUG_ASSERT(table->field);
+ DBUG_ASSERT(table->s->blob_field);
+ DBUG_ASSERT(table->s->reclength == 0);
+ DBUG_ASSERT(table->s->fields == 0);
+ DBUG_ASSERT(table->s->blob_fields == 0);
+
+ TABLE_SHARE *share= table->s;
+ ST_FIELD_INFO *defs= schema_table.fields_info;
+ uint fieldnr;
+ MEM_ROOT *mem_root_save= thd->mem_root;
+ thd->mem_root= &table->mem_root;
+
+ for (fieldnr= 0; !defs[fieldnr].end_marker(); fieldnr++)
+ {
+ const ST_FIELD_INFO &def= defs[fieldnr];
+ bool visible= bitmap_is_set(&bitmap, fieldnr);
+ Record_addr addr(def.nullable());
+ const Type_handler *h= def.type_handler();
+ Field *field= h->make_schema_field(&table->mem_root, table,
+ addr, def, visible);
+ if (!field)
+ {
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(true); // EOM
+ }
+ field->init(table);
+ add_field(table, field, fieldnr, param->force_not_null_cols);
+ }
+
+ share->fields= fieldnr;
+ share->blob_fields= m_blob_count;
+ table->field[fieldnr]= 0; // End marker
+ share->blob_field[m_blob_count]= 0; // End marker
+ param->func_count= 0;
+ share->column_bitmap_size= bitmap_buffer_size(share->fields);
+
+ thd->mem_root= mem_root_save;
+ DBUG_RETURN(false);
+}
+
+
+void Create_tmp_table::cleanup_on_failure(THD *thd, TABLE *table)
+{
+ if (table)
+ free_tmp_table(thd, table);
+ if (m_temp_pool_slot != MY_BIT_NONE)
+ bitmap_lock_clear_bit(&temp_pool, m_temp_pool_slot);
+}
+
+
+TABLE *create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
+ ulonglong select_options, ha_rows rows_limit,
+ const LEX_CSTRING *table_alias, bool do_not_open,
+ bool keep_row_order)
+{
+ TABLE *table;
+ Create_tmp_table maker(param, group,
+ distinct, save_sum_fields, select_options, rows_limit);
+ if (!(table= maker.start(thd, param, table_alias)) ||
+ maker.add_fields(thd, table, param, fields) ||
+ maker.finalize(thd, table, param, do_not_open, keep_row_order))
+ {
+ maker.cleanup_on_failure(thd, table);
+ return NULL;
+ }
+ return table;
+}
+
+
+TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap,
+ longlong select_options,
+ const LEX_CSTRING &table_alias,
+ bool keep_row_order)
+{
+ TABLE *table;
+ Create_tmp_table maker(param, (ORDER *) NULL, false, false,
+ select_options, HA_POS_ERROR);
+ if (!(table= maker.start(thd, param, &table_alias)) ||
+ maker.add_schema_fields(thd, table, param, schema_table, bitmap) ||
+ maker.finalize(thd, table, param, false, keep_row_order))
+ {
+ maker.cleanup_on_failure(thd, table);
+ return NULL;
+ }
+ return table;
}
@@ -25382,8 +25497,9 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list,
{
Item *new_item;
if (!(new_item= new (thd->mem_root) Item_ref(thd, context,
- group_tmp->item, 0,
- &item->name)))
+ group_tmp->item,
+ null_clex_str,
+ item->name)))
return 1; // fatal_error is set
thd->change_item_tree(arg, new_item);
arg_changed= TRUE;
@@ -26122,16 +26238,14 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
table_list->schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
{
IS_table_read_plan *is_table_read_plan= table_list->is_table_read_plan;
- const char *tmp_buff;
- int f_idx;
StringBuffer<64> key_name_buf;
if (is_table_read_plan->trivial_show_command ||
is_table_read_plan->has_db_lookup_value())
{
/* The "key" has the name of the column referring to the database */
- f_idx= table_list->schema_table->idx_field1;
- tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
+ int f_idx= table_list->schema_table->idx_field1;
+ LEX_CSTRING tmp= table_list->schema_table->fields_info[f_idx].name();
+ key_name_buf.append(tmp, cs);
}
if (is_table_read_plan->trivial_show_command ||
is_table_read_plan->has_table_lookup_value())
@@ -26140,9 +26254,9 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta,
is_table_read_plan->has_db_lookup_value())
key_name_buf.append(',');
- f_idx= table_list->schema_table->idx_field2;
- tmp_buff= table_list->schema_table->fields_info[f_idx].field_name;
- key_name_buf.append(tmp_buff, strlen(tmp_buff), cs);
+ int f_idx= table_list->schema_table->idx_field2;
+ LEX_CSTRING tmp= table_list->schema_table->fields_info[f_idx].name();
+ key_name_buf.append(tmp, cs);
}
if (key_name_buf.length())
diff --git a/sql/sql_select.h b/sql/sql_select.h
index b7f870bf797..40a9ed303f7 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -2419,6 +2419,13 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ulonglong select_options, ha_rows rows_limit,
const LEX_CSTRING *alias, bool do_not_open=FALSE,
bool keep_row_order= FALSE);
+TABLE *create_tmp_table_for_schema(THD *thd, TMP_TABLE_PARAM *param,
+ const ST_SCHEMA_TABLE &schema_table,
+ const MY_BITMAP &bitmap,
+ longlong select_options,
+ const LEX_CSTRING &alias,
+ bool keep_row_order);
+
void free_tmp_table(THD *thd, TABLE *entry);
bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table,
TMP_ENGINE_COLUMNDEF *start_recinfo,
diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc
index 4e8624d6360..544c9b7f436 100644
--- a/sql/sql_sequence.cc
+++ b/sql/sql_sequence.cc
@@ -48,20 +48,20 @@ struct Field_definition
static Field_definition sequence_structure[]=
{
- {"next_not_cached_value", 21, &type_handler_longlong,
+ {"next_not_cached_value", 21, &type_handler_slonglong,
{STRING_WITH_LEN("")}, FL},
- {"minimum_value", 21, &type_handler_longlong, {STRING_WITH_LEN("")}, FL},
- {"maximum_value", 21, &type_handler_longlong, {STRING_WITH_LEN("")}, FL},
- {"start_value", 21, &type_handler_longlong, {STRING_WITH_LEN("start value when sequences is created or value if RESTART is used")}, FL},
- {"increment", 21, &type_handler_longlong,
+ {"minimum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
+ {"maximum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
+ {"start_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("start value when sequences is created or value if RESTART is used")}, FL},
+ {"increment", 21, &type_handler_slonglong,
{STRING_WITH_LEN("increment value")}, FL},
- {"cache_size", 21, &type_handler_longlong, {STRING_WITH_LEN("")},
+ {"cache_size", 21, &type_handler_ulonglong, {STRING_WITH_LEN("")},
FL | UNSIGNED_FLAG},
- {"cycle_option", 1, &type_handler_tiny, {STRING_WITH_LEN("0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed")},
+ {"cycle_option", 1, &type_handler_utiny, {STRING_WITH_LEN("0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed")},
FL | UNSIGNED_FLAG },
- {"cycle_count", 21, &type_handler_longlong,
+ {"cycle_count", 21, &type_handler_slonglong,
{STRING_WITH_LEN("How many cycles have been done")}, FL},
- {NULL, 0, &type_handler_longlong, {STRING_WITH_LEN("")}, 0}
+ {NULL, 0, &type_handler_slonglong, {STRING_WITH_LEN("")}, 0}
};
#undef FL
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 60d3578e680..34c0e0abc6c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -93,7 +93,6 @@ enum enum_i_s_events_fields
ISE_DB_CL
};
-#define USERNAME_WITH_HOST_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2)
static const LEX_CSTRING trg_action_time_type_names[]=
{
@@ -377,124 +376,6 @@ int fill_all_plugins(THD *thd, TABLE_LIST *tables, COND *cond)
}
-#ifdef HAVE_SPATIAL
-static int fill_spatial_ref_sys(THD *thd, TABLE_LIST *tables, COND *cond)
-{
- DBUG_ENTER("fill_spatial_ref_sys");
- TABLE *table= tables->table;
- CHARSET_INFO *cs= system_charset_info;
- int result= 1;
-
- restore_record(table, s->default_values);
-
- table->field[0]->store(-1, FALSE); /*SRID*/
- table->field[1]->store(STRING_WITH_LEN("Not defined"), cs); /*AUTH_NAME*/
- table->field[2]->store(-1, FALSE); /*AUTH_SRID*/
- table->field[3]->store(STRING_WITH_LEN(
- "LOCAL_CS[\"Spatial reference wasn't specified\","
- "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0]," "AXIS[\"x\",EAST],"
- "AXIS[\"y\",NORTH]]"), cs);/*SRTEXT*/
- if (schema_table_store_record(thd, table))
- goto exit;
-
- table->field[0]->store(0, TRUE); /*SRID*/
- table->field[1]->store(STRING_WITH_LEN("EPSG"), cs); /*AUTH_NAME*/
- table->field[2]->store(404000, TRUE); /*AUTH_SRID*/
- table->field[3]->store(STRING_WITH_LEN(
- "LOCAL_CS[\"Wildcard 2D cartesian plane in metric unit\","
- "LOCAL_DATUM[\"Unknown\",0]," "UNIT[\"m\",1.0],"
- "AXIS[\"x\",EAST]," "AXIS[\"y\",NORTH],"
- "AUTHORITY[\"EPSG\",\"404000\"]]"), cs);/*SRTEXT*/
- if (schema_table_store_record(thd, table))
- goto exit;
-
- result= 0;
-
-exit:
- DBUG_RETURN(result);
-}
-
-
-static int get_geometry_column_record(THD *thd, TABLE_LIST *tables,
- TABLE *table, bool res,
- const LEX_CSTRING *db_name,
- const LEX_CSTRING *table_name)
-{
- CHARSET_INFO *cs= system_charset_info;
- TABLE *show_table;
- Field **ptr, *field;
- DBUG_ENTER("get_geometry_column_record");
-
- if (res)
- {
- if (thd->lex->sql_command != SQLCOM_SHOW_FIELDS)
- {
- /*
- I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
- rather than in SHOW COLUMNS
- */
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- thd->get_stmt_da()->sql_errno(),
- thd->get_stmt_da()->message());
- thd->clear_error();
- res= 0;
- }
- DBUG_RETURN(res);
- }
-
- if (tables->schema_table)
- goto exit;
- show_table= tables->table;
- ptr= show_table->field;
- show_table->use_all_columns(); // Required for default
- restore_record(show_table, s->default_values);
-
- for (; (field= *ptr) ; ptr++)
- if (field->type() == MYSQL_TYPE_GEOMETRY)
- {
- Field_geom *fg= (Field_geom *) field;
-
- DEBUG_SYNC(thd, "get_schema_column");
-
- /* Get default row, with all NULL fields set to NULL */
- restore_record(table, s->default_values);
-
- /*F_TABLE_CATALOG*/
- table->field[0]->store(STRING_WITH_LEN("def"), cs);
- /*F_TABLE_SCHEMA*/
- table->field[1]->store(db_name->str, db_name->length, cs);
- /*F_TABLE_NAME*/
- table->field[2]->store(table_name->str, table_name->length, cs);
- /*G_TABLE_CATALOG*/
- table->field[4]->store(STRING_WITH_LEN("def"), cs);
- /*G_TABLE_SCHEMA*/
- table->field[5]->store(db_name->str, db_name->length, cs);
- /*G_TABLE_NAME*/
- table->field[6]->store(table_name->str, table_name->length, cs);
- /*G_GEOMETRY_COLUMN*/
- table->field[7]->store(field->field_name.str, field->field_name.length,
- cs);
- /*STORAGE_TYPE*/
- table->field[8]->store(1LL, TRUE); /*Always 1 (binary implementation)*/
- /*GEOMETRY_TYPE*/
- table->field[9]->store((longlong) (fg->get_geometry_type()), TRUE);
- /*COORD_DIMENSION*/
- table->field[10]->store(2LL, TRUE);
- /*MAX_PPR*/
- table->field[11]->set_null();
- /*SRID*/
- table->field[12]->store((longlong) (fg->get_srid()), TRUE);
-
- if (schema_table_store_record(thd, table))
- DBUG_RETURN(1);
- }
-
-exit:
- DBUG_RETURN(0);
-}
-#endif /*HAVE_SPATIAL*/
-
-
/***************************************************************************
** List all Authors.
** If you can update it, you get to be in it :)
@@ -1470,7 +1351,7 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
LEX_CSTRING *orig_dbname,
const DDL_options_st &options)
{
- char buff[2048];
+ char buff[2048+DATABASE_COMMENT_MAXLEN];
String buffer(buff, sizeof(buff), system_charset_info);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *sctx= thd->security_ctx;
@@ -1506,6 +1387,7 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
{
*dbname= INFORMATION_SCHEMA_NAME;
create.default_table_charset= system_charset_info;
+ create.schema_comment= NULL;
}
else
{
@@ -1545,6 +1427,13 @@ bool mysqld_show_create_db(THD *thd, LEX_CSTRING *dbname,
}
buffer.append(STRING_WITH_LEN(" */"));
}
+
+ if (create.schema_comment)
+ {
+ buffer.append(STRING_WITH_LEN(" COMMENT "));
+ append_unescaped(&buffer, create.schema_comment->str,
+ create.schema_comment->length);
+ }
protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
if (protocol->write())
@@ -3619,12 +3508,18 @@ const char* get_one_variable(THD *thd,
/* fall through */
case SHOW_ULONG:
case SHOW_LONG_NOFLUSH: // the difference lies in refresh_status()
+#ifndef _WIN64
+ case SHOW_SIZE_T:
+#endif
end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG_STATUS:
value= ((char *) status_var + (intptr) value);
/* fall through */
case SHOW_ULONGLONG:
+#ifdef _WIN64
+ case SHOW_SIZE_T:
+#endif
end= longlong10_to_str(*(longlong*) value, buff, 10);
break;
case SHOW_HA_ROWS:
@@ -3953,9 +3848,9 @@ bool get_lookup_value(THD *thd, Item_func *item_func,
ST_SCHEMA_TABLE *schema_table= table->schema_table;
ST_FIELD_INFO *field_info= schema_table->fields_info;
const char *field_name1= schema_table->idx_field1 >= 0 ?
- field_info[schema_table->idx_field1].field_name : "";
+ field_info[schema_table->idx_field1].name().str : "";
const char *field_name2= schema_table->idx_field2 >= 0 ?
- field_info[schema_table->idx_field2].field_name : "";
+ field_info[schema_table->idx_field2].name().str : "";
if (item_func->functype() == Item_func::EQ_FUNC ||
item_func->functype() == Item_func::EQUAL_FUNC)
@@ -4091,9 +3986,9 @@ bool uses_only_table_name_fields(Item *item, TABLE_LIST *table)
ST_SCHEMA_TABLE *schema_table= table->schema_table;
ST_FIELD_INFO *field_info= schema_table->fields_info;
const char *field_name1= schema_table->idx_field1 >= 0 ?
- field_info[schema_table->idx_field1].field_name : "";
+ field_info[schema_table->idx_field1].name().str : "";
const char *field_name2= schema_table->idx_field2 >= 0 ?
- field_info[schema_table->idx_field2].field_name : "";
+ field_info[schema_table->idx_field2].name().str : "";
if (table->table != item_field->field->table ||
(cs->coll->strnncollsp(cs, (uchar *) field_name1, strlen(field_name1),
(uchar *) item_field->field_name.str,
@@ -4799,18 +4694,18 @@ uint get_table_open_method(TABLE_LIST *tables,
if (schema_table->i_s_requested_object & OPTIMIZE_I_S_TABLE)
{
Field **ptr, *field;
- int table_open_method= 0, field_indx= 0;
+ uint table_open_method= 0, field_indx= 0;
uint star_table_open_method= OPEN_FULL_TABLE;
bool used_star= true; // true if '*' is used in select
for (ptr=tables->table->field; (field= *ptr) ; ptr++)
{
+ const ST_FIELD_INFO &def= schema_table->fields_info[field_indx];
star_table_open_method=
- MY_MIN(star_table_open_method,
- schema_table->fields_info[field_indx].open_method);
+ MY_MIN(star_table_open_method, (uint) def.open_method());
if (bitmap_is_set(tables->table->read_set, field->field_index))
{
used_star= false;
- table_open_method|= schema_table->fields_info[field_indx].open_method;
+ table_open_method|= (uint) def.open_method();
}
field_indx++;
}
@@ -5306,14 +5201,17 @@ err:
}
-bool store_schema_shemata(THD* thd, TABLE *table, LEX_CSTRING *db_name,
- CHARSET_INFO *cs)
+bool store_schema_schemata(THD* thd, TABLE *table, LEX_CSTRING *db_name,
+ CHARSET_INFO *cs, LEX_CSTRING *schema_comment= NULL)
{
restore_record(table, s->default_values);
table->field[0]->store(STRING_WITH_LEN("def"), system_charset_info);
table->field[1]->store(db_name->str, db_name->length, system_charset_info);
table->field[2]->store(cs->csname, strlen(cs->csname), system_charset_info);
table->field[3]->store(cs->name, strlen(cs->name), system_charset_info);
+ if (schema_comment)
+ table->field[5]->store(schema_comment->str, schema_comment->length,
+ system_charset_info);
return schema_table_store_record(thd, table);
}
@@ -5366,8 +5264,8 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_ASSERT(db_name->length <= NAME_LEN);
if (db_name == &INFORMATION_SCHEMA_NAME)
{
- if (store_schema_shemata(thd, table, db_name,
- system_charset_info))
+ if (store_schema_schemata(thd, table, db_name,
+ system_charset_info))
DBUG_RETURN(1);
continue;
}
@@ -5380,8 +5278,9 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
#endif
{
load_db_opt_by_name(thd, db_name->str, &create);
- if (store_schema_shemata(thd, table, db_name,
- create.default_table_charset))
+ if (store_schema_schemata(thd, table, db_name,
+ create.default_table_charset,
+ create.schema_comment))
DBUG_RETURN(1);
}
}
@@ -5939,10 +5838,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS
rather than in SHOW COLUMNS
*/
- push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
- thd->get_stmt_da()->sql_errno(),
- thd->get_stmt_da()->message());
- thd->clear_error();
+ convert_error_to_warning(thd);
res= 0;
}
DBUG_RETURN(res);
@@ -6144,12 +6040,11 @@ static my_bool iter_schema_engines(THD *thd, plugin_ref plugin,
LEX_CSTRING yesno[2]= {{ STRING_WITH_LEN("NO") },
{ STRING_WITH_LEN("YES") }};
LEX_CSTRING *tmp;
- const char *option_name= show_comp_option_name[(int) hton->state];
+ const char *option_name= default_type != hton ? yesno[1].str
+ : "DEFAULT";
restore_record(table, s->default_values);
table->field[0]->store(name->str, name->length, scs);
- if (hton->state == SHOW_OPTION_YES && default_type == hton)
- option_name= "DEFAULT";
table->field[1]->store(option_name, strlen(option_name), scs);
table->field[2]->store(plugin_decl(plugin)->descr,
strlen(plugin_decl(plugin)->descr), scs);
@@ -8128,9 +8023,9 @@ mark_all_fields_used_in_query(THD *thd,
bitmap_set_all(bitmap);
break;
}
- for (count=0; fields->field_name; fields++, count++)
+ for (count=0; !fields->end_marker(); fields++, count++)
{
- if (!my_strcasecmp(system_charset_info, fields->field_name,
+ if (!my_strcasecmp(system_charset_info, fields->name().str,
item_field->field_name.str))
{
bitmap_set_bit(bitmap, count);
@@ -8166,19 +8061,16 @@ mark_all_fields_used_in_query(THD *thd,
TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
{
uint field_count;
- Item *item, *all_items;
+ Item *all_items;
TABLE *table;
- List<Item> field_list;
ST_SCHEMA_TABLE *schema_table= table_list->schema_table;
ST_FIELD_INFO *fields_info= schema_table->fields_info;
ST_FIELD_INFO *fields;
- CHARSET_INFO *cs= system_charset_info;
- MEM_ROOT *mem_root= thd->mem_root;
MY_BITMAP bitmap;
my_bitmap_map *buf;
DBUG_ENTER("create_schema_table");
- for (field_count= 0, fields= fields_info; fields->field_name; fields++)
+ for (field_count= 0, fields= fields_info; !fields->end_marker(); fields++)
field_count++;
if (!(buf= (my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count))))
DBUG_RETURN(NULL);
@@ -8192,138 +8084,21 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list)
mark_all_fields_used_in_query(thd, fields_info, &bitmap, all_items);
- for (field_count=0; fields_info->field_name; fields_info++)
- {
- size_t field_name_length= strlen(fields_info->field_name);
- switch (fields_info->field_type) {
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONGLONG:
- case MYSQL_TYPE_INT24:
- if (!(item= new (mem_root)
- Item_return_int(thd, fields_info->field_name,
- fields_info->field_length,
- fields_info->field_type,
- fields_info->value)))
- {
- DBUG_RETURN(0);
- }
- item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
- break;
- case MYSQL_TYPE_DATE:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type)))
- DBUG_RETURN(0);
- break;
- case MYSQL_TYPE_TIME:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type)))
- DBUG_RETURN(0);
- break;
- case MYSQL_TYPE_TIMESTAMP:
- case MYSQL_TYPE_DATETIME:
- if (!(item=new (mem_root)
- Item_return_date_time(thd, fields_info->field_name,
- (uint)field_name_length,
- fields_info->field_type,
- fields_info->field_length)))
- DBUG_RETURN(0);
- item->decimals= fields_info->field_length;
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- if ((item= new (mem_root)
- Item_float(thd, fields_info->field_name, 0.0,
- NOT_FIXED_DEC,
- fields_info->field_length)) == NULL)
- DBUG_RETURN(NULL);
- break;
- case MYSQL_TYPE_DECIMAL:
- case MYSQL_TYPE_NEWDECIMAL:
- if (!(item= new (mem_root)
- Item_decimal(thd, (longlong) fields_info->value, false)))
- {
- DBUG_RETURN(0);
- }
- /*
- Create a type holder, as we want the type of the item to defined
- the type of the object, not the value
- */
- if (!(item= new (mem_root) Item_type_holder(thd, item)))
- DBUG_RETURN(0);
- item->unsigned_flag= (fields_info->field_flags & MY_I_S_UNSIGNED);
- item->decimals= fields_info->field_length%10;
- item->max_length= (fields_info->field_length/100)%100;
- if (item->unsigned_flag == 0)
- item->max_length+= 1;
- if (item->decimals > 0)
- item->max_length+= 1;
- item->set_name(thd, fields_info->field_name, field_name_length, cs);
- break;
- case MYSQL_TYPE_TINY_BLOB:
- case MYSQL_TYPE_MEDIUM_BLOB:
- case MYSQL_TYPE_LONG_BLOB:
- case MYSQL_TYPE_BLOB:
- if (bitmap_is_set(&bitmap, field_count))
- {
- if (!(item= new (mem_root)
- Item_blob(thd, fields_info->field_name,
- fields_info->field_length)))
- {
- DBUG_RETURN(0);
- }
- }
- else
- {
- if (!(item= new (mem_root)
- Item_empty_string(thd, "", 0, cs)))
- {
- DBUG_RETURN(0);
- }
- item->set_name(thd, fields_info->field_name,
- field_name_length, cs);
- }
- break;
- default:
- {
- bool show_field;
- /* Don't let unimplemented types pass through. Could be a grave error. */
- DBUG_ASSERT(fields_info->field_type == MYSQL_TYPE_STRING);
-
- show_field= bitmap_is_set(&bitmap, field_count);
- if (!(item= new (mem_root)
- Item_empty_string(thd, "",
- show_field ? fields_info->field_length : 0, cs)))
- {
- DBUG_RETURN(0);
- }
- item->set_name(thd, fields_info->field_name,
- field_name_length, cs);
- break;
- }
- }
- field_list.push_back(item, thd->mem_root);
- item->maybe_null= (fields_info->field_flags & MY_I_S_MAYBE_NULL);
- field_count++;
- }
TMP_TABLE_PARAM *tmp_table_param =
(TMP_TABLE_PARAM*) (thd->alloc(sizeof(TMP_TABLE_PARAM)));
tmp_table_param->init();
- tmp_table_param->table_charset= cs;
+ tmp_table_param->table_charset= system_charset_info;
tmp_table_param->field_count= field_count;
tmp_table_param->schema_table= 1;
SELECT_LEX *select_lex= table_list->select_lex;
bool keep_row_order= is_show_command(thd);
- if (!(table= create_tmp_table(thd, tmp_table_param,
- field_list, (ORDER*) 0, 0, 0,
- (select_lex->options | thd->variables.option_bits |
- TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR,
- &table_list->alias, false, keep_row_order)))
+ if (!(table= create_tmp_table_for_schema(thd, tmp_table_param,
+ *schema_table, bitmap,
+ (select_lex->options |
+ thd->variables.option_bits |
+ TMP_TABLE_ALL_COLUMNS),
+ table_list->alias,
+ keep_row_order)))
DBUG_RETURN(0);
my_bitmap_map* bitmaps=
(my_bitmap_map*) thd->alloc(bitmap_buffer_size(field_count));
@@ -8355,19 +8130,16 @@ static int make_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= schema_table->fields_info;
Name_resolution_context *context= &thd->lex->first_select_lex()->context;
- for (; field_info->field_name; field_info++)
+ for (; !field_info->end_marker(); field_info++)
{
- if (field_info->old_name)
+ if (field_info->old_name().str)
{
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
+ LEX_CSTRING field_name= field_info->name();
Item_field *field= new (thd->mem_root)
- Item_field(thd, context, NullS, NullS, &field_name);
+ Item_field(thd, context, field_name);
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8388,22 +8160,19 @@ int make_schemata_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
{
ST_FIELD_INFO *field_info= &schema_table->fields_info[1];
String buffer(tmp,sizeof(tmp), system_charset_info);
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
-
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (!field || add_item_to_list(thd, field))
return 1;
buffer.length(0);
- buffer.append(field_info->old_name);
+ buffer.append(field_info->old_name());
if (lex->wild && lex->wild->ptr())
{
buffer.append(STRING_WITH_LEN(" ("));
buffer.append(lex->wild->ptr());
buffer.append(')');
}
- field->set_name(thd, buffer.ptr(), buffer.length(), system_charset_info);
+ field->set_name(thd, buffer.lex_cstring());
}
return 0;
}
@@ -8416,11 +8185,10 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
LEX *lex= thd->lex;
Name_resolution_context *context= &lex->first_select_lex()->context;
ST_FIELD_INFO *field_info= &schema_table->fields_info[2];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name) };
+ LEX_CSTRING field_name= field_info->name();
buffer.length(0);
- buffer.append(field_info->old_name);
+ buffer.append(field_info->old_name());
buffer.append(&lex->first_select_lex()->db);
if (lex->wild && lex->wild->ptr())
{
@@ -8428,22 +8196,17 @@ int make_table_names_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
buffer.append(lex->wild->ptr());
buffer.append(')');
}
- Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ Item_field *field= new (thd->mem_root) Item_field(thd, context, field_name);
if (add_item_to_list(thd, field))
return 1;
- field->set_name(thd, buffer.ptr(), buffer.length(), system_charset_info);
+ field->set_name(thd, buffer.lex_cstring());
if (thd->lex->verbose)
{
field_info= &schema_table->fields_info[3];
- LEX_CSTRING field_name2= {field_info->field_name,
- strlen(field_info->field_name) };
- field= new (thd->mem_root) Item_field(thd, context, NullS, NullS,
- &field_name2);
+ field= new (thd->mem_root) Item_field(thd, context, field_info->name());
if (add_item_to_list(thd, field))
return 1;
- field->set_name(thd, field_info->old_name, strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
}
return 0;
}
@@ -8459,19 +8222,15 @@ int make_columns_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
if (!thd->lex->verbose && (*field_num == 14 ||
*field_num == 18 ||
*field_num == 19))
continue;
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8490,15 +8249,11 @@ int make_character_sets_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8517,15 +8272,11 @@ int make_proc_old_format(THD *thd, ST_SCHEMA_TABLE *schema_table)
for (; *field_num >= 0; field_num++)
{
field_info= &schema_table->fields_info[*field_num];
- LEX_CSTRING field_name= {field_info->field_name,
- strlen(field_info->field_name)};
Item_field *field= new (thd->mem_root) Item_field(thd, context,
- NullS, NullS, &field_name);
+ field_info->name());
if (field)
{
- field->set_name(thd, field_info->old_name,
- strlen(field_info->old_name),
- system_charset_info);
+ field->set_name(thd, field_info->old_name());
if (add_item_to_list(thd, field))
return 1;
}
@@ -8941,7 +8692,7 @@ static my_bool run_hton_fill_schema_table(THD *thd, plugin_ref plugin,
struct run_hton_fill_schema_table_args *args=
(run_hton_fill_schema_table_args *) arg;
handlerton *hton= plugin_hton(plugin);
- if (hton->fill_is_table && hton->state == SHOW_OPTION_YES)
+ if (hton->fill_is_table)
hton->fill_is_table(hton, thd, args->tables, args->cond,
get_schema_table_idx(args->tables->schema_table));
return false;
@@ -9047,809 +8798,653 @@ int fill_key_cache_tables(THD *thd, TABLE_LIST *tables, COND *cond)
}
+namespace Show {
+
ST_FIELD_INFO schema_fields_info[]=
{
- {"CATALOG_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SCHEMA_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
- SKIP_OPEN_TABLE},
- {"DEFAULT_CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"DEFAULT_COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"SQL_PATH", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CATALOG_NAME", Catalog(), NOT_NULL),
+ Column("SCHEMA_NAME", Name(), NOT_NULL, "Database"),
+ Column("DEFAULT_CHARACTER_SET_NAME", CSName(), NOT_NULL),
+ Column("DEFAULT_COLLATION_NAME", CSName(), NOT_NULL),
+ Column("SQL_PATH", Varchar(FN_REFLEN), NULLABLE),
+ Column("SCHEMA_COMMENT", Varchar(DATABASE_COMMENT_MAXLEN), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO tables_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine", OPEN_FRM_ONLY},
- {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", OPEN_FRM_ONLY},
- {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE},
- {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE},
- {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE},
- {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE},
- {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE},
- {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE},
- {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE},
- {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", OPEN_FULL_TABLE},
- {"TABLE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
- OPEN_FRM_ONLY},
- {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", OPEN_FULL_TABLE},
- {"CREATE_OPTIONS", 2048, MYSQL_TYPE_STRING, 0, 1, "Create_options",
- OPEN_FULL_TABLE},
- {"TABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Comment", OPEN_FRM_ONLY},
- {"MAX_INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_index_length", OPEN_FULL_TABLE},
- {"TEMPORARY", 1, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "Temporary", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL, "Name"),
+ Column("TABLE_TYPE", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ENGINE", Name(), NULLABLE, "Engine", OPEN_FRM_ONLY),
+ Column("VERSION", ULonglong(), NULLABLE, "Version", OPEN_FRM_ONLY),
+ Column("ROW_FORMAT", Varchar(10), NULLABLE, "Row_format", OPEN_FULL_TABLE),
+ Column("TABLE_ROWS", ULonglong(), NULLABLE, "Rows", OPEN_FULL_TABLE),
+ Column("AVG_ROW_LENGTH", ULonglong(), NULLABLE, "Avg_row_length",
+ OPEN_FULL_TABLE),
+ Column("DATA_LENGTH", ULonglong(), NULLABLE, "Data_length",OPEN_FULL_TABLE),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, "Max_data_length",
+ OPEN_FULL_TABLE),
+ Column("INDEX_LENGTH", ULonglong(), NULLABLE, "Index_length",OPEN_FULL_TABLE),
+ Column("DATA_FREE", ULonglong(), NULLABLE, "Data_free", OPEN_FULL_TABLE),
+ Column("AUTO_INCREMENT", ULonglong(), NULLABLE, "Auto_increment",
+ OPEN_FULL_TABLE),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, "Create_time",OPEN_FULL_TABLE),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, "Update_time",OPEN_FULL_TABLE),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, "Check_time", OPEN_FULL_TABLE),
+ Column("TABLE_COLLATION", CSName(), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("CHECKSUM", ULonglong(), NULLABLE, "Checksum", OPEN_FULL_TABLE),
+ Column("CREATE_OPTIONS", Varchar(2048),NULLABLE, "Create_options",
+ OPEN_FULL_TABLE),
+ Column("TABLE_COMMENT", Varchar(TABLE_COMMENT_MAXLEN),
+ NOT_NULL, "Comment", OPEN_FRM_ONLY),
+ Column("MAX_INDEX_LENGTH",ULonglong(), NULLABLE, "Max_index_length",
+ OPEN_FULL_TABLE),
+ Column("TEMPORARY", Varchar(1), NULLABLE, "Temporary", OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO columns_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_UNSIGNED, 0, OPEN_FRM_ONLY},
- {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0,
- 1, "Default", OPEN_FRM_ONLY},
- {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 1, "Collation",
- OPEN_FRM_ONLY},
- {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type", OPEN_FRM_ONLY},
- {"COLUMN_KEY", 3, MYSQL_TYPE_STRING, 0, 0, "Key", OPEN_FRM_ONLY},
- {"EXTRA", 30, MYSQL_TYPE_STRING, 0, 0, "Extra", OPEN_FRM_ONLY},
- {"PRIVILEGES", 80, MYSQL_TYPE_STRING, 0, 0, "Privileges", OPEN_FRM_ONLY},
- {"COLUMN_COMMENT", COLUMN_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Comment", OPEN_FRM_ONLY},
- {"IS_GENERATED", 6, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"GENERATION_EXPRESSION", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1,
- 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLUMN_NAME", Name(), NOT_NULL, "Field", OPEN_FRM_ONLY),
+ Column("ORDINAL_POSITION", ULonglong(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLUMN_DEFAULT", Longtext(MAX_FIELD_VARCHARLENGTH),
+ NULLABLE, "Default",OPEN_FRM_ONLY),
+ Column("IS_NULLABLE", Yesno(), NOT_NULL, "Null", OPEN_FRM_ONLY),
+ Column("DATA_TYPE", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHARACTER_MAXIMUM_LENGTH",ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_OCTET_LENGTH", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("NUMERIC_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("NUMERIC_SCALE", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", CSName(), NULLABLE, OPEN_FRM_ONLY),
+ Column("COLLATION_NAME", CSName(), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("COLUMN_TYPE", Longtext(65535), NOT_NULL, "Type", OPEN_FRM_ONLY),
+ Column("COLUMN_KEY", Varchar(3), NOT_NULL, "Key", OPEN_FRM_ONLY),
+ Column("EXTRA", Varchar(30), NOT_NULL, "Extra", OPEN_FRM_ONLY),
+ Column("PRIVILEGES", Varchar(80), NOT_NULL, "Privileges", OPEN_FRM_ONLY),
+ Column("COLUMN_COMMENT", Varchar(COLUMN_COMMENT_MAXLEN), NOT_NULL, "Comment",
+ OPEN_FRM_ONLY),
+ Column("IS_GENERATED", Varchar(6), NOT_NULL, OPEN_FRM_ONLY),
+ Column("GENERATION_EXPRESSION", Longtext(MAX_FIELD_VARCHARLENGTH),
+ NULLABLE, OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO charsets_fields_info[]=
{
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
- SKIP_OPEN_TABLE},
- {"DEFAULT_COLLATE_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Default collation", SKIP_OPEN_TABLE},
- {"DESCRIPTION", 60, MYSQL_TYPE_STRING, 0, 0, "Description",
- SKIP_OPEN_TABLE},
- {"MAXLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Maxlen", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL, "Charset"),
+ Column("DEFAULT_COLLATE_NAME", CSName(), NOT_NULL, "Default collation"),
+ Column("DESCRIPTION", Varchar(60), NOT_NULL, "Description"),
+ Column("MAXLEN", SLonglong(3), NOT_NULL, "Maxlen"),
+ CEnd()
};
ST_FIELD_INFO collation_fields_info[]=
{
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Collation",
- SKIP_OPEN_TABLE},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, "Charset",
- SKIP_OPEN_TABLE},
- {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 0, "Id",
- SKIP_OPEN_TABLE},
- {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default", SKIP_OPEN_TABLE},
- {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled", SKIP_OPEN_TABLE},
- {"SORTLEN", 3, MYSQL_TYPE_LONGLONG, 0, 0, "Sortlen", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("COLLATION_NAME", CSName(), NOT_NULL, "Collation"),
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL, "Charset"),
+ Column("ID", SLonglong(MY_INT32_NUM_DECIMAL_DIGITS), NOT_NULL, "Id"),
+ Column("IS_DEFAULT", Yesno(), NOT_NULL, "Default"),
+ Column("IS_COMPILED", Yesno(), NOT_NULL, "Compiled"),
+ Column("SORTLEN", SLonglong(3), NOT_NULL, "Sortlen"),
+ CEnd()
};
ST_FIELD_INFO applicable_roles_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("ROLE_NAME", Varchar(USERNAME_CHAR_LENGTH), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ Column("IS_DEFAULT", Yesno(), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO enabled_roles_fields_info[]=
{
- {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ROLE_NAME", Varchar(USERNAME_CHAR_LENGTH), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO engines_fields_info[]=
{
- {"ENGINE", 64, MYSQL_TYPE_STRING, 0, 0, "Engine", SKIP_OPEN_TABLE},
- {"SUPPORT", 8, MYSQL_TYPE_STRING, 0, 0, "Support", SKIP_OPEN_TABLE},
- {"COMMENT", 160, MYSQL_TYPE_STRING, 0, 0, "Comment", SKIP_OPEN_TABLE},
- {"TRANSACTIONS", 3, MYSQL_TYPE_STRING, 0, 1, "Transactions", SKIP_OPEN_TABLE},
- {"XA", 3, MYSQL_TYPE_STRING, 0, 1, "XA", SKIP_OPEN_TABLE},
- {"SAVEPOINTS", 3 ,MYSQL_TYPE_STRING, 0, 1, "Savepoints", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ENGINE", Varchar(64), NOT_NULL, "Engine"),
+ Column("SUPPORT", Varchar(8), NOT_NULL, "Support"),
+ Column("COMMENT", Varchar(160), NOT_NULL, "Comment"),
+ Column("TRANSACTIONS", Varchar(3), NULLABLE, "Transactions"),
+ Column("XA", Varchar(3), NULLABLE, "XA"),
+ Column("SAVEPOINTS", Varchar(3), NULLABLE, "Savepoints"),
+ CEnd()
};
ST_FIELD_INFO events_fields_info[]=
{
- {"EVENT_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
- SKIP_OPEN_TABLE},
- {"EVENT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
- {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone", SKIP_OPEN_TABLE},
- {"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"EXECUTE_AT", 0, MYSQL_TYPE_DATETIME, 0, 1, "Execute at", SKIP_OPEN_TABLE},
- {"INTERVAL_VALUE", 256, MYSQL_TYPE_STRING, 0, 1, "Interval value",
- SKIP_OPEN_TABLE},
- {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field",
- SKIP_OPEN_TABLE},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"STARTS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Starts", SKIP_OPEN_TABLE},
- {"ENDS", 0, MYSQL_TYPE_DATETIME, 0, 1, "Ends", SKIP_OPEN_TABLE},
- {"STATUS", 18, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
- {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
- {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, 0, SKIP_OPEN_TABLE},
- {"LAST_EXECUTED", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EVENT_COMMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ORIGINATOR", 10, MYSQL_TYPE_LONGLONG, 0, 0, "Originator", SKIP_OPEN_TABLE},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", SKIP_OPEN_TABLE},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", SKIP_OPEN_TABLE},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ // QQ: shouldn't EVENT_CATALOG be Catalog() like in all other places?
+ Column("EVENT_CATALOG", Name(), NOT_NULL),
+ Column("EVENT_SCHEMA", Name(), NOT_NULL, "Db"),
+ Column("EVENT_NAME", Name(), NOT_NULL, "Name"),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer"),
+ Column("TIME_ZONE", Varchar(64), NOT_NULL, "Time zone"),
+ Column("EVENT_BODY", Varchar(8), NOT_NULL),
+ Column("EVENT_DEFINITION", Longtext(65535), NOT_NULL),
+ Column("EVENT_TYPE", Varchar(9), NOT_NULL, "Type"),
+ Column("EXECUTE_AT", Datetime(0), NULLABLE, "Execute at"),
+ Column("INTERVAL_VALUE", Varchar(256),NULLABLE, "Interval value"),
+ Column("INTERVAL_FIELD", Varchar(18), NULLABLE, "Interval field"),
+ Column("SQL_MODE", SQLMode(), NOT_NULL),
+ Column("STARTS", Datetime(0), NULLABLE, "Starts"),
+ Column("ENDS", Datetime(0), NULLABLE, "Ends"),
+ Column("STATUS", Varchar(18), NOT_NULL, "Status"),
+ Column("ON_COMPLETION", Varchar(12), NOT_NULL),
+ Column("CREATED", Datetime(0), NOT_NULL),
+ Column("LAST_ALTERED", Datetime(0), NOT_NULL),
+ Column("LAST_EXECUTED", Datetime(0), NULLABLE),
+ Column("EVENT_COMMENT", Name(), NOT_NULL),
+ Column("ORIGINATOR", SLonglong(10),NOT_NULL,"Originator"),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client"),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection"),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation"),
+ CEnd()
};
ST_FIELD_INFO coll_charset_app_fields_info[]=
{
- {"COLLATION_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"CHARACTER_SET_NAME", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("COLLATION_NAME", CSName(), NOT_NULL),
+ Column("CHARACTER_SET_NAME", CSName(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO proc_fields_info[]=
{
- {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Db",
- SKIP_OPEN_TABLE},
- {"ROUTINE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"ROUTINE_TYPE", 13, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTERNAL_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTERNAL_LANGUAGE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"PARAMETER_STYLE", 8, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_DETERMINISTIC", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SQL_DATA_ACCESS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"SQL_PATH", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, "Security_type",
- SKIP_OPEN_TABLE},
- {"CREATED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Created", SKIP_OPEN_TABLE},
- {"LAST_ALTERED", 0, MYSQL_TYPE_DATETIME, 0, 0, "Modified", SKIP_OPEN_TABLE},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"ROUTINE_COMMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Comment",
- SKIP_OPEN_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", SKIP_OPEN_TABLE},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", SKIP_OPEN_TABLE},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", SKIP_OPEN_TABLE},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("SPECIFIC_NAME", Name(), NOT_NULL),
+ Column("ROUTINE_CATALOG", Catalog(), NOT_NULL),
+ Column("ROUTINE_SCHEMA", Name(), NOT_NULL, "Db"),
+ Column("ROUTINE_NAME", Name(), NOT_NULL, "Name"),
+ Column("ROUTINE_TYPE", Varchar(13),NOT_NULL, "Type"),
+ Column("DATA_TYPE", Name(), NOT_NULL),
+ Column("CHARACTER_MAXIMUM_LENGTH",SLong(21), NULLABLE),
+ Column("CHARACTER_OCTET_LENGTH", SLong(21), NULLABLE),
+ Column("NUMERIC_PRECISION", SLong(21), NULLABLE),
+ Column("NUMERIC_SCALE", SLong(21), NULLABLE),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", Varchar(64),NULLABLE),
+ Column("COLLATION_NAME", Varchar(64),NULLABLE),
+ Column("DTD_IDENTIFIER", Longtext(65535), NULLABLE),
+ Column("ROUTINE_BODY", Varchar(8), NOT_NULL),
+ Column("ROUTINE_DEFINITION", Longtext(65535), NULLABLE),
+ Column("EXTERNAL_NAME", Name(), NULLABLE),
+ Column("EXTERNAL_LANGUAGE", Name(), NULLABLE),
+ Column("PARAMETER_STYLE", Varchar(8), NOT_NULL),
+ Column("IS_DETERMINISTIC", Varchar(3), NOT_NULL),
+ Column("SQL_DATA_ACCESS", Name(), NOT_NULL),
+ Column("SQL_PATH", Name(), NULLABLE),
+ Column("SECURITY_TYPE", Varchar(7), NOT_NULL, "Security_type"),
+ Column("CREATED", Datetime(0), NOT_NULL, "Created"),
+ Column("LAST_ALTERED", Datetime(0), NOT_NULL, "Modified"),
+ Column("SQL_MODE", SQLMode(), NOT_NULL),
+ Column("ROUTINE_COMMENT", Longtext(65535), NOT_NULL, "Comment"),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer"),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client"),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection"),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation"),
+ CEnd()
};
ST_FIELD_INFO stat_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", OPEN_FRM_ONLY},
- {"NON_UNIQUE", 1, MYSQL_TYPE_LONGLONG, 0, 0, "Non_unique", OPEN_FRM_ONLY},
- {"INDEX_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"INDEX_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Key_name",
- OPEN_FRM_ONLY},
- {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONGLONG, 0, 0, "Seq_in_index", OPEN_FRM_ONLY},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name",
- OPEN_FRM_ONLY},
- {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation", OPEN_FRM_ONLY},
- {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, 1,
- "Cardinality", OPEN_FULL_TABLE},
- {"SUB_PART", 3, MYSQL_TYPE_LONGLONG, 0, 1, "Sub_part", OPEN_FRM_ONLY},
- {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed", OPEN_FRM_ONLY},
- {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null", OPEN_FRM_ONLY},
- {"INDEX_TYPE", 16, MYSQL_TYPE_STRING, 0, 0, "Index_type", OPEN_FULL_TABLE},
- {"COMMENT", 16, MYSQL_TYPE_STRING, 0, 1, "Comment", OPEN_FRM_ONLY},
- {"INDEX_COMMENT", INDEX_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0,
- "Index_comment", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, "Table", OPEN_FRM_ONLY),
+ Column("NON_UNIQUE", SLonglong(1),NOT_NULL, "Non_unique", OPEN_FRM_ONLY),
+ Column("INDEX_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("INDEX_NAME", Name(), NOT_NULL, "Key_name", OPEN_FRM_ONLY),
+ Column("SEQ_IN_INDEX", SLonglong(2),NOT_NULL, "Seq_in_index",OPEN_FRM_ONLY),
+ Column("COLUMN_NAME", Name(), NOT_NULL, "Column_name", OPEN_FRM_ONLY),
+ Column("COLLATION", Varchar(1), NULLABLE, "Collation", OPEN_FRM_ONLY),
+ Column("CARDINALITY", SLonglong(), NULLABLE, "Cardinality", OPEN_FULL_TABLE),
+ Column("SUB_PART", SLonglong(3),NULLABLE, "Sub_part", OPEN_FRM_ONLY),
+ Column("PACKED", Varchar(10), NULLABLE, "Packed", OPEN_FRM_ONLY),
+ Column("NULLABLE", Varchar(3), NOT_NULL, "Null", OPEN_FRM_ONLY),
+ Column("INDEX_TYPE", Varchar(16), NOT_NULL, "Index_type", OPEN_FULL_TABLE),
+ Column("COMMENT", Varchar(16), NULLABLE, "Comment", OPEN_FRM_ONLY),
+ Column("INDEX_COMMENT", Varchar(INDEX_COMMENT_MAXLEN),
+ NOT_NULL, "Index_comment",OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO view_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"VIEW_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHECK_OPTION", 8, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"ALGORITHM", 10, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("VIEW_DEFINITION", Longtext(65535), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHECK_OPTION", Varchar(8), NOT_NULL, OPEN_FRM_ONLY),
+ Column("IS_UPDATABLE", Yesno(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DEFINER", Definer(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("SECURITY_TYPE", Varchar(7), NOT_NULL, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ALGORITHM", Varchar(10),NOT_NULL, OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO user_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO schema_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO table_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO column_privileges_fields_info[]=
{
- {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("GRANTEE", Userhost(), NOT_NULL),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Name(), NOT_NULL),
+ Column("COLUMN_NAME", Name(), NOT_NULL),
+ Column("PRIVILEGE_TYPE", Name(), NOT_NULL),
+ Column("IS_GRANTABLE", Yesno(), NOT_NULL),
+ CEnd()
};
ST_FIELD_INFO table_constraints_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CONSTRAINT_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_TYPE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO key_column_usage_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ORDINAL_POSITION", 10 ,MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FULL_TABLE},
- {"POSITION_IN_UNIQUE_CONSTRAINT", 10 ,MYSQL_TYPE_LONGLONG, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"REFERENCED_COLUMN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("COLUMN_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ORDINAL_POSITION", SLonglong(10), NOT_NULL, OPEN_FULL_TABLE),
+ Column("POSITION_IN_UNIQUE_CONSTRAINT", SLonglong(10), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_SCHEMA", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("REFERENCED_COLUMN_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO table_names_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH,
- MYSQL_TYPE_STRING, 0, 0, "Tables_in_", SKIP_OPEN_TABLE},
- {"TABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table_type",
- OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL),
+ Column("TABLE_NAME", Varchar(NAME_CHAR_LEN + MYSQL50_TABLE_NAME_PREFIX_LENGTH),
+ NOT_NULL, "Tables_in_"),
+ Column("TABLE_TYPE", Name(), NOT_NULL, "Table_type", OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO open_tables_fields_info[]=
{
- {"Database", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Database",
- SKIP_OPEN_TABLE},
- {"Table",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table", SKIP_OPEN_TABLE},
- {"In_use", 1, MYSQL_TYPE_LONGLONG, 0, 0, "In_use", SKIP_OPEN_TABLE},
- {"Name_locked", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Name_locked", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("Database", Name(), NOT_NULL, "Database"),
+ Column("Table", Name(), NOT_NULL, "Table"),
+ Column("In_use", SLonglong(1), NOT_NULL, "In_use"),
+ Column("Name_locked", SLonglong(4), NOT_NULL, "Name_locked"),
+ CEnd()
};
ST_FIELD_INFO triggers_fields_info[]=
{
- {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TRIGGER_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"TRIGGER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger",
- OPEN_FRM_ONLY},
- {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event", OPEN_FRM_ONLY},
- {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"EVENT_OBJECT_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FRM_ONLY},
- {"EVENT_OBJECT_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Table",
- OPEN_FRM_ONLY},
- {"ACTION_ORDER", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FRM_ONLY},
- {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement",
- OPEN_FRM_ONLY},
- {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing", OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_OLD_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_NEW_TABLE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
+ Column("TRIGGER_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TRIGGER_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("TRIGGER_NAME", Name(), NOT_NULL, "Trigger", OPEN_FRM_ONLY),
+ Column("EVENT_MANIPULATION", Varchar(6), NOT_NULL, "Event", OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_CATALOG", Catalog(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_SCHEMA", Name(), NOT_NULL, OPEN_FRM_ONLY),
+ Column("EVENT_OBJECT_TABLE", Name(), NOT_NULL, "Table", OPEN_FRM_ONLY),
+ Column("ACTION_ORDER", SLonglong(4), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_CONDITION", Longtext(65535), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_STATEMENT", Longtext(65535), NOT_NULL, "Statement",OPEN_FRM_ONLY),
+ Column("ACTION_ORIENTATION", Varchar(9), NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_TIMING", Varchar(6), NOT_NULL, "Timing", OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_OLD_TABLE",Name(), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_NEW_TABLE",Name(), NULLABLE, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_OLD_ROW",Varchar(3),NOT_NULL, OPEN_FRM_ONLY),
+ Column("ACTION_REFERENCE_NEW_ROW",Varchar(3),NOT_NULL, OPEN_FRM_ONLY),
/* 2 here indicates 2 decimals */
- {"CREATED", 2, MYSQL_TYPE_DATETIME, 0, 1, "Created", OPEN_FRM_ONLY},
- {"SQL_MODE", 32*256, MYSQL_TYPE_STRING, 0, 0, "sql_mode", OPEN_FRM_ONLY},
- {"DEFINER", DEFINER_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "Definer", OPEN_FRM_ONLY},
- {"CHARACTER_SET_CLIENT", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "character_set_client", OPEN_FRM_ONLY},
- {"COLLATION_CONNECTION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "collation_connection", OPEN_FRM_ONLY},
- {"DATABASE_COLLATION", MY_CS_NAME_SIZE, MYSQL_TYPE_STRING, 0, 0,
- "Database Collation", OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CREATED", Datetime(2), NULLABLE, "Created", OPEN_FRM_ONLY),
+ Column("SQL_MODE", SQLMode(), NOT_NULL, "sql_mode", OPEN_FRM_ONLY),
+ Column("DEFINER", Definer(), NOT_NULL, "Definer", OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_CLIENT", CSName(), NOT_NULL, "character_set_client",
+ OPEN_FRM_ONLY),
+ Column("COLLATION_CONNECTION", CSName(), NOT_NULL, "collation_connection",
+ OPEN_FRM_ONLY),
+ Column("DATABASE_COLLATION", CSName(), NOT_NULL, "Database Collation",
+ OPEN_FRM_ONLY),
+ CEnd()
};
ST_FIELD_INFO partitions_fields_info[]=
{
- {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_SCHEMA",NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"PARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"PARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_ORDINAL_POSITION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"PARTITION_METHOD", 18, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_METHOD", 12, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"PARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"SUBPARTITION_EXPRESSION", 65535, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {"PARTITION_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, 0,
- OPEN_FULL_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FULL_TABLE},
- {"PARTITION_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"NODEGROUP", 12 , MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLE_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("PARTITION_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_ORDINAL_POSITION", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_ORDINAL_POSITION",ULonglong(),NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_METHOD", Varchar(18), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_METHOD", Varchar(12), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_EXPRESSION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("SUBPARTITION_EXPRESSION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_DESCRIPTION", Longtext(65535), NULLABLE, OPEN_FULL_TABLE),
+ Column("TABLE_ROWS", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("AVG_ROW_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DATA_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("INDEX_LENGTH", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DATA_FREE", ULonglong(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHECKSUM", ULonglong(), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARTITION_COMMENT", Varchar(80), NOT_NULL, OPEN_FULL_TABLE),
+ Column("NODEGROUP", Varchar(12), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLESPACE_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO variables_fields_info[]=
{
- {"VARIABLE_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Variable_name",
- SKIP_OPEN_TABLE},
- {"VARIABLE_VALUE", 2048, MYSQL_TYPE_STRING, 0, 0, "Value", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("VARIABLE_NAME", Varchar(64), NOT_NULL, "Variable_name"),
+ Column("VARIABLE_VALUE", Varchar(2048), NOT_NULL, "Value"),
+ CEnd()
};
ST_FIELD_INFO sysvars_fields_info[]=
{
- {"VARIABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"SESSION_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"GLOBAL_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"GLOBAL_VALUE_ORIGIN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"DEFAULT_VALUE", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"VARIABLE_SCOPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"VARIABLE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"VARIABLE_COMMENT", TABLE_COMMENT_MAXLEN, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"NUMERIC_MIN_VALUE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"NUMERIC_MAX_VALUE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"NUMERIC_BLOCK_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"ENUM_VALUE_LIST", 65535, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {"READ_ONLY", 3, MYSQL_TYPE_STRING, 0, 0, 0, 0},
- {"COMMAND_LINE_ARGUMENT", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+ Column("VARIABLE_NAME", Name(), NOT_NULL),
+ Column("SESSION_VALUE", Varchar(2048), NULLABLE),
+ Column("GLOBAL_VALUE", Varchar(2048), NULLABLE),
+ Column("GLOBAL_VALUE_ORIGIN", Name(), NOT_NULL),
+ Column("DEFAULT_VALUE", Varchar(2048), NULLABLE),
+ Column("VARIABLE_SCOPE", Name(), NOT_NULL),
+ Column("VARIABLE_TYPE", Name(), NOT_NULL),
+ Column("VARIABLE_COMMENT", Varchar(TABLE_COMMENT_MAXLEN), NOT_NULL),
+ Column("NUMERIC_MIN_VALUE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("NUMERIC_MAX_VALUE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("NUMERIC_BLOCK_SIZE", Varchar(MY_INT64_NUM_DECIMAL_DIGITS), NULLABLE),
+ Column("ENUM_VALUE_LIST", Longtext(65535), NULLABLE),
+ Column("READ_ONLY", Yesno(), NOT_NULL),
+ Column("COMMAND_LINE_ARGUMENT",Name(), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO processlist_fields_info[]=
{
- {"ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Id", SKIP_OPEN_TABLE},
- {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User",
- SKIP_OPEN_TABLE},
- {"HOST", LIST_PROCESS_HOST_LEN, MYSQL_TYPE_STRING, 0, 0, "Host",
- SKIP_OPEN_TABLE},
- {"DB", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Db", SKIP_OPEN_TABLE},
- {"COMMAND", 16, MYSQL_TYPE_STRING, 0, 0, "Command", SKIP_OPEN_TABLE},
- {"TIME", 7, MYSQL_TYPE_LONG, 0, 0, "Time", SKIP_OPEN_TABLE},
- {"STATE", 64, MYSQL_TYPE_STRING, 0, 1, "State", SKIP_OPEN_TABLE},
- {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info",
- SKIP_OPEN_TABLE},
- {"TIME_MS", 100 * (MY_INT64_NUM_DECIMAL_DIGITS + 1) + 3, MYSQL_TYPE_DECIMAL,
- 0, 0, "Time_ms", SKIP_OPEN_TABLE},
- {"STAGE", 2, MYSQL_TYPE_TINY, 0, 0, "Stage", SKIP_OPEN_TABLE},
- {"MAX_STAGE", 2, MYSQL_TYPE_TINY, 0, 0, "Max_stage", SKIP_OPEN_TABLE},
- {"PROGRESS", 703, MYSQL_TYPE_DECIMAL, 0, 0, "Progress",
- SKIP_OPEN_TABLE},
- {"MEMORY_USED", 7, MYSQL_TYPE_LONGLONG, 0, 0, "Memory_used", SKIP_OPEN_TABLE},
- {"MAX_MEMORY_USED", 7, MYSQL_TYPE_LONGLONG, 0, 0, "Max_memory_used", SKIP_OPEN_TABLE},
- {"EXAMINED_ROWS", 7, MYSQL_TYPE_LONG, 0, 0, "Examined_rows", SKIP_OPEN_TABLE},
- {"QUERY_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"INFO_BINARY", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_BLOB, 0, 1,
- "Info_binary", SKIP_OPEN_TABLE},
- {"TID", 4, MYSQL_TYPE_LONGLONG, 0, 0, "Tid", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("ID", SLonglong(4), NOT_NULL, "Id"),
+ Column("USER", Varchar(USERNAME_CHAR_LENGTH), NOT_NULL, "User"),
+ Column("HOST", Varchar(LIST_PROCESS_HOST_LEN),NOT_NULL, "Host"),
+ Column("DB", Name(), NULLABLE, "Db"),
+ Column("COMMAND", Varchar(16), NOT_NULL, "Command"),
+ Column("TIME", SLong(7), NOT_NULL, "Time"),
+ Column("STATE", Varchar(64), NULLABLE, "State"),
+ Column("INFO", Longtext(PROCESS_LIST_INFO_WIDTH),
+ NULLABLE, "Info"),
+ Column("TIME_MS", Decimal(100 * (MY_INT64_NUM_DECIMAL_DIGITS + 1) + 3),
+ NOT_NULL, "Time_ms"),
+ Column("STAGE", STiny(2), NOT_NULL, "Stage"),
+ Column("MAX_STAGE", STiny(2), NOT_NULL, "Max_stage"),
+ Column("PROGRESS", Decimal(703), NOT_NULL, "Progress"),
+ Column("MEMORY_USED", SLonglong(7), NOT_NULL, "Memory_used"),
+ Column("MAX_MEMORY_USED",SLonglong(7), NOT_NULL, "Max_memory_used"),
+ Column("EXAMINED_ROWS", SLong(7), NOT_NULL, "Examined_rows"),
+ Column("QUERY_ID", SLonglong(4), NOT_NULL),
+ Column("INFO_BINARY",Blob(PROCESS_LIST_INFO_WIDTH),NULLABLE, "Info_binary"),
+ Column("TID", SLonglong(4), NOT_NULL, "Tid"),
+ CEnd()
};
ST_FIELD_INFO plugin_fields_info[]=
{
- {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name",
- SKIP_OPEN_TABLE},
- {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_STATUS", 16, MYSQL_TYPE_STRING, 0, 0, "Status", SKIP_OPEN_TABLE},
- {"PLUGIN_TYPE", 80, MYSQL_TYPE_STRING, 0, 0, "Type", SKIP_OPEN_TABLE},
- {"PLUGIN_TYPE_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_LIBRARY", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, "Library",
- SKIP_OPEN_TABLE},
- {"PLUGIN_LIBRARY_VERSION", 20, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_AUTHOR", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_DESCRIPTION", 65535, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_LICENSE", 80, MYSQL_TYPE_STRING, 0, 0, "License", SKIP_OPEN_TABLE},
- {"LOAD_OPTION", 64, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_MATURITY", 12, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"PLUGIN_AUTH_VERSION", 80, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("PLUGIN_NAME", Name(), NOT_NULL, "Name"),
+ Column("PLUGIN_VERSION", Varchar(20), NOT_NULL),
+ Column("PLUGIN_STATUS", Varchar(16), NOT_NULL, "Status"),
+ Column("PLUGIN_TYPE", Varchar(80), NOT_NULL, "Type"),
+ Column("PLUGIN_TYPE_VERSION", Varchar(20), NOT_NULL),
+ Column("PLUGIN_LIBRARY", Name(), NULLABLE, "Library"),
+ Column("PLUGIN_LIBRARY_VERSION", Varchar(20), NULLABLE),
+ Column("PLUGIN_AUTHOR", Name(), NULLABLE),
+ Column("PLUGIN_DESCRIPTION", Longtext(65535), NULLABLE),
+ Column("PLUGIN_LICENSE", Varchar(80), NOT_NULL, "License"),
+ Column("LOAD_OPTION", Varchar(64), NOT_NULL),
+ Column("PLUGIN_MATURITY", Varchar(12), NOT_NULL),
+ Column("PLUGIN_AUTH_VERSION", Varchar(80), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO files_fields_info[]=
{
- {"FILE_ID", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"FILE_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"FILE_TYPE", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"TABLE_CATALOG", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0,
- SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NUMBER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"FULLTEXT_KEYS", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {"DELETED_ROWS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"UPDATE_COUNT", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"FREE_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TOTAL_EXTENTS", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"LAST_ACCESS_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE},
- {"RECOVER_TIME", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"TRANSACTION_COUNTER", 4, MYSQL_TYPE_LONGLONG, 0, 1, 0, SKIP_OPEN_TABLE},
- {"VERSION", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Version", SKIP_OPEN_TABLE},
- {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE},
- {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE},
- {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE},
- {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE},
- {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE},
- {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE},
- {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE},
- {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE},
- {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE},
- {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE},
- {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE},
- {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("FILE_ID", SLonglong(4), NOT_NULL),
+ Column("FILE_NAME", Varchar(FN_REFLEN),NULLABLE),
+ Column("FILE_TYPE", Varchar(20), NOT_NULL),
+ Column("TABLESPACE_NAME", Name(), NULLABLE),
+ Column("TABLE_CATALOG", Name(), NOT_NULL),
+ Column("TABLE_SCHEMA", Name(), NULLABLE),
+ Column("TABLE_NAME", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NAME", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NUMBER",SLonglong(4), NULLABLE),
+ Column("ENGINE", Name(), NOT_NULL),
+ Column("FULLTEXT_KEYS", Name(), NULLABLE),
+ Column("DELETED_ROWS", SLonglong(4), NULLABLE),
+ Column("UPDATE_COUNT", SLonglong(4), NULLABLE),
+ Column("FREE_EXTENTS", SLonglong(4), NULLABLE),
+ Column("TOTAL_EXTENTS", SLonglong(4), NULLABLE),
+ Column("EXTENT_SIZE", SLonglong(4), NOT_NULL),
+ Column("INITIAL_SIZE", ULonglong(), NULLABLE),
+ Column("MAXIMUM_SIZE", ULonglong(), NULLABLE),
+ Column("AUTOEXTEND_SIZE", ULonglong(), NULLABLE),
+ Column("CREATION_TIME", Datetime(0), NULLABLE),
+ Column("LAST_UPDATE_TIME", Datetime(0), NULLABLE),
+ Column("LAST_ACCESS_TIME", Datetime(0), NULLABLE),
+ Column("RECOVER_TIME", SLonglong(4), NULLABLE),
+ Column("TRANSACTION_COUNTER", SLonglong(4), NULLABLE),
+ Column("VERSION", ULonglong(), NULLABLE, "Version"),
+ Column("ROW_FORMAT", Varchar(10), NULLABLE, "Row_format"),
+ Column("TABLE_ROWS", ULonglong(), NULLABLE, "Rows"),
+ Column("AVG_ROW_LENGTH", ULonglong(), NULLABLE, "Avg_row_length"),
+ Column("DATA_LENGTH", ULonglong(), NULLABLE, "Data_length"),
+ Column("MAX_DATA_LENGTH", ULonglong(), NULLABLE, "Max_data_length"),
+ Column("INDEX_LENGTH", ULonglong(), NULLABLE, "Index_length"),
+ Column("DATA_FREE", ULonglong(), NULLABLE, "Data_free"),
+ Column("CREATE_TIME", Datetime(0), NULLABLE, "Create_time"),
+ Column("UPDATE_TIME", Datetime(0), NULLABLE, "Update_time"),
+ Column("CHECK_TIME", Datetime(0), NULLABLE, "Check_time"),
+ Column("CHECKSUM", ULonglong(), NULLABLE, "Checksum"),
+ Column("STATUS", Varchar(20), NOT_NULL),
+ Column("EXTRA", Varchar(255), NULLABLE),
+ CEnd()
};
+}; // namespace Show
+
+
void init_fill_schema_files_row(TABLE* table)
{
int i;
- for(i=0; files_fields_info[i].field_name!=NULL; i++)
+ for(i=0; !Show::files_fields_info[i].end_marker(); i++)
table->field[i]->set_null();
table->field[IS_FILES_STATUS]->set_notnull();
table->field[IS_FILES_STATUS]->store("NORMAL", 6, system_charset_info);
}
+
+namespace Show {
+
ST_FIELD_INFO referential_constraints_fields_info[]=
{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"UNIQUE_CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0,
- MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE},
- {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"REFERENCED_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UNIQUE_CONSTRAINT_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("MATCH_OPTION", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("UPDATE_RULE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("DELETE_RULE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("REFERENCED_TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO parameters_fields_info[]=
{
- {"SPECIFIC_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"SPECIFIC_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"SPECIFIC_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FULL_TABLE},
- {"PARAMETER_MODE", 5, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"PARAMETER_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"DATA_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0, OPEN_FULL_TABLE},
- {"DATETIME_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG,
- 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, OPEN_FRM_ONLY},
- {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0, OPEN_FULL_TABLE},
- {"DTD_IDENTIFIER", 65535, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"ROUTINE_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}
+ Column("SPECIFIC_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("SPECIFIC_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("SPECIFIC_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ORDINAL_POSITION", SLong(21), NOT_NULL, OPEN_FULL_TABLE),
+ Column("PARAMETER_MODE", Varchar(5), NULLABLE, OPEN_FULL_TABLE),
+ Column("PARAMETER_NAME", Name(), NULLABLE, OPEN_FULL_TABLE),
+ Column("DATA_TYPE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CHARACTER_MAXIMUM_LENGTH",SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("CHARACTER_OCTET_LENGTH", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("NUMERIC_PRECISION", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("NUMERIC_SCALE", SLong(21), NULLABLE, OPEN_FULL_TABLE),
+ Column("DATETIME_PRECISION", ULonglong(), NULLABLE, OPEN_FRM_ONLY),
+ Column("CHARACTER_SET_NAME", Varchar(64), NULLABLE, OPEN_FULL_TABLE),
+ Column("COLLATION_NAME", Varchar(64), NULLABLE, OPEN_FULL_TABLE),
+ Column("DTD_IDENTIFIER", Longtext(65535), NOT_NULL, OPEN_FULL_TABLE),
+ Column("ROUTINE_TYPE", Varchar(9), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
ST_FIELD_INFO tablespaces_fields_info[]=
{
- {"TABLESPACE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- SKIP_OPEN_TABLE},
- {"ENGINE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
- 0, SKIP_OPEN_TABLE},
- {"LOGFILE_GROUP_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL,
- 0, SKIP_OPEN_TABLE},
- {"EXTENT_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"NODEGROUP_ID", 21, MYSQL_TYPE_LONGLONG, 0,
- MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED, 0, SKIP_OPEN_TABLE},
- {"TABLESPACE_COMMENT", 2048, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0,
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("TABLESPACE_NAME", Name(), NOT_NULL),
+ Column("ENGINE", Name(), NOT_NULL),
+ Column("TABLESPACE_TYPE", Name(), NULLABLE),
+ Column("LOGFILE_GROUP_NAME", Name(), NULLABLE),
+ Column("EXTENT_SIZE", ULonglong(), NULLABLE),
+ Column("AUTOEXTEND_SIZE", ULonglong(), NULLABLE),
+ Column("MAXIMUM_SIZE", ULonglong(), NULLABLE),
+ Column("NODEGROUP_ID", ULonglong(), NULLABLE),
+ Column("TABLESPACE_COMMENT", Varchar(2048), NULLABLE),
+ CEnd()
};
ST_FIELD_INFO keycache_fields_info[]=
{
- {"KEY_CACHE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SEGMENTS", 3, MYSQL_TYPE_LONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED) , 0, SKIP_OPEN_TABLE},
- {"SEGMENT_NUMBER", 3, MYSQL_TYPE_LONG, 0,
- (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"FULL_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE},
- {"BLOCK_SIZE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE },
- {"USED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_used", SKIP_OPEN_TABLE},
- {"UNUSED_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_unused", SKIP_OPEN_TABLE},
- {"DIRTY_BLOCKS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_blocks_not_flushed", SKIP_OPEN_TABLE},
- {"READ_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_read_requests", SKIP_OPEN_TABLE},
- {"READS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_reads", SKIP_OPEN_TABLE},
- {"WRITE_REQUESTS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_write_requests", SKIP_OPEN_TABLE},
- {"WRITES", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0,
- (MY_I_S_UNSIGNED), "Key_writes", SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
+ Column("KEY_CACHE_NAME",Varchar(NAME_LEN),NOT_NULL),
+ Column("SEGMENTS", ULong(3), NULLABLE),
+ Column("SEGMENT_NUMBER", ULong(3), NULLABLE),
+ Column("FULL_SIZE", ULonglong(), NOT_NULL),
+ Column("BLOCK_SIZE", ULonglong(), NOT_NULL),
+ Column("USED_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_used"),
+ Column("UNUSED_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_unused"),
+ Column("DIRTY_BLOCKS", ULonglong(), NOT_NULL, "Key_blocks_not_flushed"),
+ Column("READ_REQUESTS", ULonglong(), NOT_NULL, "Key_read_requests"),
+ Column("READS", ULonglong(), NOT_NULL, "Key_reads"),
+ Column("WRITE_REQUESTS", ULonglong(), NOT_NULL, "Key_write_requests"),
+ Column("WRITES", ULonglong(), NOT_NULL, "Key_writes"),
+ CEnd()
};
ST_FIELD_INFO show_explain_fields_info[]=
{
- /* field_name, length, type, value, field_flags, old_name*/
- {"id", 3, MYSQL_TYPE_LONGLONG, 0 /*value*/, MY_I_S_MAYBE_NULL, "id",
- SKIP_OPEN_TABLE},
- {"select_type", 19, MYSQL_TYPE_STRING, 0 /*value*/, 0, "select_type",
- SKIP_OPEN_TABLE},
- {"table", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0 /*value*/, MY_I_S_MAYBE_NULL,
- "table", SKIP_OPEN_TABLE},
- {"type", 15, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, "type", SKIP_OPEN_TABLE},
- {"possible_keys", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "possible_keys", SKIP_OPEN_TABLE},
- {"key", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "key", SKIP_OPEN_TABLE},
- {"key_len", NAME_CHAR_LEN*MAX_KEY, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "key_len", SKIP_OPEN_TABLE},
- {"ref", NAME_CHAR_LEN*MAX_REF_PARTS, MYSQL_TYPE_STRING, 0/*value*/,
- MY_I_S_MAYBE_NULL, "ref", SKIP_OPEN_TABLE},
- {"rows", 10, MYSQL_TYPE_LONGLONG, 0/*value*/, MY_I_S_MAYBE_NULL, "rows",
- SKIP_OPEN_TABLE},
- {"Extra", 255, MYSQL_TYPE_STRING, 0/*value*/, 0 /*flags*/, "Extra",
- SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
-};
-
-
-#ifdef HAVE_SPATIAL
-ST_FIELD_INFO geometry_columns_fields_info[]=
-{
- {"F_TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"F_GEOMETRY_COLUMN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"G_TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FRM_ONLY},
- {"G_GEOMETRY_COLUMN", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Field",
- OPEN_FRM_ONLY},
- {"STORAGE_TYPE", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"GEOMETRY_TYPE", 7, MYSQL_TYPE_LONG, 0, 0, 0, OPEN_FRM_ONLY},
- {"COORD_DIMENSION", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"MAX_PPR", 2, MYSQL_TYPE_TINY, 0, 0, 0, OPEN_FRM_ONLY},
- {"SRID", 5, MYSQL_TYPE_SHORT, 0, 0, 0, OPEN_FRM_ONLY},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+ Column("id", SLonglong(3), NULLABLE, "id"),
+ Column("select_type", Varchar(19), NOT_NULL, "select_type"),
+ Column("table", Name(), NULLABLE, "table"),
+ Column("type", Varchar(15), NULLABLE, "type"),
+ Column("possible_keys",Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "possible_keys"),
+ Column("key", Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "key"),
+ Column("key_len", Varchar(NAME_CHAR_LEN*MAX_KEY), NULLABLE, "key_len"),
+ Column("ref", Varchar(NAME_CHAR_LEN*MAX_REF_PARTS),NULLABLE, "ref"),
+ Column("rows", SLonglong(10), NULLABLE, "rows"),
+ Column("Extra", Varchar(255), NOT_NULL, "Extra"),
+ CEnd()
};
-ST_FIELD_INFO spatial_ref_sys_fields_info[]=
+ST_FIELD_INFO check_constraints_fields_info[]=
{
- {"SRID", 5, MYSQL_TYPE_SHORT, 0, 0, 0, SKIP_OPEN_TABLE},
- {"AUTH_NAME", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {"AUTH_SRID", 5, MYSQL_TYPE_LONG, 0, 0, 0, SKIP_OPEN_TABLE},
- {"SRTEXT", 2048, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}
+ Column("CONSTRAINT_CATALOG", Catalog(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_SCHEMA", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CONSTRAINT_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("TABLE_NAME", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ Column("CHECK_CLAUSE", Name(), NOT_NULL, OPEN_FULL_TABLE),
+ CEnd()
};
-#endif /*HAVE_SPATIAL*/
+}; // namespace Show
-ST_FIELD_INFO check_constraints_fields_info[]=
-{
- {"CONSTRAINT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE},
- {"CHECK_CLAUSE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0,
- OPEN_FULL_TABLE},
- {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}
-};
+
+namespace Show {
/** For creating fields of information_schema.OPTIMIZER_TRACE */
extern ST_FIELD_INFO optimizer_trace_info[];
+} //namespace Show
+
/*
Description of ST_FIELD_INFO in table.h
@@ -9859,108 +9454,101 @@ extern ST_FIELD_INFO optimizer_trace_info[];
ST_SCHEMA_TABLE schema_tables[]=
{
- {"ALL_PLUGINS", plugin_fields_info, 0,
+ {"ALL_PLUGINS", Show::plugin_fields_info, 0,
fill_all_plugins, make_old_format, 0, 5, -1, 0, 0},
- {"APPLICABLE_ROLES", applicable_roles_fields_info, 0,
+ {"APPLICABLE_ROLES", Show::applicable_roles_fields_info, 0,
fill_schema_applicable_roles, 0, 0, -1, -1, 0, 0},
- {"CHARACTER_SETS", charsets_fields_info, 0,
+ {"CHARACTER_SETS", Show::charsets_fields_info, 0,
fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0},
- {"CHECK_CONSTRAINTS", check_constraints_fields_info, 0,
+ {"CHECK_CONSTRAINTS", Show::check_constraints_fields_info, 0,
get_all_tables, 0, get_check_constraints_record, 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"COLLATIONS", collation_fields_info, 0,
+ {"COLLATIONS", Show::collation_fields_info, 0,
fill_schema_collation, make_old_format, 0, -1, -1, 0, 0},
- {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info,
+ {"COLLATION_CHARACTER_SET_APPLICABILITY", Show::coll_charset_app_fields_info,
0, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0},
- {"COLUMNS", columns_fields_info, 0,
+ {"COLUMNS", Show::columns_fields_info, 0,
get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
- {"COLUMN_PRIVILEGES", column_privileges_fields_info, 0,
+ {"COLUMN_PRIVILEGES", Show::column_privileges_fields_info, 0,
fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
- {"ENABLED_ROLES", enabled_roles_fields_info, 0,
+ {"ENABLED_ROLES", Show::enabled_roles_fields_info, 0,
fill_schema_enabled_roles, 0, 0, -1, -1, 0, 0},
- {"ENGINES", engines_fields_info, 0,
+ {"ENGINES", Show::engines_fields_info, 0,
fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
#ifdef HAVE_EVENT_SCHEDULER
- {"EVENTS", events_fields_info, 0,
+ {"EVENTS", Show::events_fields_info, 0,
Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
#else
- {"EVENTS", events_fields_info, 0,
+ {"EVENTS", Show::events_fields_info, 0,
0, make_old_format, 0, -1, -1, 0, 0},
#endif
- {"EXPLAIN", show_explain_fields_info, 0, fill_show_explain,
+ {"EXPLAIN", Show::show_explain_fields_info, 0, fill_show_explain,
make_old_format, 0, -1, -1, TRUE /*hidden*/ , 0},
- {"FILES", files_fields_info, 0,
+ {"FILES", Show::files_fields_info, 0,
hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
- {"GLOBAL_STATUS", variables_fields_info, 0,
+ {"GLOBAL_STATUS", Show::variables_fields_info, 0,
fill_status, make_old_format, 0, 0, -1, 0, 0},
- {"GLOBAL_VARIABLES", variables_fields_info, 0,
+ {"GLOBAL_VARIABLES", Show::variables_fields_info, 0,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
- {"KEY_CACHES", keycache_fields_info, 0,
+ {"KEY_CACHES", Show::keycache_fields_info, 0,
fill_key_cache_tables, 0, 0, -1,-1, 0, 0},
- {"KEY_COLUMN_USAGE", key_column_usage_fields_info, 0,
+ {"KEY_COLUMN_USAGE", Show::key_column_usage_fields_info, 0,
get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"OPEN_TABLES", open_tables_fields_info, 0,
+ {"OPEN_TABLES", Show::open_tables_fields_info, 0,
fill_open_tables, make_old_format, 0, -1, -1, 1, 0},
- {"OPTIMIZER_TRACE", optimizer_trace_info, 0,
+ {"OPTIMIZER_TRACE", Show::optimizer_trace_info, 0,
fill_optimizer_trace_info, NULL, NULL, -1, -1, false, 0},
- {"PARAMETERS", parameters_fields_info, 0,
+ {"PARAMETERS", Show::parameters_fields_info, 0,
fill_schema_proc, 0, 0, -1, -1, 0, 0},
- {"PARTITIONS", partitions_fields_info, 0,
+ {"PARTITIONS", Show::partitions_fields_info, 0,
get_all_tables, 0, get_schema_partitions_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"PLUGINS", plugin_fields_info, 0,
+ {"PLUGINS", Show::plugin_fields_info, 0,
fill_plugins, make_old_format, 0, -1, -1, 0, 0},
- {"PROCESSLIST", processlist_fields_info, 0,
+ {"PROCESSLIST", Show::processlist_fields_info, 0,
fill_schema_processlist, make_old_format, 0, -1, -1, 0, 0},
- {"PROFILING", query_profile_statistics_info, 0,
+ {"PROFILING", Show::query_profile_statistics_info, 0,
fill_query_profile_statistics_info, make_profile_table_for_show,
NULL, -1, -1, false, 0},
- {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info,
+ {"REFERENTIAL_CONSTRAINTS", Show::referential_constraints_fields_info,
0, get_all_tables, 0, get_referential_constraints_record,
1, 9, 0, OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"ROUTINES", proc_fields_info, 0,
+ {"ROUTINES", Show::proc_fields_info, 0,
fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0},
- {"SCHEMATA", schema_fields_info, 0,
+ {"SCHEMATA", Show::schema_fields_info, 0,
fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0},
- {"SCHEMA_PRIVILEGES", schema_privileges_fields_info, 0,
+ {"SCHEMA_PRIVILEGES", Show::schema_privileges_fields_info, 0,
fill_schema_schema_privileges, 0, 0, -1, -1, 0, 0},
- {"SESSION_STATUS", variables_fields_info, 0,
+ {"SESSION_STATUS", Show::variables_fields_info, 0,
fill_status, make_old_format, 0, 0, -1, 0, 0},
- {"SESSION_VARIABLES", variables_fields_info, 0,
+ {"SESSION_VARIABLES", Show::variables_fields_info, 0,
fill_variables, make_old_format, 0, 0, -1, 0, 0},
- {"STATISTICS", stat_fields_info, 0,
+ {"STATISTICS", Show::stat_fields_info, 0,
get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0,
OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE},
- {"SYSTEM_VARIABLES", sysvars_fields_info, 0,
+ {"SYSTEM_VARIABLES", Show::sysvars_fields_info, 0,
fill_sysvars, make_old_format, 0, 0, -1, 0, 0},
- {"TABLES", tables_fields_info, 0,
+ {"TABLES", Show::tables_fields_info, 0,
get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0,
OPTIMIZE_I_S_TABLE},
- {"TABLESPACES", tablespaces_fields_info, 0,
+ {"TABLESPACES", Show::tablespaces_fields_info, 0,
hton_fill_schema_table, 0, 0, -1, -1, 0, 0},
- {"TABLE_CONSTRAINTS", table_constraints_fields_info, 0,
+ {"TABLE_CONSTRAINTS", Show::table_constraints_fields_info, 0,
get_all_tables, 0, get_schema_constraints_record, 3, 4, 0,
OPTIMIZE_I_S_TABLE|OPEN_TABLE_ONLY},
- {"TABLE_NAMES", table_names_fields_info, 0,
+ {"TABLE_NAMES", Show::table_names_fields_info, 0,
get_all_tables, make_table_names_old_format, 0, 1, 2, 1, OPTIMIZE_I_S_TABLE},
- {"TABLE_PRIVILEGES", table_privileges_fields_info, 0,
+ {"TABLE_PRIVILEGES", Show::table_privileges_fields_info, 0,
fill_schema_table_privileges, 0, 0, -1, -1, 0, 0},
- {"TRIGGERS", triggers_fields_info, 0,
+ {"TRIGGERS", Show::triggers_fields_info, 0,
get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0,
OPEN_TRIGGER_ONLY|OPTIMIZE_I_S_TABLE},
- {"USER_PRIVILEGES", user_privileges_fields_info, 0,
+ {"USER_PRIVILEGES", Show::user_privileges_fields_info, 0,
fill_schema_user_privileges, 0, 0, -1, -1, 0, 0},
- {"VIEWS", view_fields_info, 0,
+ {"VIEWS", Show::view_fields_info, 0,
get_all_tables, 0, get_schema_views_record, 1, 2, 0,
OPEN_VIEW_ONLY|OPTIMIZE_I_S_TABLE},
-#ifdef HAVE_SPATIAL
- {"GEOMETRY_COLUMNS", geometry_columns_fields_info, 0,
- get_all_tables, make_columns_old_format, get_geometry_column_record,
- 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL},
- {"SPATIAL_REF_SYS", spatial_ref_sys_fields_info, 0,
- fill_spatial_ref_sys, make_old_format, 0, -1, -1, 0, 0},
-#endif /*HAVE_SPATIAL*/
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};
@@ -9993,8 +9581,8 @@ int initialize_schema_table(st_plugin_int *plugin)
}
if (!schema_table->old_format)
- for (ST_FIELD_INFO *f= schema_table->fields_info; f->field_name; f++)
- if (f->old_name && f->old_name[0])
+ for (ST_FIELD_INFO *f= schema_table->fields_info; !f->end_marker(); f++)
+ if (f->old_name().str && f->old_name().str[0])
{
schema_table->old_format= make_old_format;
break;
@@ -10118,7 +9706,7 @@ static bool show_create_trigger_impl(THD *thd, Trigger *trigger)
Item_datetime_literal *tmp= (new (mem_root)
Item_datetime_literal(thd, &zero_time, 2));
- tmp->set_name(thd, STRING_WITH_LEN("Created"), system_charset_info);
+ tmp->set_name(thd, Lex_cstring(STRING_WITH_LEN("Created")));
fields.push_back(tmp, mem_root);
if (p->send_result_set_metadata(&fields,
diff --git a/sql/sql_show.h b/sql/sql_show.h
index 39cbc35230a..a98ba451088 100644
--- a/sql/sql_show.h
+++ b/sql/sql_show.h
@@ -76,6 +76,9 @@ typedef struct system_status_var STATUS_VAR;
#define IS_FILES_EXTRA 37
typedef enum { WITHOUT_DB_NAME, WITH_DB_NAME } enum_with_db_name;
+
+int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond);
+
int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet,
Table_specification_st *create_info_arg,
enum_with_db_name with_db_name);
@@ -117,9 +120,7 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name);
void view_store_options(THD *thd, TABLE_LIST *table, String *buff);
void init_fill_schema_files_row(TABLE* table);
-bool schema_table_store_record(THD *thd, TABLE *table);
void initialize_information_schema_acl();
-COND *make_cond_for_info_schema(THD *thd, COND *cond, TABLE_LIST *table);
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const LEX_CSTRING *table_name,
bool *in_plugin);
diff --git a/sql/sql_signal.cc b/sql/sql_signal.cc
index 320a954711a..1b1d2fe0f31 100644
--- a/sql/sql_signal.cc
+++ b/sql/sql_signal.cc
@@ -151,7 +151,7 @@ static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
Item *set, String *ci)
{
char str_buff[(64+1)*4]; /* Room for a null terminated UTF8 String 64 */
- String str_value(str_buff, sizeof(str_buff), & my_charset_utf8_bin);
+ String str_value(str_buff, sizeof(str_buff), & my_charset_utf8mb3_bin);
String *str;
bool truncated;
@@ -164,7 +164,7 @@ static int assign_condition_item(MEM_ROOT *mem_root, const char* name, THD *thd,
}
str= set->val_str(& str_value);
- truncated= assign_fixed_string(mem_root, & my_charset_utf8_bin, 64, ci, str);
+ truncated= assign_fixed_string(mem_root, & my_charset_utf8mb3_bin, 64, ci, str);
if (truncated)
{
if (thd->is_strict_mode())
@@ -260,7 +260,7 @@ int Sql_cmd_common_signal::eval_signal_informations(THD *thd, Sql_condition *con
bool truncated;
String utf8_text;
str= set->val_str(& str_value);
- truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8_bin,
+ truncated= assign_fixed_string(thd->mem_root, & my_charset_utf8mb3_bin,
MYSQL_ERRMSG_SIZE,
& utf8_text, str);
if (truncated)
diff --git a/sql/sql_string.h b/sql/sql_string.h
index 10af5a9426f..1eac2200625 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -139,6 +139,11 @@ public:
CHARSET_INFO *charset() const { return m_charset; }
uint mbminlen() const { return m_charset->mbminlen; }
uint mbmaxlen() const { return m_charset->mbmaxlen; }
+ bool is_good_for_ft() const
+ {
+ // Binary and UCS2/UTF16/UTF32 are not supported
+ return m_charset != &my_charset_bin && m_charset->mbminlen == 1;
+ }
size_t numchars(const char *str, const char *end) const
{
@@ -523,6 +528,10 @@ public:
q_append(s, size);
return false;
}
+ bool append(const LEX_CSTRING &s)
+ {
+ return append(s.str, s.length);
+ }
bool append(const Binary_string &s)
{
return append(s.ptr(), s.length());
@@ -900,6 +909,10 @@ public:
// Append with optional character set conversion from cs to charset()
bool append(const char *s, size_t arg_length, CHARSET_INFO *cs);
+ bool append(const LEX_CSTRING &s, CHARSET_INFO *cs)
+ {
+ return append(s.str, s.length, cs);
+ }
void strip_sp();
friend int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
@@ -992,6 +1005,15 @@ public:
};
+template<size_t buff_sz>
+class BinaryStringBuffer : public Binary_string
+{
+ char buff[buff_sz];
+public:
+ BinaryStringBuffer() : Binary_string(buff, buff_sz) { length(0); }
+};
+
+
class String_space: public String
{
public:
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f3e4d35c0f5..9bb1d98152b 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -28,7 +28,7 @@
#include "sql_base.h" // lock_table_names
#include "lock.h" // mysql_unlock_tables
#include "strfunc.h" // find_type2, find_set
-#include "sql_truncate.h" // regenerate_locked_table
+#include "sql_truncate.h" // regenerate_locked_table
#include "sql_partition.h" // mem_alloc_error,
// partition_info
// NOT_A_PARTITION_ID
@@ -2732,7 +2732,8 @@ bool log_drop_table(THD *thd, const LEX_CSTRING *db_name,
*/
bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
- const LEX_CSTRING *table_name, uint flags, const char *table_path)
+ const LEX_CSTRING *table_name, uint flags,
+ const char *table_path)
{
char path[FN_REFLEN + 1];
int error= 0;
@@ -2740,11 +2741,13 @@ bool quick_rm_table(THD *thd, handlerton *base, const LEX_CSTRING *db,
size_t path_length= table_path ?
(strxnmov(path, sizeof(path) - 1, table_path, reg_ext, NullS) - path) :
- build_table_filename(path, sizeof(path)-1, db->str, table_name->str, reg_ext, flags);
- if (mysql_file_delete(key_file_frm, path, MYF(0)))
- error= 1; /* purecov: inspected */
+ build_table_filename(path, sizeof(path)-1, db->str, table_name->str,
+ reg_ext, flags);
+ if (!(flags & NO_FRM_RENAME))
+ if (mysql_file_delete(key_file_frm, path, MYF(0)))
+ error= 1; /* purecov: inspected */
path[path_length - reg_ext_length]= '\0'; // Remove reg_ext
- if (flags & NO_HA_TABLE)
+ if ((flags & (NO_HA_TABLE | NO_PAR_TABLE)) == NO_HA_TABLE)
{
handler *file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base);
if (!file)
@@ -2850,7 +2853,7 @@ static int sort_keys(KEY *a, KEY *b)
*/
bool check_duplicates_in_interval(const char *set_or_name,
- const char *name, TYPELIB *typelib,
+ const char *name, const TYPELIB *typelib,
CHARSET_INFO *cs, unsigned int *dup_val_count)
{
TYPELIB tmp= *typelib;
@@ -3347,7 +3350,7 @@ static Create_field * add_hash_field(THD * thd, List<Create_field> *create_list,
}
}
cf->field_name= field_name;
- cf->set_handler(&type_handler_longlong);
+ cf->set_handler(&type_handler_slonglong);
key_info->algorithm= HA_KEY_ALG_LONG_HASH;
create_list->push_back(cf,thd->mem_root);
return cf;
@@ -3365,6 +3368,63 @@ mysql_add_invisible_index(THD *thd, List<Key> *key_list,
key_list->push_back(key, thd->mem_root);
return key;
}
+
+
+bool Type_handler_string::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ /*
+ Set length to 0. It's set to the real column width later for CHAR.
+ It has to be the correct col width for CHAR, as its data are not
+ prefixed with length (unlike blobs).
+ */
+ part->length= 0;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+bool Type_handler_varchar::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ part->length= 0;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+bool
+Type_handler_blob_common::Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ /*
+ Set keyseg length to 1 for blobs.
+ It's ignored in ft code: the data length is taken from the length prefix.
+ */
+ part->length= 1;
+ return !Charset(def.charset).is_good_for_ft();
+}
+
+
+static bool
+key_add_part_check_null(const handler *file, KEY *key_info,
+ const Column_definition *sql_field,
+ const Key_part_spec *column)
+{
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ key_info->flags|= HA_NULL_PART_KEY;
+ if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
+ {
+ my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
+ return true;
+ }
+ }
+ return false;
+}
+
+
/*
Preparation for table creation
@@ -3415,12 +3475,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_EXECUTE_IF("test_pseudo_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, INVISIBLE_SYSTEM,
+ "invisible", &type_handler_slong, INVISIBLE_SYSTEM,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_completely_invisible",{
mysql_add_invisible_field(thd, &alter_info->create_list,
- "invisible", &type_handler_long, INVISIBLE_FULL,
+ "invisible", &type_handler_slong, INVISIBLE_FULL,
new (thd->mem_root)Item_int(thd, 9));
});
DBUG_EXECUTE_IF("test_invisible_index",{
@@ -3907,130 +3967,85 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
cols2.rewind();
- if (key->type == Key::FULLTEXT)
- {
- if ((sql_field->real_field_type() != MYSQL_TYPE_STRING &&
- sql_field->real_field_type() != MYSQL_TYPE_VARCHAR &&
- !f_is_blob(sql_field->pack_flag)) ||
- sql_field->charset == &my_charset_bin ||
- sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet
- (ft_key_charset && sql_field->charset != ft_key_charset))
- {
- my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
- DBUG_RETURN(-1);
- }
- ft_key_charset=sql_field->charset;
- /*
- for fulltext keys keyseg length is 1 for blobs (it's ignored in ft
- code anyway, and 0 (set to column width later) for char's. it has
- to be correct col width for char's, as char data are not prefixed
- with length (unlike blobs, where ft code takes data length from a
- data prefix, ignoring column->length).
- */
- column->length= MY_TEST(f_is_blob(sql_field->pack_flag));
- }
- else
- {
- column->length*= sql_field->charset->mbmaxlen;
+ switch(key->type) {
- if (key->type == Key::SPATIAL)
+ case Key::FULLTEXT:
+ if (sql_field->type_handler()->Key_part_spec_init_ft(column,
+ *sql_field) ||
+ (ft_key_charset && sql_field->charset != ft_key_charset))
{
- if (column->length)
- {
- my_error(ER_WRONG_SUB_KEY, MYF(0));
- DBUG_RETURN(TRUE);
- }
- if (!f_is_geom(sql_field->pack_flag))
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
- DBUG_RETURN(TRUE);
- }
+ my_error(ER_BAD_FT_COLUMN, MYF(0), column->field_name.str);
+ DBUG_RETURN(-1);
}
+ ft_key_charset= sql_field->charset;
+ break;
- if (f_is_blob(sql_field->pack_flag) ||
- (f_is_geom(sql_field->pack_flag) && key->type != Key::SPATIAL))
+ case Key::SPATIAL:
+ if (sql_field->type_handler()->Key_part_spec_init_spatial(column,
+ *sql_field) ||
+ sql_field->check_vcol_for_key(thd))
+ DBUG_RETURN(TRUE);
+ if (!(sql_field->flags & NOT_NULL_FLAG))
{
- if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS))
- {
- my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->field_name.str,
- file->table_type());
- DBUG_RETURN(TRUE);
- }
- if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type ==
- Field::GEOM_POINT)
- column->length= MAX_LEN_GEOM_POINT_FIELD;
- if (!column->length)
- {
- if (key->type == Key::UNIQUE)
- is_hash_field_needed= true;
- else if (key->type == Key::MULTIPLE)
- column->length= file->max_key_length() + 1;
- else
- {
- my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str);
- DBUG_RETURN(TRUE);
- }
- }
+ my_message(ER_SPATIAL_CANT_HAVE_NULL,
+ ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
+ DBUG_RETURN(TRUE);
}
-#ifdef HAVE_SPATIAL
- if (key->type == Key::SPATIAL)
- {
- if (!column->length)
- {
- /*
- 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
- Lately we'll extend this code to support more dimensions
- */
- column->length= 4*sizeof(double);
- }
- }
-#endif
+ break;
+
+ case Key::PRIMARY:
if (sql_field->vcol_info)
{
- if (key->type == Key::PRIMARY)
- {
- my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
- DBUG_RETURN(TRUE);
- }
- if (sql_field->vcol_info->flags & VCOL_NOT_STRICTLY_DETERMINISTIC)
- {
- /* use check_expression() to report an error */
- check_expression(sql_field->vcol_info, &sql_field->field_name,
- VCOL_GENERATED_STORED);
- DBUG_ASSERT(thd->is_error());
- DBUG_RETURN(TRUE);
- }
+ my_error(ER_PRIMARY_KEY_BASED_ON_GENERATED_COLUMN, MYF(0));
+ DBUG_RETURN(TRUE);
}
- if (!(sql_field->flags & NOT_NULL_FLAG))
- {
- if (key->type == Key::PRIMARY)
- {
- /* Implicitly set primary key fields to NOT NULL for ISO conf. */
- sql_field->flags|= NOT_NULL_FLAG;
- sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
- null_fields--;
- }
- else
- {
- key_info->flags|= HA_NULL_PART_KEY;
- if (!(file->ha_table_flags() & HA_NULL_IN_KEY))
- {
- my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->field_name.str);
- DBUG_RETURN(TRUE);
- }
- if (key->type == Key::SPATIAL)
- {
- my_message(ER_SPATIAL_CANT_HAVE_NULL,
- ER_THD(thd, ER_SPATIAL_CANT_HAVE_NULL), MYF(0));
- DBUG_RETURN(TRUE);
- }
- }
- }
- if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
- {
- if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
- auto_increment--; // Field is used
- }
+ if (sql_field->type_handler()->Key_part_spec_init_primary(column,
+ *sql_field,
+ file))
+ DBUG_RETURN(TRUE);
+ if (!(sql_field->flags & NOT_NULL_FLAG))
+ {
+ /* Implicitly set primary key fields to NOT NULL for ISO conf. */
+ sql_field->flags|= NOT_NULL_FLAG;
+ sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
+ null_fields--;
+ }
+ break;
+
+ case Key::MULTIPLE:
+ if (sql_field->type_handler()->Key_part_spec_init_multiple(column,
+ *sql_field,
+ file) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+
+ case Key::FOREIGN_KEY:
+ if (sql_field->type_handler()->Key_part_spec_init_foreign(column,
+ *sql_field,
+ file) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+
+ case Key::UNIQUE:
+ if (sql_field->type_handler()->Key_part_spec_init_unique(column,
+ *sql_field, file,
+ &is_hash_field_needed) ||
+ sql_field->check_vcol_for_key(thd) ||
+ key_add_part_check_null(file, key_info, sql_field, column))
+ DBUG_RETURN(TRUE);
+ break;
+ }
+
+ if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
+ {
+ DBUG_ASSERT(key->type != Key::FULLTEXT);
+ DBUG_ASSERT(key->type != Key::SPATIAL);
+ if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY))
+ auto_increment--; // Field is used
}
key_part_info->fieldnr= field;
@@ -5527,7 +5542,8 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
{
if (rename_file_ext(from,to,reg_ext))
error= my_errno;
- (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
+ if (!(flags & NO_PAR_TABLE))
+ (void) file->ha_create_partitioning_metadata(to, from, CHF_RENAME_FLAG);
}
else if (!file || likely(!(error=file->ha_rename_table(from_base, to_base))))
{
@@ -5551,7 +5567,6 @@ mysql_rename_table(handlerton *base, const LEX_CSTRING *old_db,
my_error(ER_BAD_DB_ERROR, MYF(0), new_db->str);
else if (error)
my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error);
-
else if (!(flags & FN_IS_TMP))
mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name);
@@ -5829,8 +5844,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
goto err;
/*
- As the reference table is temporary and may not exist on slave, we must
- force the ENGINE to be present into CREATE TABLE.
+ As the reference table is temporary and may not exist on slave, we
+ must force the ENGINE to be present into CREATE TABLE.
*/
create_info->used_fields|= HA_CREATE_USED_ENGINE;
@@ -7516,11 +7531,10 @@ static bool mysql_inplace_alter_table(THD *thd,
{
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN | MYSQL_OPEN_IGNORE_KILLED);
handlerton *db_type= table->s->db_type();
- MDL_ticket *mdl_ticket= table->mdl_ticket;
Alter_info *alter_info= ha_alter_info->alter_info;
bool reopen_tables= false;
bool res;
-
+ handlerton *hton;
DBUG_ENTER("mysql_inplace_alter_table");
/* Downgrade DDL lock while we are waiting for exclusive lock below */
@@ -7727,6 +7741,28 @@ static bool mysql_inplace_alter_table(THD *thd,
}
}
+ /* Notify the engine that the table definition has changed */
+
+ hton= table->file->ht;
+ if (hton->notify_tabledef_changed)
+ {
+ char db_buff[FN_REFLEN], table_buff[FN_REFLEN];
+ LEX_CSTRING tmp_db, tmp_table;
+ tmp_db.str= db_buff;
+ tmp_table.str= table_buff;
+ tmp_db.length= tablename_to_filename(table_list->db.str,
+ db_buff, sizeof(db_buff));
+ tmp_table.length= tablename_to_filename(table_list->table_name.str,
+ table_buff, sizeof(table_buff));
+ if ((hton->notify_tabledef_changed)(hton, &tmp_db, &tmp_table,
+ table->s->frm_image,
+ &table->s->tabledef_version))
+ {
+ my_error(HA_ERR_INCOMPATIBLE_DEFINITION, MYF(0));
+ DBUG_RETURN(true);
+ }
+ }
+
close_all_tables_for_name(thd, table->s,
alter_ctx->is_table_renamed() ?
HA_EXTRA_PREPARE_FOR_RENAME :
@@ -7751,24 +7787,6 @@ static bool mysql_inplace_alter_table(THD *thd,
DBUG_RETURN(true);
}
- table_list->mdl_request.ticket= mdl_ticket;
- if (open_table(thd, table_list, &ot_ctx))
- DBUG_RETURN(true);
-
- /*
- Tell the handler that the changed frm is on disk and table
- has been re-opened
- */
- table_list->table->file->ha_notify_table_changed();
-
- /*
- We might be going to reopen table down on the road, so we have to
- restore state of the TABLE object which we used for obtaining of
- handler object to make it usable for later reopening.
- */
- close_thread_table(thd, &thd->open_tables);
- table_list->table= NULL;
-
// Rename altered table if requested.
if (alter_ctx->is_table_renamed())
{
@@ -8220,15 +8238,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
flag to allow ALTER TABLE only if the table to be altered is empty.
*/
- if ((def->real_field_type() == MYSQL_TYPE_DATE ||
- def->real_field_type() == MYSQL_TYPE_NEWDATE ||
- def->real_field_type() == MYSQL_TYPE_DATETIME ||
- def->real_field_type() == MYSQL_TYPE_DATETIME2) &&
- !alter_ctx->datetime_field &&
- !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
- thd->variables.sql_mode & MODE_NO_ZERO_DATE)
- {
- alter_ctx->datetime_field= def;
+ if (!alter_ctx->implicit_default_value_error_field &&
+ !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
+ def->type_handler()->validate_implicit_default_value(thd, *def))
+ {
+ alter_ctx->implicit_default_value_error_field= def;
alter_ctx->error_if_not_empty= TRUE;
}
if (def->flags & VERS_SYSTEM_FIELD &&
@@ -9327,6 +9341,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore)
{
+ bool engine_changed;
DBUG_ENTER("mysql_alter_table");
/*
@@ -10209,6 +10224,23 @@ do_continue:;
}
/*
+ Check if file names for the engine are unique. If we change engine
+ and file names are unique then we don't need to rename the original
+ table to a temporary name during the rename phase
+
+ File names are unique if engine changed and
+ - Either new or old engine does not store the table in files
+ - Neither old or new engine uses files from another engine
+ The above is mainly true for the sequence and the partition engine.
+ */
+ engine_changed= ((new_table->file->ht != table->file->ht) &&
+ (((!(new_table->file->ha_table_flags() & HA_FILE_BASED) ||
+ !(table->file->ha_table_flags() & HA_FILE_BASED))) ||
+ (!(table->file->ha_table_flags() & HA_REUSES_FILE_NAMES) &&
+ !(new_table->file->ha_table_flags() &
+ HA_REUSES_FILE_NAMES))));
+
+ /*
Close the intermediate table that will be the new table, but do
not delete it! Even though MERGE tables do not have their children
attached here it is safe to call THD::drop_temporary_table().
@@ -10251,23 +10283,39 @@ do_continue:;
/*
Rename the old table to temporary name to have a backup in case
anything goes wrong while renaming the new table.
+ We only have to do this if name of the table is not changed.
+ If we are changing to use another table handler, we don't
+ have to do the rename as the table names will not interfer.
*/
char backup_name_buff[FN_LEN];
LEX_CSTRING backup_name;
backup_name.str= backup_name_buff;
- backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff),
- "%s2-%lx-%lx", tmp_file_prefix,
+ DBUG_PRINT("info", ("is_table_renamed: %d engine_changed: %d",
+ alter_ctx.is_table_renamed(), engine_changed));
+
+ if (!alter_ctx.is_table_renamed())
+ {
+ backup_name.length= my_snprintf(backup_name_buff, sizeof(backup_name_buff),
+ "%s2-%lx-%lx", tmp_file_prefix,
current_pid, (long) thd->thread_id);
- if (lower_case_table_names)
- my_casedn_str(files_charset_info, backup_name_buff);
- if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name,
- &alter_ctx.db, &backup_name, FN_TO_IS_TMP))
+ if (lower_case_table_names)
+ my_casedn_str(files_charset_info, backup_name_buff);
+ if (mysql_rename_table(old_db_type, &alter_ctx.db, &alter_ctx.table_name,
+ &alter_ctx.db, &backup_name,
+ FN_TO_IS_TMP |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE : 0)))
+ {
+ // Rename to temporary name failed, delete the new table, abort ALTER.
+ (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
+ &alter_ctx.tmp_name, FN_IS_TMP);
+ goto err_with_mdl;
+ }
+ }
+ else
{
- // Rename to temporary name failed, delete the new table, abort ALTER.
- (void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
- &alter_ctx.tmp_name, FN_IS_TMP);
- goto err_with_mdl;
+ /* The original table is the backup */
+ backup_name= alter_ctx.table_name;
}
// Rename the new table to the correct name.
@@ -10279,10 +10327,15 @@ do_continue:;
(void) quick_rm_table(thd, new_db_type, &alter_ctx.new_db,
&alter_ctx.tmp_name, FN_IS_TMP);
- // Restore the backup of the original table to the old name.
- (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
- &alter_ctx.db, &alter_ctx.alias,
- FN_FROM_IS_TMP | NO_FK_CHECKS);
+ if (!alter_ctx.is_table_renamed())
+ {
+ // Restore the backup of the original table to the old name.
+ (void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
+ &alter_ctx.db, &alter_ctx.alias,
+ FN_FROM_IS_TMP | NO_FK_CHECKS |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
+ 0));
+ }
goto err_with_mdl;
}
@@ -10302,7 +10355,9 @@ do_continue:;
// Restore the backup of the original table to the old name.
(void) mysql_rename_table(old_db_type, &alter_ctx.db, &backup_name,
&alter_ctx.db, &alter_ctx.alias,
- FN_FROM_IS_TMP | NO_FK_CHECKS);
+ FN_FROM_IS_TMP | NO_FK_CHECKS |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE :
+ 0));
goto err_with_mdl;
}
rename_table_in_stat_tables(thd, &alter_ctx.db, &alter_ctx.alias,
@@ -10310,7 +10365,19 @@ do_continue:;
}
// ALTER TABLE succeeded, delete the backup of the old table.
- if (quick_rm_table(thd, old_db_type, &alter_ctx.db, &backup_name, FN_IS_TMP))
+ error= quick_rm_table(thd, old_db_type, &alter_ctx.db, &backup_name,
+ FN_IS_TMP |
+ (engine_changed ? NO_HA_TABLE | NO_PAR_TABLE: 0));
+ if (engine_changed)
+ {
+ /* the .frm file was removed but not the original table */
+ error|= quick_rm_table(thd, old_db_type, &alter_ctx.db,
+ &alter_ctx.table_name,
+ NO_FRM_RENAME |
+ (engine_changed ? 0 : FN_IS_TMP));
+ }
+
+ if (error)
{
/*
The fact that deletion of the backup failed is not critical
@@ -10357,6 +10424,7 @@ end_temporary:
DBUG_RETURN(false);
err_new_table_cleanup:
+ DBUG_PRINT("error", ("err_new_table_cleanup"));
my_free(const_cast<uchar*>(frm.str));
/*
No default value was provided for a DATE/DATETIME field, the
@@ -10367,30 +10435,8 @@ err_new_table_cleanup:
if (unlikely(alter_ctx.error_if_not_empty &&
thd->get_stmt_da()->current_row_for_warning()))
{
- const char *f_val= "0000-00-00";
- const char *f_type= "date";
- switch (alter_ctx.datetime_field->real_field_type())
- {
- case MYSQL_TYPE_DATE:
- case MYSQL_TYPE_NEWDATE:
- break;
- case MYSQL_TYPE_DATETIME:
- case MYSQL_TYPE_DATETIME2:
- f_val= "0000-00-00 00:00:00";
- f_type= "datetime";
- break;
- default:
- /* Shouldn't get here. */
- DBUG_ASSERT(0);
- }
- bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= true;
- thd->push_warning_truncated_value_for_field(Sql_condition::WARN_LEVEL_WARN,
- f_type, f_val,
- new_table->s,
- alter_ctx.datetime_field->
- field_name.str);
- thd->abort_on_warning= save_abort_on_warning;
+ Abort_on_warning_instant_set aws(thd, true);
+ alter_ctx.report_implicit_default_value_error(thd, new_table->s);
}
if (new_table)
@@ -10406,11 +10452,16 @@ err_new_table_cleanup:
DBUG_RETURN(true);
err_with_mdl_after_alter:
+ DBUG_PRINT("error", ("err_with_mdl_after_alter"));
/* the table was altered. binlog the operation */
DBUG_ASSERT(!(mysql_bin_log.is_open() &&
thd->is_current_stmt_binlog_format_row() &&
(create_info->tmp_table())));
- write_bin_log(thd, true, thd->query(), thd->query_length());
+ /*
+ We can't reset error as we will return 'true' below and the server
+ expects that error is set
+ */
+ write_bin_log(thd, FALSE, thd->query(), thd->query_length());
err_with_mdl:
/*
@@ -10593,14 +10644,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to,
to->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
- bool save_abort_on_warning= thd->abort_on_warning;
- thd->abort_on_warning= false;
+ Abort_on_warning_instant_set aws(thd, false);
my_snprintf(warn_buff, sizeof(warn_buff),
"ORDER BY ignored as there is a user-defined clustered index"
" in the table '%-.192s'", from->s->table_name.str);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
warn_buff);
- thd->abort_on_warning= save_abort_on_warning;
}
else
{
diff --git a/sql/sql_table.h b/sql/sql_table.h
index 35bff0873ea..ae05fe05c5d 100644
--- a/sql/sql_table.h
+++ b/sql/sql_table.h
@@ -118,8 +118,6 @@ enum enum_explain_filename_mode
EXPLAIN_PARTITIONS_AS_COMMENT
};
-/* Maximum length of GEOM_POINT Field */
-#define MAX_LEN_GEOM_POINT_FIELD 25
/* depends on errmsg.txt Database `db`, Table `t` ... */
#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
@@ -140,6 +138,8 @@ static const uint NO_HA_TABLE= 1 << 4;
static const uint SKIP_SYMDIR_ACCESS= 1 << 5;
/** Don't check foreign key constraints while renaming table */
static const uint NO_FK_CHECKS= 1 << 6;
+/* Don't delete .par table in quick_rm_table() */
+static const uint NO_PAR_TABLE= 1 << 7;
uint filename_to_tablename(const char *from, char *to, size_t to_length,
bool stay_quiet = false);
diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc
index d912fabe8c8..bfbaf185243 100644
--- a/sql/sql_tablespace.cc
+++ b/sql/sql_tablespace.cc
@@ -32,7 +32,7 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info)
If the user haven't defined an engine, this will fallback to using the
default storage engine.
*/
- if (hton == NULL || hton->state != SHOW_OPTION_YES)
+ if (hton == NULL)
{
hton= ha_default_handlerton(thd);
if (ts_info->storage_engine != 0)
diff --git a/sql/sql_tvc.cc b/sql/sql_tvc.cc
index ef8e15df838..9eefd0376a5 100644
--- a/sql/sql_tvc.cc
+++ b/sql/sql_tvc.cc
@@ -647,7 +647,7 @@ st_select_lex *wrap_tvc(THD *thd, st_select_lex *tvc_sl,
wrapper_sl->set_linkage(tvc_sl->get_linkage());
wrapper_sl->parsing_place= SELECT_LIST;
item= new (thd->mem_root) Item_field(thd, &wrapper_sl->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (item == NULL || add_item_to_list(thd, item))
goto err;
(wrapper_sl->with_wild)++;
@@ -861,7 +861,7 @@ Item *Item_func_in::in_predicate_to_in_subs_transformer(THD *thd,
sq_select= lex->current_select;
sq_select->parsing_place= SELECT_LIST;
item= new (thd->mem_root) Item_field(thd, &sq_select->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (item == NULL || add_item_to_list(thd, item))
goto err;
(sq_select->with_wild)++;
diff --git a/sql/sql_type.cc b/sql/sql_type.cc
index 6653b8b1a3f..905676ee604 100644
--- a/sql/sql_type.cc
+++ b/sql/sql_type.cc
@@ -16,6 +16,7 @@
#include "mariadb.h"
#include "sql_type.h"
+#include "sql_type_geom.h"
#include "sql_const.h"
#include "sql_class.h"
#include "sql_time.h"
@@ -23,17 +24,29 @@
#include "log.h"
#include "tztime.h"
+
+const DTCollation &DTCollation_numeric::singleton()
+{
+ static const DTCollation_numeric tmp;
+ return tmp;
+}
+
+
Type_handler_row type_handler_row;
Type_handler_null type_handler_null;
Type_handler_bool type_handler_bool;
-Type_handler_tiny type_handler_tiny;
-Type_handler_short type_handler_short;
-Type_handler_long type_handler_long;
-Type_handler_int24 type_handler_int24;
-Type_handler_longlong type_handler_longlong;
-Type_handler_longlong type_handler_ulonglong; // Only used for CAST() for now
+Type_handler_tiny type_handler_stiny;
+Type_handler_short type_handler_sshort;
+Type_handler_long type_handler_slong;
+Type_handler_int24 type_handler_sint24;
+Type_handler_longlong type_handler_slonglong;
+Type_handler_utiny type_handler_utiny;
+Type_handler_ushort type_handler_ushort;
+Type_handler_ulong type_handler_ulong;
+Type_handler_uint24 type_handler_uint24;
+Type_handler_ulonglong type_handler_ulonglong;
Type_handler_vers_trx_id type_handler_vers_trx_id;
Type_handler_float type_handler_float;
Type_handler_double type_handler_double;
@@ -60,74 +73,137 @@ Type_handler_string type_handler_string;
Type_handler_var_string type_handler_var_string;
Type_handler_varchar type_handler_varchar;
Type_handler_hex_hybrid type_handler_hex_hybrid;
-static Type_handler_varchar_compressed type_handler_varchar_compressed;
+Type_handler_varchar_compressed type_handler_varchar_compressed;
Type_handler_tiny_blob type_handler_tiny_blob;
Type_handler_medium_blob type_handler_medium_blob;
Type_handler_long_blob type_handler_long_blob;
Type_handler_blob type_handler_blob;
-static Type_handler_blob_compressed type_handler_blob_compressed;
+Type_handler_blob_compressed type_handler_blob_compressed;
Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
-#ifdef HAVE_SPATIAL
-Type_handler_geometry type_handler_geometry;
-#endif
+
+class Type_collection_std: public Type_collection
+{
+public:
+ bool init(Type_handler_data *data) override
+ {
+ return false;
+ }
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return Type_handler::aggregate_for_result_traditional(a, b);
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override;
+};
+
+
+static Type_collection_std type_collection_std;
+
+const Type_collection *Type_handler::type_collection() const
+{
+ return &type_collection_std;
+}
+
+
+bool Type_handler::is_traditional_scalar_type() const
+{
+ return type_collection() == &type_collection_std;
+}
+
+
+class Type_collection_row: public Type_collection
+{
+public:
+ bool init(Type_handler_data *data) override
+ {
+ return false;
+ }
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ DBUG_ASSERT(a == &type_handler_row);
+ DBUG_ASSERT(b == &type_handler_row);
+ return &type_handler_row;
+ }
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+};
+
+
+static Type_collection_row type_collection_row;
+
+const Type_collection *Type_handler_row::type_collection() const
+{
+ return &type_collection_row;
+}
bool Type_handler_data::init()
{
#ifdef HAVE_SPATIAL
-
-#ifndef DBUG_OFF
- if (m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_non_commutative_test.add(&type_handler_geometry,
- &type_handler_varchar,
- &type_handler_long_blob))
- return true;
+ return type_collection_geometry.init(this);
#endif
+ return false;
+}
- return
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_null,
- &type_handler_geometry) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_hex_hybrid,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_tiny_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_medium_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_long_blob,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_varchar,
- &type_handler_long_blob) ||
- m_type_aggregator_for_result.add(&type_handler_geometry,
- &type_handler_string,
- &type_handler_long_blob) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_geometry,
- &type_handler_geometry) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_null,
- &type_handler_geometry) ||
- m_type_aggregator_for_comparison.add(&type_handler_geometry,
- &type_handler_long_blob,
- &type_handler_long_blob);
+
+const Type_handler *
+Type_handler::handler_by_name(const LEX_CSTRING &name)
+{
+#ifdef HAVE_SPATIAL
+ const Type_handler *ha= type_collection_geometry.handler_by_name(name);
+ if (ha)
+ return ha;
#endif
- return false;
+ return NULL;
+}
+
+
+const Type_handler *
+Type_handler::handler_by_name_or_error(const LEX_CSTRING &name)
+{
+ const Type_handler *h= handler_by_name(name);
+ if (!h)
+ my_error(ER_UNKNOWN_DATA_TYPE, MYF(0),
+ ErrConvString(name.str, name.length, system_charset_info).ptr());
+ return h;
}
@@ -1006,7 +1082,7 @@ Datetime_truncation_not_needed::Datetime_truncation_not_needed(THD *thd, Item *i
/********************************************************************/
-uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
+uint Type_numeric_attributes::find_max_decimals(Item **item, uint nitems)
{
uint res= 0;
for (uint i= 0; i < nitems; i++)
@@ -1015,55 +1091,61 @@ uint Type_std_attributes::count_max_decimals(Item **item, uint nitems)
}
-/**
- Set max_length/decimals of function if function is fixed point and
- result length/precision depends on argument ones.
-*/
-
-void Type_std_attributes::count_decimal_length(Item **item, uint nitems)
+uint Type_numeric_attributes::count_unsigned(Item **item, uint nitems)
{
- int max_int_part= 0;
- decimals= 0;
- unsigned_flag= 1;
- for (uint i=0 ; i < nitems ; i++)
+ uint res= 0;
+ for (uint i= 0 ; i < nitems ; i++)
{
- set_if_bigger(decimals, item[i]->decimals);
- set_if_bigger(max_int_part, item[i]->decimal_int_part());
- set_if_smaller(unsigned_flag, item[i]->unsigned_flag);
+ if (item[i]->unsigned_flag)
+ res++;
}
- int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
- fix_char_length(my_decimal_precision_to_length_no_truncation(precision,
- (uint8) decimals,
- unsigned_flag));
+ return res;
}
-/**
- Set max_length of if it is maximum length of its arguments.
-*/
-
-void Type_std_attributes::count_only_length(Item **item, uint nitems)
+uint32 Type_numeric_attributes::find_max_char_length(Item **item, uint nitems)
{
uint32 char_length= 0;
- unsigned_flag= 0;
for (uint i= 0; i < nitems ; i++)
- {
set_if_bigger(char_length, item[i]->max_char_length());
- set_if_bigger(unsigned_flag, item[i]->unsigned_flag);
- }
- fix_char_length(char_length);
+ return char_length;
}
-void Type_std_attributes::count_octet_length(Item **item, uint nitems)
+uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems)
{
- max_length= 0;
- unsigned_flag= 0;
+ uint32 octet_length= 0;
for (uint i= 0; i < nitems ; i++)
- {
- set_if_bigger(max_length, item[i]->max_length);
- set_if_bigger(unsigned_flag, item[i]->unsigned_flag);
- }
+ set_if_bigger(octet_length, item[i]->max_length);
+ return octet_length;
+}
+
+
+int Type_numeric_attributes::find_max_decimal_int_part(Item **item, uint nitems)
+{
+ int max_int_part= 0;
+ for (uint i=0 ; i < nitems ; i++)
+ set_if_bigger(max_int_part, item[i]->decimal_int_part());
+ return max_int_part;
+}
+
+
+/**
+ Set max_length/decimals of function if function is fixed point and
+ result length/precision depends on argument ones.
+*/
+
+void
+Type_numeric_attributes::aggregate_numeric_attributes_decimal(Item **item,
+ uint nitems,
+ bool unsigned_arg)
+{
+ int max_int_part= find_max_decimal_int_part(item, nitems);
+ decimals= find_max_decimals(item, nitems);
+ int precision= MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ (uint8) decimals,
+ unsigned_flag);
}
@@ -1072,7 +1154,9 @@ void Type_std_attributes::count_octet_length(Item **item, uint nitems)
result length/precision depends on argument ones.
*/
-void Type_std_attributes::count_real_length(Item **items, uint nitems)
+void
+Type_numeric_attributes::aggregate_numeric_attributes_real(Item **items,
+ uint nitems)
{
uint32 length= 0;
decimals= 0;
@@ -1111,16 +1195,17 @@ void Type_std_attributes::count_real_length(Item **items, uint nitems)
@retval False on success, true on error.
*/
-bool Type_std_attributes::count_string_length(const char *func_name,
- Item **items, uint nitems)
+bool Type_std_attributes::aggregate_attributes_string(const char *func_name,
+ Item **items, uint nitems)
{
if (agg_arg_charsets_for_string_result(collation, func_name,
items, nitems, 1))
return true;
if (collation.collation == &my_charset_bin)
- count_octet_length(items, nitems);
+ max_length= find_max_octet_length(items, nitems);
else
- count_only_length(items, nitems);
+ fix_char_length(find_max_char_length(items, nitems));
+ unsigned_flag= false;
decimals= max_length ? NOT_FIXED_DEC : 0;
return false;
}
@@ -1267,7 +1352,7 @@ Type_handler::get_handler_by_cmp_type(Item_result type)
{
switch (type) {
case REAL_RESULT: return &type_handler_double;
- case INT_RESULT: return &type_handler_longlong;
+ case INT_RESULT: return &type_handler_slonglong;
case DECIMAL_RESULT: return &type_handler_newdecimal;
case STRING_RESULT: return &type_handler_long_blob;
case TIME_RESULT: return &type_handler_datetime;
@@ -1341,26 +1426,175 @@ const Name
Type_handler_datetime_common::m_name_datetime(STRING_WITH_LEN("datetime")),
Type_handler_timestamp_common::m_name_timestamp(STRING_WITH_LEN("timestamp"));
+
+const Name Type_handler_utiny::name() const
+{
+ static Name tmp(STRING_WITH_LEN("tiny unsigned"));
+ return tmp;
+}
+
+
+const Name Type_handler_ushort::name() const
+{
+ static Name tmp(STRING_WITH_LEN("smallint unsigned"));
+ return tmp;
+}
+
+
+const Name Type_handler_uint24::name() const
+{
+ static Name tmp(STRING_WITH_LEN("mediumint unsigned"));
+ return tmp;
+}
+
+
+const Name Type_handler_ulong::name() const
+{
+ static Name tmp(STRING_WITH_LEN("int unsigned"));
+ return tmp;
+}
+
+
+const Name Type_handler_ulonglong::name() const
+{
+ static Name tmp(STRING_WITH_LEN("bigint unsigned"));
+ return tmp;
+}
+
+
+/***************************************************************************/
+
const Name
Type_handler::m_version_default(STRING_WITH_LEN("")),
Type_handler::m_version_mariadb53(STRING_WITH_LEN("mariadb-5.3")),
Type_handler::m_version_mysql56(STRING_WITH_LEN("mysql-5.6"));
-const Type_limits_int
- Type_handler_tiny::m_limits_sint8= Type_limits_sint8(),
- Type_handler_tiny::m_limits_uint8= Type_limits_uint8(),
- Type_handler_short::m_limits_sint16= Type_limits_sint16(),
- Type_handler_short::m_limits_uint16= Type_limits_uint16(),
- Type_handler_int24::m_limits_sint24= Type_limits_sint24(),
- Type_handler_int24::m_limits_uint24= Type_limits_uint24(),
- Type_handler_long::m_limits_sint32= Type_limits_sint32(),
- Type_handler_long::m_limits_uint32= Type_limits_uint32(),
- Type_handler_longlong::m_limits_sint64= Type_limits_sint64(),
- Type_handler_longlong::m_limits_uint64= Type_limits_uint64();
+/***************************************************************************/
+
+const Type_limits_int *Type_handler_tiny::type_limits_int() const
+{
+ static const Type_limits_sint8 limits_sint8;
+ return &limits_sint8;
+}
+
+const Type_limits_int *Type_handler_utiny::type_limits_int() const
+{
+ static const Type_limits_uint8 limits_uint8;
+ return &limits_uint8;
+}
+
+const Type_limits_int *Type_handler_short::type_limits_int() const
+{
+ static const Type_limits_sint16 limits_sint16;
+ return &limits_sint16;
+}
+
+const Type_limits_int *Type_handler_ushort::type_limits_int() const
+{
+ static const Type_limits_uint16 limits_uint16;
+ return &limits_uint16;
+}
+
+const Type_limits_int *Type_handler_int24::type_limits_int() const
+{
+ static const Type_limits_sint24 limits_sint24;
+ return &limits_sint24;
+}
+
+const Type_limits_int *Type_handler_uint24::type_limits_int() const
+{
+ static const Type_limits_uint24 limits_uint24;
+ return &limits_uint24;
+}
+
+const Type_limits_int *Type_handler_long::type_limits_int() const
+{
+ static const Type_limits_sint32 limits_sint32;
+ return &limits_sint32;
+}
+
+const Type_limits_int *Type_handler_ulong::type_limits_int() const
+{
+ static const Type_limits_uint32 limits_uint32;
+ return &limits_uint32;
+}
+
+const Type_limits_int *Type_handler_longlong::type_limits_int() const
+{
+ static const Type_limits_sint64 limits_sint64;
+ return &limits_sint64;
+}
+
+const Type_limits_int *Type_handler_ulonglong::type_limits_int() const
+{
+ static const Type_limits_uint64 limits_uint64;
+ return &limits_uint64;
+}
/***************************************************************************/
+const Type_handler *Type_handler_bool::type_handler_signed() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_bool::type_handler_unsigned() const
+{
+ return &type_handler_bool;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_signed() const
+{
+ return &type_handler_stiny;
+}
+
+const Type_handler *Type_handler_tiny::type_handler_unsigned() const
+{
+ return &type_handler_utiny;
+}
+
+const Type_handler *Type_handler_short::type_handler_signed() const
+{
+ return &type_handler_sshort;
+}
+
+const Type_handler *Type_handler_short::type_handler_unsigned() const
+{
+ return &type_handler_ushort;
+}
+
+const Type_handler *Type_handler_int24::type_handler_signed() const
+{
+ return &type_handler_sint24;
+}
+
+const Type_handler *Type_handler_int24::type_handler_unsigned() const
+{
+ return &type_handler_uint24;
+}
+
+const Type_handler *Type_handler_long::type_handler_signed() const
+{
+ return &type_handler_slong;
+}
+
+const Type_handler *Type_handler_long::type_handler_unsigned() const
+{
+ return &type_handler_ulong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_signed() const
+{
+ return &type_handler_slonglong;
+}
+
+const Type_handler *Type_handler_longlong::type_handler_unsigned() const
+{
+ return &type_handler_ulonglong;
+}
+
+/***************************************************************************/
const Type_handler *Type_handler_null::type_handler_for_comparison() const
{
@@ -1370,7 +1604,7 @@ const Type_handler *Type_handler_null::type_handler_for_comparison() const
const Type_handler *Type_handler_int_result::type_handler_for_comparison() const
{
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1439,7 +1673,7 @@ const Type_handler *Type_handler_typelib::type_handler_for_item_field() const
const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
{
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1448,14 +1682,12 @@ const Type_handler *Type_handler_typelib::cast_to_int_type_handler() const
bool
Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
{
- if (m_type_handler->is_traditional_type() && other->is_traditional_type())
- {
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, other);
- return false;
- }
- other= type_handler_data->
- m_type_aggregator_for_result.find_handler(m_type_handler, other);
+ const Type_collection *collection0= m_type_handler->type_collection();
+ if (collection0 == other->type_collection())
+ other= collection0->aggregate_for_result(m_type_handler, other);
+ else
+ other= type_handler_data->
+ m_type_aggregator_for_result.find_handler(m_type_handler, other);
if (!other)
return true;
m_type_handler= other;
@@ -1464,13 +1696,21 @@ Type_handler_hybrid_field_type::aggregate_for_result(const Type_handler *other)
const Type_handler *
-Type_handler::type_handler_long_or_longlong(uint max_char_length)
+Type_handler::type_handler_long_or_longlong(uint max_char_length,
+ bool unsigned_flag)
{
+ if (unsigned_flag)
+ {
+ if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
+ return &type_handler_ulong;
+ return &type_handler_ulonglong;
+ }
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS - 2)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_slong;
+ return &type_handler_slonglong;
}
+
/*
This method is called for CASE (and its abbreviations) and LEAST/GREATEST
when data type aggregation returned LONGLONG and there were some BIT
@@ -1481,8 +1721,8 @@ const Type_handler *
Type_handler::bit_and_int_mixture_handler(uint max_char_length)
{
if (max_char_length <= MY_INT32_NUM_DECIMAL_DIGITS)
- return &type_handler_long;
- return &type_handler_longlong;
+ return &type_handler_slong;
+ return &type_handler_slonglong;
}
@@ -1544,9 +1784,9 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
{
bit_and_non_bit_mixture_found= true;
if (type_handler() == &type_handler_bit)
- set_handler(&type_handler_longlong); // BIT + non-BIT
+ set_handler(&type_handler_slonglong); // BIT + non-BIT
else
- cur= &type_handler_longlong; // non-BIT + BIT
+ cur= &type_handler_slonglong; // non-BIT + BIT
}
if (aggregate_for_result(cur))
{
@@ -1555,7 +1795,7 @@ Type_handler_hybrid_field_type::aggregate_for_result(const char *funcname,
return true;
}
}
- if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
return false;
}
@@ -1574,37 +1814,42 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
{
DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
DBUG_ASSERT(h == h->type_handler_for_comparison());
-
- if (!m_type_handler->is_traditional_type() ||
- !h->is_traditional_type())
- {
+ const Type_collection *collection0= m_type_handler->type_collection();
+ if (collection0 == h->type_collection())
+ h= collection0->aggregate_for_comparison(m_type_handler, h);
+ else
h= type_handler_data->
- m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
- if (!h)
- return true;
- m_type_handler= h;
- DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
- return false;
- }
+ m_type_aggregator_for_comparison.find_handler(m_type_handler, h);
+ if (!h)
+ return true;
+ m_type_handler= h;
+ DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
+ return false;
+}
+
- Item_result a= cmp_type();
- Item_result b= h->cmp_type();
+const Type_handler *
+Type_collection_std::aggregate_for_comparison(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
if (a == STRING_RESULT && b == STRING_RESULT)
- m_type_handler= &type_handler_long_blob;
- else if (a == INT_RESULT && b == INT_RESULT)
- m_type_handler= &type_handler_longlong;
- else if (a == ROW_RESULT || b == ROW_RESULT)
- m_type_handler= &type_handler_row;
- else if (a == TIME_RESULT || b == TIME_RESULT)
+ return &type_handler_long_blob;
+ if (a == INT_RESULT && b == INT_RESULT)
+ return &type_handler_slonglong;
+ if (a == ROW_RESULT || b == ROW_RESULT)
+ return &type_handler_row;
+ if (a == TIME_RESULT || b == TIME_RESULT)
{
if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
{
/*
We're here if there's only one temporal data type:
either m_type_handler or h.
+ Temporal types bit non-temporal types.
*/
- if (b == TIME_RESULT)
- m_type_handler= h; // Temporal types bit non-temporal types
+ const Type_handler *res= b == TIME_RESULT ? hb : ha;
/*
Compare TIMESTAMP to a non-temporal type as DATETIME.
This is needed to make queries with fuzzy dates work:
@@ -1612,9 +1857,9 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
WHERE
ts BETWEEN '0000-00-00' AND '2010-00-01 00:00:00';
*/
- if (m_type_handler->type_handler_for_native_format() ==
- &type_handler_timestamp2)
- m_type_handler= &type_handler_datetime;
+ if (res->type_handler_for_native_format() == &type_handler_timestamp2)
+ return &type_handler_datetime;
+ return res;
}
else
{
@@ -1626,19 +1871,15 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
to print DATE constants using proper format:
'YYYY-MM-DD' rather than 'YYYY-MM-DD 00:00:00'.
*/
- if (m_type_handler->field_type() != h->field_type())
- m_type_handler= &type_handler_datetime;
+ if (ha->field_type() != hb->field_type())
+ return &type_handler_datetime;
+ return ha;
}
}
- else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
- (b == INT_RESULT || b == DECIMAL_RESULT))
- {
- m_type_handler= &type_handler_newdecimal;
- }
- else
- m_type_handler= &type_handler_double;
- DBUG_ASSERT(m_type_handler == m_type_handler->type_handler_for_comparison());
- return false;
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return &type_handler_newdecimal;
+ return &type_handler_double;
}
@@ -1654,12 +1895,12 @@ Type_handler_hybrid_field_type::aggregate_for_comparison(const Type_handler *h)
bool
Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
{
- if (!m_type_handler->is_traditional_type() ||
- !h->is_traditional_type())
+ const Type_collection *collection0= m_type_handler->type_collection();
+ if (collection0 == h->type_collection())
+ h= collection0->aggregate_for_min_max(m_type_handler, h);
+ else
{
/*
- If at least one data type is non-traditional,
- do aggregation for result immediately.
For now we suppose that these two expressions:
- LEAST(type1, type2)
- COALESCE(type1, type2)
@@ -1668,78 +1909,73 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const Type_handler *h)
This may change in the future.
*/
h= type_handler_data->
- m_type_aggregator_for_result.find_handler(m_type_handler, h);
- if (!h)
- return true;
- m_type_handler= h;
- return false;
+ m_type_aggregator_for_result.find_handler(m_type_handler, h);
}
+ if (!h)
+ return true;
+ m_type_handler= h;
+ return false;
+}
+
- Item_result a= cmp_type();
- Item_result b= h->cmp_type();
+const Type_handler *
+Type_collection_std::aggregate_for_min_max(const Type_handler *ha,
+ const Type_handler *hb) const
+{
+ Item_result a= ha->cmp_type();
+ Item_result b= hb->cmp_type();
DBUG_ASSERT(a != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
DBUG_ASSERT(b != ROW_RESULT); // Disallowed by check_cols() in fix_fields()
if (a == STRING_RESULT && b == STRING_RESULT)
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
- else if (a == INT_RESULT && b == INT_RESULT)
+ return Type_collection_std::aggregate_for_result(ha, hb);
+ if (a == INT_RESULT && b == INT_RESULT)
{
// BIT aggregates with non-BIT as BIGINT
- if (m_type_handler != h)
+ if (ha != hb)
{
- if (m_type_handler == &type_handler_bit)
- m_type_handler= &type_handler_longlong;
- else if (h == &type_handler_bit)
- h= &type_handler_longlong;
+ if (ha == &type_handler_bit)
+ ha= &type_handler_slonglong;
+ else if (hb == &type_handler_bit)
+ hb= &type_handler_slonglong;
}
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
+ return Type_collection_std::aggregate_for_result(ha, hb);
}
- else if (a == TIME_RESULT || b == TIME_RESULT)
+ if (a == TIME_RESULT || b == TIME_RESULT)
{
- if ((m_type_handler->type_handler_for_native_format() ==
- &type_handler_timestamp2) +
- (h->type_handler_for_native_format() ==
- &type_handler_timestamp2) == 1)
+ if ((ha->type_handler_for_native_format() == &type_handler_timestamp2) +
+ (hb->type_handler_for_native_format() == &type_handler_timestamp2) == 1)
{
/*
Handle LEAST(TIMESTAMP, non-TIMESTAMP) as DATETIME,
to make sure fuzzy dates work in this context:
LEAST('2001-00-00', timestamp_field)
*/
- m_type_handler= &type_handler_datetime2;
+ return &type_handler_datetime2;
}
- else if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
+ if ((a == TIME_RESULT) + (b == TIME_RESULT) == 1)
{
/*
We're here if there's only one temporal data type:
either m_type_handler or h.
+ Temporal types bit non-temporal types.
*/
- if (b == TIME_RESULT)
- m_type_handler= h; // Temporal types bit non-temporal types
+ return (b == TIME_RESULT) ? hb : ha;
}
- else
- {
- /*
- We're here if both m_type_handler and h are temporal data types.
- */
- m_type_handler=
- Type_handler::aggregate_for_result_traditional(m_type_handler, h);
- }
- }
- else if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
- (b == INT_RESULT || b == DECIMAL_RESULT))
- {
- m_type_handler= &type_handler_newdecimal;
+ /*
+ We're here if both m_type_handler and h are temporal data types.
+ */
+ return Type_collection_std::aggregate_for_result(ha, hb);
}
- else
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
{
- // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
- if (m_type_handler != &type_handler_float || h != &type_handler_float)
- m_type_handler= &type_handler_double;
+ return &type_handler_newdecimal;
}
- return false;
+ // Preserve FLOAT if two FLOATs, set to DOUBLE otherwise.
+ if (ha == &type_handler_float && hb == &type_handler_float)
+ return &type_handler_float;
+ return &type_handler_double;
}
@@ -1748,15 +1984,12 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
Item **items, uint nitems)
{
bool bit_and_non_bit_mixture_found= false;
- uint32 max_display_length;
// LEAST/GREATEST require at least two arguments
DBUG_ASSERT(nitems > 1);
set_handler(items[0]->type_handler());
- max_display_length= items[0]->max_display_length();
for (uint i= 1; i < nitems; i++)
{
const Type_handler *cur= items[i]->type_handler();
- set_if_bigger(max_display_length, items[i]->max_display_length());
// Check if BIT + non-BIT, or non-BIT + BIT
bit_and_non_bit_mixture_found|= (m_type_handler == &type_handler_bit) !=
(cur == &type_handler_bit);
@@ -1767,15 +2000,20 @@ Type_handler_hybrid_field_type::aggregate_for_min_max(const char *funcname,
return true;
}
}
- if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_longlong)
+ if (bit_and_non_bit_mixture_found && type_handler() == &type_handler_slonglong)
+ {
+ uint32 max_display_length= items[0]->max_display_length();
+ for (uint i= 1; i < nitems; i++)
+ set_if_bigger(max_display_length, items[i]->max_display_length());
set_handler(Type_handler::bit_and_int_mixture_handler(max_display_length));
+ }
return false;
}
const Type_handler *
-Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
- const Type_handler *h1)
+Type_collection_std::aggregate_for_num_op(const Type_handler *h0,
+ const Type_handler *h1) const
{
Item_result r0= h0->cmp_type();
Item_result r1= h1->cmp_type();
@@ -1791,7 +2029,7 @@ Type_handler::aggregate_for_num_op_traditional(const Type_handler *h0,
return &type_handler_newdecimal;
DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
- return &type_handler_longlong;
+ return &type_handler_slonglong;
}
@@ -1816,17 +2054,15 @@ Type_handler_hybrid_field_type::aggregate_for_num_op(const Type_aggregator *agg,
const Type_handler *h1)
{
const Type_handler *hres;
- if (h0->is_traditional_type() && h1->is_traditional_type())
- {
- set_handler(Type_handler::aggregate_for_num_op_traditional(h0, h1));
- return false;
- }
- if ((hres= agg->find_handler(h0, h1)))
- {
- set_handler(hres);
- return false;
- }
- return true;
+ const Type_collection *collection0= h0->type_collection();
+ if (collection0 == h1->type_collection())
+ hres= collection0->aggregate_for_num_op(h0, h1);
+ else
+ hres= agg->find_handler(h0, h1);
+ if (!hres)
+ return true;
+ m_type_handler= hres;
+ return false;
}
@@ -1838,11 +2074,11 @@ Type_handler::get_handler_by_field_type(enum_field_types type)
switch (type) {
case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
- case MYSQL_TYPE_TINY: return &type_handler_tiny;
- case MYSQL_TYPE_SHORT: return &type_handler_short;
- case MYSQL_TYPE_LONG: return &type_handler_long;
- case MYSQL_TYPE_LONGLONG: return &type_handler_longlong;
- case MYSQL_TYPE_INT24: return &type_handler_int24;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
case MYSQL_TYPE_YEAR: return &type_handler_year;
case MYSQL_TYPE_BIT: return &type_handler_bit;
case MYSQL_TYPE_FLOAT: return &type_handler_float;
@@ -1893,11 +2129,11 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
switch (type) {
case MYSQL_TYPE_DECIMAL: return &type_handler_olddecimal;
case MYSQL_TYPE_NEWDECIMAL: return &type_handler_newdecimal;
- case MYSQL_TYPE_TINY: return &type_handler_tiny;
- case MYSQL_TYPE_SHORT: return &type_handler_short;
- case MYSQL_TYPE_LONG: return &type_handler_long;
- case MYSQL_TYPE_LONGLONG: return &type_handler_longlong;
- case MYSQL_TYPE_INT24: return &type_handler_int24;
+ case MYSQL_TYPE_TINY: return &type_handler_stiny;
+ case MYSQL_TYPE_SHORT: return &type_handler_sshort;
+ case MYSQL_TYPE_LONG: return &type_handler_slong;
+ case MYSQL_TYPE_LONGLONG: return &type_handler_slonglong;
+ case MYSQL_TYPE_INT24: return &type_handler_sint24;
case MYSQL_TYPE_YEAR: return &type_handler_year;
case MYSQL_TYPE_BIT: return &type_handler_bit;
case MYSQL_TYPE_FLOAT: return &type_handler_float;
@@ -1910,13 +2146,7 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
case MYSQL_TYPE_LONG_BLOB: return &type_handler_long_blob;
case MYSQL_TYPE_BLOB: return &type_handler_blob;
case MYSQL_TYPE_BLOB_COMPRESSED: return &type_handler_blob_compressed;
- case MYSQL_TYPE_VAR_STRING:
- /*
- VAR_STRING is actually a field_type(), not a real_type(),
- but it's used around the code in real_type() context.
- We should clean up the code and add DBUG_ASSERT(0) here.
- */
- return &type_handler_string;
+ case MYSQL_TYPE_VAR_STRING: return &type_handler_var_string;
case MYSQL_TYPE_STRING: return &type_handler_string;
case MYSQL_TYPE_ENUM: return &type_handler_enum;
case MYSQL_TYPE_SET: return &type_handler_set;
@@ -1935,8 +2165,7 @@ Type_handler::get_handler_by_real_type(enum_field_types type)
case MYSQL_TYPE_DATETIME2: return &type_handler_datetime2;
case MYSQL_TYPE_NEWDATE: return &type_handler_newdate;
};
- DBUG_ASSERT(0);
- return &type_handler_string;
+ return NULL;
}
@@ -2005,7 +2234,8 @@ Type_handler_int_result::make_num_distinct_aggregator_field(MEM_ROOT *mem_root,
/***********************************************************************/
-Field *Type_handler_tiny::make_conversion_table_field(TABLE *table,
+Field *Type_handler_tiny::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2016,84 +2246,91 @@ Field *Type_handler_tiny::make_conversion_table_field(TABLE *table,
using conversions so it should be true also when using conversions.
*/
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_tiny(NULL, 4 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_short::make_conversion_table_field(TABLE *table,
+Field *Type_handler_short::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_short(NULL, 6 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_int24::make_conversion_table_field(TABLE *table,
+Field *Type_handler_int24::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_medium(NULL, 9 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_long::make_conversion_table_field(TABLE *table,
+Field *Type_handler_long::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_long(NULL, 11 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_longlong::make_conversion_table_field(TABLE *table,
+Field *Type_handler_longlong::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
bool unsigned_flag= ((Field_num*) target)->unsigned_flag;
- return new (table->in_use->mem_root)
+ return new (root)
Field_longlong(NULL, 20 /*max_length*/,(uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*zerofill*/, unsigned_flag);
}
-Field *Type_handler_float::make_conversion_table_field(TABLE *table,
+Field *Type_handler_float::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_float(NULL, 12 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}
-Field *Type_handler_double::make_conversion_table_field(TABLE *table,
+Field *Type_handler_double::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_double(NULL, 22 /*max_length*/, (uchar *) "", 1, Field::NONE,
&empty_clex_str, 0/*dec*/, 0/*zerofill*/, 0/*unsigned_flag*/);
}
-Field *Type_handler_newdecimal::make_conversion_table_field(TABLE *table,
+Field *Type_handler_newdecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2102,13 +2339,14 @@ Field *Type_handler_newdecimal::make_conversion_table_field(TABLE *table,
uint8 decimals= metadata & 0x00ff;
uint32 max_length= my_decimal_precision_to_length(precision, decimals, false);
DBUG_ASSERT(decimals <= DECIMAL_MAX_SCALE);
- return new (table->in_use->mem_root)
+ return new (root)
Field_new_decimal(NULL, max_length, (uchar *) "", 1, Field::NONE,
&empty_clex_str, decimals, 0/*zerofill*/, 0/*unsigned*/);
}
-Field *Type_handler_olddecimal::make_conversion_table_field(TABLE *table,
+Field *Type_handler_olddecimal::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2125,153 +2363,169 @@ Field *Type_handler_olddecimal::make_conversion_table_field(TABLE *table,
}
-Field *Type_handler_year::make_conversion_table_field(TABLE *table,
+Field *Type_handler_year::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_year(NULL, 4, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_null::make_conversion_table_field(TABLE *table,
+Field *Type_handler_null::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_null(NULL, 0, Field::NONE, &empty_clex_str, target->charset());
}
-Field *Type_handler_timestamp::make_conversion_table_field(TABLE *table,
+Field *Type_handler_timestamp::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_timestamp(table->in_use->mem_root, NULL, (uchar *) "", 1,
- Field::NONE, &empty_clex_str, table->s, target->decimals());
+ return new_Field_timestamp(root, NULL, (uchar *) "", 1,
+ Field::NONE, &empty_clex_str,
+ table->s, target->decimals());
}
-Field *Type_handler_timestamp2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_timestamp2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_timestampf(NULL, (uchar *) "", 1, Field::NONE,
&empty_clex_str, table->s, metadata);
}
-Field *Type_handler_newdate::make_conversion_table_field(TABLE *table,
+Field *Type_handler_newdate::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_newdate(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_date::make_conversion_table_field(TABLE *table,
+Field *Type_handler_date::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_date(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str);
}
-Field *Type_handler_time::make_conversion_table_field(TABLE *table,
+Field *Type_handler_time::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_time(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ return new_Field_time(root, NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->decimals());
}
-Field *Type_handler_time2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_time2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_timef(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, metadata);
}
-Field *Type_handler_datetime::make_conversion_table_field(TABLE *table,
+Field *Type_handler_datetime::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new_Field_datetime(table->in_use->mem_root, NULL, (uchar *) "", 1,
+ return new_Field_datetime(root, NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->decimals());
}
-Field *Type_handler_datetime2::make_conversion_table_field(TABLE *table,
+Field *Type_handler_datetime2::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_datetimef(NULL, (uchar *) "", 1,
Field::NONE, &empty_clex_str, metadata);
}
-Field *Type_handler_bit::make_conversion_table_field(TABLE *table,
+Field *Type_handler_bit::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT((metadata & 0xff) <= 7);
uint32 max_length= 8 * (metadata >> 8U) + (metadata & 0x00ff);
- return new(table->in_use->mem_root)
+ return new(root)
Field_bit_as_char(NULL, max_length, (uchar *) "", 1,
Field::NONE, &empty_clex_str);
}
-Field *Type_handler_string::make_conversion_table_field(TABLE *table,
+Field *Type_handler_string::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
/* This is taken from Field_string::unpack. */
uint32 max_length= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff);
- return new(table->in_use->mem_root)
+ return new(root)
Field_string(NULL, max_length, (uchar *) "", 1,
Field::NONE, &empty_clex_str, target->charset());
}
-Field *Type_handler_varchar::make_conversion_table_field(TABLE *table,
+Field *Type_handler_varchar::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(metadata) <= MAX_FIELD_VARCHARLENGTH);
- return new(table->in_use->mem_root)
+ return new(root)
Field_varstring(NULL, metadata, HA_VARCHAR_PACKLENGTH(metadata),
(uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, target->charset());
}
-Field *Type_handler_varchar_compressed::make_conversion_table_field(TABLE *table,
+Field *Type_handler_varchar_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
- return new(table->in_use->mem_root)
+ return new(root)
Field_varstring_compressed(NULL, metadata,
HA_VARCHAR_PACKLENGTH(metadata),
(uchar *) "", 1, Field::NONE,
@@ -2282,7 +2536,9 @@ Field *Type_handler_varchar_compressed::make_conversion_table_field(TABLE *table
-Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
+Field *Type_handler_blob_compressed::make_conversion_table_field(
+ MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -2290,7 +2546,7 @@ Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
uint pack_length= metadata & 0x00ff;
if (pack_length < 1 || pack_length > 4)
return NULL; // Broken binary log?
- return new(table->in_use->mem_root)
+ return new(root)
Field_blob_compressed(NULL, (uchar *) "", 1, Field::NONE,
&empty_clex_str,
table->s, pack_length, target->charset(),
@@ -2298,43 +2554,15 @@ Field *Type_handler_blob_compressed::make_conversion_table_field(TABLE *table,
}
-#ifdef HAVE_SPATIAL
-const Name Type_handler_geometry::m_name_geometry(STRING_WITH_LEN("geometry"));
-
-
-const Type_handler *Type_handler_geometry::type_handler_for_comparison() const
-{
- return &type_handler_geometry;
-}
-
-
-Field *Type_handler_geometry::make_conversion_table_field(TABLE *table,
- uint metadata,
- const Field *target)
- const
-{
- DBUG_ASSERT(target->type() == MYSQL_TYPE_GEOMETRY);
- /*
- We do not do not update feature_gis statistics here:
- status_var_increment(target->table->in_use->status_var.feature_gis);
- as this is only a temporary field.
- The statistics was already incremented when "target" was created.
- */
- return new(table->in_use->mem_root)
- Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str, table->s, 4,
- ((const Field_geom*) target)->geom_type,
- ((const Field_geom*) target)->srid);
-}
-#endif
-
-Field *Type_handler_enum::make_conversion_table_field(TABLE *table,
+Field *Type_handler_enum::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
DBUG_ASSERT(target->real_type() == MYSQL_TYPE_ENUM);
- return new(table->in_use->mem_root)
+ return new(root)
Field_enum(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/,
@@ -2342,14 +2570,15 @@ Field *Type_handler_enum::make_conversion_table_field(TABLE *table,
}
-Field *Type_handler_set::make_conversion_table_field(TABLE *table,
+Field *Type_handler_set::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
{
DBUG_ASSERT(target->type() == MYSQL_TYPE_STRING);
DBUG_ASSERT(target->real_type() == MYSQL_TYPE_SET);
- return new(table->in_use->mem_root)
+ return new(root)
Field_set(NULL, target->field_length,
(uchar *) "", 1, Field::NONE, &empty_clex_str,
metadata & 0x00ff/*pack_length()*/,
@@ -2357,6 +2586,28 @@ Field *Type_handler_set::make_conversion_table_field(TABLE *table,
}
+Field *Type_handler_enum::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ const Typelib *typelib= def.typelib();
+ DBUG_ASSERT(typelib);
+ /*
+ Assume I_S columns don't have non-ASCII characters in names.
+ If we eventually want to, Typelib::max_char_length() must be implemented.
+ */
+ return new (root)
+ Field_enum(addr.ptr(), (uint32) typelib->max_octet_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ get_enum_pack_length(typelib->count),
+ typelib, system_charset_info);
+
+}
+
+
/*************************************************************************/
bool Type_handler::
@@ -2447,14 +2698,6 @@ bool Type_handler_blob_common::
return def->check_length(ER_TOO_BIG_DISPLAYWIDTH, MAX_FIELD_BLOBLENGTH);
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_fix_attributes(Column_definition *def) const
-{
- def->flags|= BLOB_FLAG;
- return false;
-}
-#endif
bool Type_handler_year::
Column_definition_fix_attributes(Column_definition *def) const
@@ -2547,18 +2790,6 @@ void Type_handler_typelib::
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::
- Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *def,
- const Field *field) const
-{
- def->geom_type= ((Field_geom*) field)->geom_type;
- def->srid= ((Field_geom*) field)->srid;
-}
-#endif
-
-
void Type_handler_year::
Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *def,
@@ -2668,20 +2899,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_prepare_stage1(THD *thd,
- MEM_ROOT *mem_root,
- Column_definition *def,
- handler *file,
- ulonglong table_flags) const
-{
- def->create_length_to_internal_length_string();
- return def->prepare_blob_field(thd);
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler::
@@ -2822,21 +3039,6 @@ bool Type_handler_blob_common::
return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_BLOB);
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_prepare_stage2(Column_definition *def,
- handler *file,
- ulonglong table_flags) const
-{
- if (!(table_flags & HA_CAN_GEOMETRY))
- {
- my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
- return true;
- }
- return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM);
-}
-#endif
-
bool Type_handler_varchar::
Column_definition_prepare_stage2(Column_definition *def,
handler *file,
@@ -2892,6 +3094,93 @@ bool Type_handler_bit::
return false;
}
+
+/*************************************************************************/
+bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_field_needed) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return false;
+}
+
+
+bool Type_handler::Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "SPATIAL INDEX");
+ return true;
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_primary_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ if (!(part->length*= def.charset->mbmaxlen))
+ *hash_field_needed= true;
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->init_multiple_key_for_blob(file);
+}
+
+
+bool Type_handler_blob_common::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length*= def.charset->mbmaxlen;
+ return part->check_foreign_key_for_blob(file);
+}
+
+
+
/*************************************************************************/
uint32 Type_handler_time::calc_pack_length(uint32 length) const
@@ -2950,13 +3239,6 @@ uint32 Type_handler_long_blob::calc_pack_length(uint32 length) const
return 4 + portable_sizeof_char_ptr;
}
-#ifdef HAVE_SPATIAL
-uint32 Type_handler_geometry::calc_pack_length(uint32 length) const
-{
- return 4 + portable_sizeof_char_ptr;
-}
-#endif
-
uint32 Type_handler_newdecimal::calc_pack_length(uint32 length) const
{
abort(); // This shouldn't happen
@@ -2977,49 +3259,56 @@ uint32 Type_handler_enum::calc_pack_length(uint32 length) const
/*************************************************************************/
-Field *Type_handler::make_and_init_table_field(const LEX_CSTRING *name,
+Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- Field *field= make_table_field(name, addr, attr, table);
+ Field *field= make_table_field(root, name, addr, attr, table);
if (field)
field->init(table);
return field;
}
-Field *Type_handler_tiny::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_tiny::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_tiny(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
-Field *Type_handler_short::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
+Field *Type_handler_short::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_short(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
-Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_int24::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_medium(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3027,24 +3316,28 @@ Field *Type_handler_int24::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_long::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_long::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_long(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, 0/*zerofill*/, attr.unsigned_flag);
}
-Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_longlong::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_longlong(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3052,12 +3345,14 @@ Field *Type_handler_longlong::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_vers_trx_id::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ DBUG_ASSERT(is_unsigned() == attr.unsigned_flag);
+ return new (root)
Field_vers_trx_id(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3065,12 +3360,13 @@ Field *Type_handler_vers_trx_id::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_float::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_float(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3078,12 +3374,13 @@ Field *Type_handler_float::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_double::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_double::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_double(addr.ptr(), attr.max_char_length(),
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3092,7 +3389,8 @@ Field *Type_handler_double::make_table_field(const LEX_CSTRING *name,
Field *
-Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
+Type_handler_olddecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3105,7 +3403,7 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
in make_field() in field.cc, to open old tables with old decimal.
*/
DBUG_ASSERT(0);
- return new (table->in_use->mem_root)
+ return new (root)
Field_decimal(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, (uint8) attr.decimals,
@@ -3114,7 +3412,8 @@ Type_handler_olddecimal::make_table_field(const LEX_CSTRING *name,
Field *
-Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
+Type_handler_newdecimal::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3153,50 +3452,54 @@ Type_handler_newdecimal::make_table_field(const LEX_CSTRING *name,
/* Corrected value fits. */
len= required_length;
}
- return new (table->in_use->mem_root)
+ return new (root)
Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
dec, 0/*zerofill*/, attr.unsigned_flag);
}
-Field *Type_handler_year::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_year::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_year(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_null::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_null::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_null(addr.ptr(), attr.max_length,
Field::NONE, name, attr.collation.collation);
}
-Field *Type_handler_timestamp::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_timestamp::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new_Field_timestamp(table->in_use->mem_root,
+ return new_Field_timestamp(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, attr.decimals);
}
-Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_timestamp2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3206,25 +3509,27 @@ Field *Type_handler_timestamp2::make_table_field(const LEX_CSTRING *name,
Will be changed to "new Field_timestampf" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_timestamp(table->in_use->mem_root,
+ return new_Field_timestamp(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s, attr.decimals);
}
-Field *Type_handler_newdate::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_newdate::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_date::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3235,25 +3540,27 @@ Field *Type_handler_date::make_table_field(const LEX_CSTRING *name,
for make_field() in field.cc
*/
DBUG_ASSERT(0);
- return new (table->in_use->mem_root)
+ return new (root)
Field_date(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_time::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_time::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new_Field_time(table->in_use->mem_root,
+ return new_Field_time(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_time2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3264,25 +3571,27 @@ Field *Type_handler_time2::make_table_field(const LEX_CSTRING *name,
Will be changed to "new Field_timef" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_time(table->in_use->mem_root,
+ return new_Field_time(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_datetime::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_datetime::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new_Field_datetime(table->in_use->mem_root,
+ return new_Field_datetime(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_datetime2::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3291,39 +3600,42 @@ Field *Type_handler_datetime2::make_table_field(const LEX_CSTRING *name,
Will be changed to "new Field_datetimef" when we reuse
make_table_field() for make_field() purposes in field.cc.
*/
- return new_Field_datetime(table->in_use->mem_root,
+ return new_Field_datetime(root,
addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.decimals);
}
-Field *Type_handler_bit::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_bit::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_bit_as_char(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name);
}
-Field *Type_handler_string::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_string::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_string(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name, attr.collation);
}
-Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_varchar::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
@@ -3331,7 +3643,7 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
{
DBUG_ASSERT(HA_VARCHAR_PACKLENGTH(attr.max_length) <=
MAX_FIELD_VARCHARLENGTH);
- return new (table->in_use->mem_root)
+ return new (root)
Field_varstring(addr.ptr(), attr.max_length,
HA_VARCHAR_PACKLENGTH(attr.max_length),
addr.null_ptr(), addr.null_bit(),
@@ -3340,26 +3652,28 @@ Field *Type_handler_varchar::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_tiny_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_tiny_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
1, attr.collation);
}
-Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
2, attr.collation);
@@ -3367,56 +3681,43 @@ Field *Type_handler_blob::make_table_field(const LEX_CSTRING *name,
Field *
-Type_handler_medium_blob::make_table_field(const LEX_CSTRING *name,
+Type_handler_medium_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
3, attr.collation);
}
-Field *Type_handler_long_blob::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_long_blob::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- return new (table->in_use->mem_root)
+ return new (root)
Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
Field::NONE, name, table->s,
4, attr.collation);
}
-
-#ifdef HAVE_SPATIAL
-Field *Type_handler_geometry::make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const
-{
- return new (table->in_use->mem_root)
- Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
- Field::NONE, name, table->s, 4,
- (Field::geometry_type) attr.uint_geometry_type(),
- 0);
-}
-#endif
-
-
-Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_enum::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- TYPELIB *typelib= attr.get_typelib();
+ const TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
- return new (table->in_use->mem_root)
+ return new (root)
Field_enum(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3425,15 +3726,16 @@ Field *Type_handler_enum::make_table_field(const LEX_CSTRING *name,
}
-Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
+Field *Type_handler_set::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const
{
- TYPELIB *typelib= attr.get_typelib();
+ const TYPELIB *typelib= attr.get_typelib();
DBUG_ASSERT(typelib);
- return new (table->in_use->mem_root)
+ return new (root)
Field_set(addr.ptr(), attr.max_length,
addr.null_ptr(), addr.null_bit(),
Field::NONE, name,
@@ -3441,6 +3743,198 @@ Field *Type_handler_set::make_table_field(const LEX_CSTRING *name,
attr.collation);
}
+
+/*************************************************************************/
+
+Field *Type_handler_float::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_float(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_double::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_double(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) NOT_FIXED_DEC,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_decimal_result::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ uint dec= def.decimal_scale();
+ uint prec= def.decimal_precision();
+ DBUG_ASSERT(dec <= DECIMAL_MAX_SCALE);
+ uint32 len= my_decimal_precision_to_length(prec, dec, def.unsigned_flag());
+ return new (root)
+ Field_new_decimal(addr.ptr(), len, addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ (uint8) dec, 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_blob_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ if (show_field)
+ {
+ return new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, table->s,
+ length_bytes(),
+ &my_charset_bin);
+ }
+ else
+ return new (root)
+ Field_null(addr.ptr(), 0, Field::NONE, &name, &my_charset_bin);
+}
+
+
+Field *Type_handler_varchar::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ DBUG_ASSERT(def.char_length());
+ LEX_CSTRING name= def.name();
+ uint32 octet_length= (uint32) def.char_length() * 3;
+ if (octet_length > MAX_FIELD_VARCHARLENGTH)
+ {
+ Field *field= new (root)
+ Field_blob(addr.ptr(), addr.null_ptr(), addr.null_bit(), Field::NONE,
+ &name, table->s, 4, system_charset_info);
+ if (field)
+ field->field_length= octet_length;
+ return field;
+ }
+ else if (show_field)
+ {
+ return new (root)
+ Field_varstring(addr.ptr(), octet_length,
+ HA_VARCHAR_PACKLENGTH(octet_length),
+ addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name,
+ table->s, system_charset_info);
+ }
+ else
+ return new (root)
+ Field_null(addr.ptr(), 0, Field::NONE, &name, system_charset_info);
+}
+
+
+Field *Type_handler_tiny::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_tiny(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_short::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_short(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_long::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_long(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_longlong::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_longlong(addr.ptr(), def.char_length(),
+ addr.null_ptr(), addr.null_bit(), Field::NONE, &name,
+ 0/*zerofill*/, def.unsigned_flag());
+}
+
+
+Field *Type_handler_date_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new (root)
+ Field_newdate(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name);
+}
+
+
+Field *Type_handler_time_common::make_schema_field(MEM_ROOT *root, TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new_Field_time(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
+Field *Type_handler_datetime_common::make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+{
+ LEX_CSTRING name= def.name();
+ return new_Field_datetime(root,
+ addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, &name, def.fsp());
+}
+
+
/*************************************************************************/
/*
@@ -3498,13 +3992,6 @@ uint32 Type_handler_bit::max_display_length(const Item *item) const
}
-uint32 Type_handler_general_purpose_int::max_display_length(const Item *item)
- const
-{
- return type_limits_int_by_unsigned_flag(item->unsigned_flag)->char_length();
-}
-
-
/*************************************************************************/
void Type_handler_row::Item_update_null_value(Item *item) const
@@ -3716,7 +4203,7 @@ bool Type_handler_string_result::
the query should return only the row with 'oe'.
It should not return 'o-umlaut', because 'o-umlaut' does not match
the right part of the condition: a='oe'
- ('o-umlaut' is not equal to 'oe' in utf8_general_ci,
+ ('o-umlaut' is not equal to 'oe' in utf8mb3_general_ci,
which is the collation of the field "a").
If we change the right part from:
@@ -3857,11 +4344,14 @@ bool Type_handler_int_result::
{
// Convert a mixture of signed and unsigned int to decimal
handler->set_handler(&type_handler_newdecimal);
- func->aggregate_attributes_decimal(items, nitems);
+ func->aggregate_attributes_decimal(items, nitems, false);
return false;
}
}
func->aggregate_attributes_int(items, nitems);
+ handler->set_handler(func->unsigned_flag ?
+ handler->type_handler()->type_handler_unsigned() :
+ handler->type_handler()->type_handler_signed());
return false;
}
@@ -3885,7 +4375,8 @@ bool Type_handler_decimal_result::
Type_all_attributes *func,
Item **items, uint nitems) const
{
- func->aggregate_attributes_decimal(items, nitems);
+ uint unsigned_count= func->count_unsigned(items, nitems);
+ func->aggregate_attributes_decimal(items, nitems, unsigned_count == nitems);
return false;
}
@@ -3913,10 +4404,10 @@ bool Type_handler_typelib::
Type_all_attributes *func,
Item **items, uint nitems) const
{
- TYPELIB *typelib= NULL;
+ const TYPELIB *typelib= NULL;
for (uint i= 0; i < nitems; i++)
{
- TYPELIB *typelib2;
+ const TYPELIB *typelib2;
if ((typelib2= items[i]->get_typelib()))
{
if (typelib)
@@ -3999,29 +4490,6 @@ bool Type_handler_timestamp_common::
return false;
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_hybrid_func_fix_attributes(THD *thd,
- const char *func_name,
- Type_handler_hybrid_field_type *handler,
- Type_all_attributes *func,
- Item **items, uint nitems) const
-{
- DBUG_ASSERT(nitems > 0);
- Type_geometry_attributes gattr(items[0]->type_handler(), items[0]);
- for (uint i= 1; i < nitems; i++)
- gattr.join(items[i]);
- func->set_geometry_type(gattr.get_geometry_type());
- func->collation.set(&my_charset_bin);
- func->unsigned_flag= false;
- func->decimals= 0;
- func->max_length= (uint32) UINT_MAX32;
- func->set_maybe_null(true);
- return false;
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler::
@@ -4156,7 +4624,15 @@ bool Type_handler_real_result::
bool Type_handler_int_result::
Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
{
- return func->fix_length_and_dec_numeric(&type_handler_longlong);
+ /*
+ "this" is equal func->args[0]->type_handler() here, e.g. for MIN()/MAX().
+ func->unsigned_flag is not reliably set yet.
+ It will be set by the call below (copied from args[0]).
+ */
+ const Type_handler *h= is_unsigned() ?
+ &type_handler_ulonglong :
+ &type_handler_slonglong;
+ return func->fix_length_and_dec_numeric(h);
}
@@ -4239,13 +4715,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
-{
- return Item_func_or_sum_illegal_param("sum");
-}
-#endif
/*************************************************************************/
@@ -4290,13 +4759,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
-{
- return Item_func_or_sum_illegal_param("avg");
-}
-#endif
/*************************************************************************/
@@ -4341,15 +4803,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
-
/*************************************************************************/
bool Type_handler_real_result::Item_val_bool(Item *item) const
@@ -5628,14 +6081,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_round_fix_length_and_dec(Item_func_round *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5686,14 +6131,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5744,14 +6181,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_row::
@@ -5802,15 +6231,6 @@ bool Type_handler_string_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-#endif
-
-
/***************************************************************************/
bool Type_handler::
@@ -5960,78 +6380,6 @@ bool Type_handler::
}
-#ifdef HAVE_SPATIAL
-
-bool Type_handler_geometry::
- Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
-{
- if (item->cast_charset() != &my_charset_bin)
- return Item_func_or_sum_illegal_param(item); // CAST(geom AS CHAR)
- item->fix_length_and_dec_str();
- return false; // CAST(geom AS BINARY)
-}
-
-
-bool Type_handler_geometry::
- Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-
-bool Type_handler_geometry::
- Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
-{
- return Item_func_or_sum_illegal_param(item);
-}
-
-
-bool Type_handler_geometry::
- Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
- const
-{
- return Item_func_or_sum_illegal_param(item);
-
-}
-
-#endif /* HAVE_SPATIAL */
-
/***************************************************************************/
bool Type_handler_row::
@@ -6650,21 +6998,6 @@ bool Type_handler_temporal_result::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Item_param_set_from_value(THD *thd,
- Item_param *param,
- const Type_all_attributes *attr,
- const st_value *val) const
-{
- param->unsigned_flag= false;
- param->setup_conversion_blob(thd);
- param->set_geometry_type(attr->uint_geometry_type());
- return param->set_str(val->m_string.ptr(), val->m_string.length(),
- &my_charset_bin, &my_charset_bin);
-}
-#endif
-
/***************************************************************************/
bool Type_handler_null::
@@ -6832,10 +7165,10 @@ Item *Type_handler_string_result::
String *result= item->val_str(&tmp);
if (item->null_value)
return new (thd->mem_root) Item_null(thd, item->name.str);
- uint length= result->length();
- char *tmp_str= thd->strmake(result->ptr(), length);
- return new (thd->mem_root) Item_string(thd, item->name.str,
- tmp_str, length, result->charset());
+ LEX_CSTRING value;
+ thd->make_lex_string(&value, result->ptr(), result->length());
+ return new (thd->mem_root) Item_string(thd, item->name, value,
+ result->charset());
}
@@ -7185,7 +7518,8 @@ void Type_handler_datetime_common::Item_param_set_param_func(Item_param *param,
param->set_param_datetime(pos, len);
}
-Field *Type_handler_blob_common::make_conversion_table_field(TABLE *table,
+Field *Type_handler_blob_common::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target)
const
@@ -7193,7 +7527,7 @@ Field *Type_handler_blob_common::make_conversion_table_field(TABLE *table,
uint pack_length= metadata & 0x00ff;
if (pack_length < 1 || pack_length > 4)
return NULL; // Broken binary log?
- return new(table->in_use->mem_root)
+ return new(root)
Field_blob(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
table->s, pack_length, target->charset());
}
@@ -7223,15 +7557,6 @@ void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
- uchar **pos,
- ulong len) const
-{
- param->set_null(); // Not possible type code in the client-server protocol
-}
-#endif
-
/***************************************************************************/
Field *Type_handler_row::
@@ -7555,21 +7880,6 @@ Field *Type_handler_bit::
}
-#ifdef HAVE_SPATIAL
-Field *Type_handler_geometry::
- make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
- const LEX_CSTRING *name,
- const Record_addr &rec, const Bit_addr &bit,
- const Column_definition_attributes *attr,
- uint32 flags) const
-{
- status_var_increment(current_thd->status_var.feature_gis);
- return new (mem_root)
- Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
- attr->unireg_check, name, share,
- attr->pack_flag_to_pack_length(), attr->geom_type, attr->srid);
-}
-#endif
Field *Type_handler_string::
@@ -7667,16 +7977,6 @@ void Type_handler::
}
-#ifdef HAVE_SPATIAL
-void Type_handler_geometry::
- Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
- uchar *buff) const
-{
- def->frm_pack_basic(buff);
- buff[11]= 0;
- buff[14]= (uchar) def->geom_type;
-}
-#endif
/***************************************************************************/
@@ -7693,29 +7993,6 @@ bool Type_handler::
}
-#ifdef HAVE_SPATIAL
-bool Type_handler_geometry::
- Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
- TABLE_SHARE *share,
- const uchar *buffer,
- LEX_CUSTRING *gis_options)
- const
-{
- uint gis_opt_read, gis_length, gis_decimals;
- Field_geom::storage_type st_type;
- attr->frm_unpack_basic(buffer);
- // charset and geometry_type share the same byte in frm
- attr->geom_type= (Field::geometry_type) buffer[14];
- gis_opt_read= gis_field_options_read(gis_options->str,
- gis_options->length,
- &st_type, &gis_length,
- &gis_decimals, &attr->srid);
- gis_options->str+= gis_opt_read;
- gis_options->length-= gis_opt_read;
- return false;
-}
-#endif
-
/***************************************************************************/
bool Type_handler::Vers_history_point_resolve_unit(THD *thd,
@@ -7854,14 +8131,14 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a,
const Type_handler *
Type_handler_hex_hybrid::cast_to_int_type_handler() const
{
- return &type_handler_longlong;
+ return &type_handler_ulonglong;
}
const Type_handler *
Type_handler_hex_hybrid::type_handler_for_system_time() const
{
- return &type_handler_longlong;
+ return &type_handler_ulonglong;
}
@@ -8268,6 +8545,91 @@ Type_handler_timestamp_common::Item_param_val_native(THD *thd,
}
+/***************************************************************************/
+
+bool Type_handler::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ DBUG_EXECUTE_IF("validate_implicit_default_value_error", return true;);
+ return false;
+}
+
+
+bool Type_handler_date_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+{
+ return thd->variables.sql_mode & MODE_NO_ZERO_DATE;
+}
+
+
+/***************************************************************************/
+
+const Name & Type_handler_row::default_value() const
+{
+ DBUG_ASSERT(0);
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_numeric::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0"));
+ return def;
+}
+
+const Name & Type_handler_string_result::default_value() const
+{
+ static Name def(STRING_WITH_LEN(""));
+ return def;
+}
+
+const Name & Type_handler_time_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_date_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00"));
+ return def;
+}
+
+const Name & Type_handler_datetime_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+const Name & Type_handler_timestamp_common::default_value() const
+{
+ static Name def(STRING_WITH_LEN("0000-00-00 00:00:00"));
+ return def;
+}
+
+/***************************************************************************/
+
+bool Type_handler::Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const
+{
+ // Have *some* columns write type info (let's use string fields as an example)
+ DBUG_EXECUTE_IF("frm_data_type_info_emulate",
+ if (cmp_type() == STRING_RESULT)
+ return to->append(name().lex_cstring()););
+ return false;
+}
+
+
+/***************************************************************************/
+
LEX_CSTRING Charset::collation_specific_name() const
{
/*
diff --git a/sql/sql_type.h b/sql/sql_type.h
index 18796f8c967..07cc9db4760 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -27,10 +27,14 @@
#include "sql_time.h"
#include "sql_type_real.h"
#include "compat56.h"
+C_MODE_START
+#include <ma_dyncol.h>
+C_MODE_END
class Field;
class Column_definition;
class Column_definition_attributes;
+class Key_part_spec;
class Item;
class Item_const;
class Item_literal;
@@ -69,6 +73,7 @@ class Item_func_div;
class Item_func_mod;
class cmp_item;
class in_vector;
+class Type_handler_data;
class Type_handler_hybrid_field_type;
class Sort_param;
class Arg_comparator;
@@ -81,6 +86,10 @@ struct TABLE;
struct SORT_FIELD_ATTR;
class Vers_history_point;
class Virtual_column_info;
+class Conv_source;
+class ST_FIELD_INFO;
+class Type_collection;
+class Create_func;
#define my_charset_numeric my_charset_latin1
@@ -110,6 +119,82 @@ enum scalar_comparison_op
};
+class Data_type_statistics
+{
+public:
+ uint m_uneven_bit_length;
+ uint m_fixed_string_total_length;
+ uint m_fixed_string_count;
+ uint m_variable_string_total_length;
+ uint m_variable_string_count;
+ uint m_blob_count;
+ Data_type_statistics()
+ :m_uneven_bit_length(0),
+ m_fixed_string_total_length(0),
+ m_fixed_string_count(0),
+ m_variable_string_total_length(0),
+ m_variable_string_count(0),
+ m_blob_count(0)
+ { }
+ uint string_count() const
+ {
+ return m_fixed_string_count + m_variable_string_count;
+ }
+ uint string_total_length() const
+ {
+ return m_fixed_string_total_length + m_variable_string_total_length;
+ }
+};
+
+
+class Typelib: public TYPELIB
+{
+public:
+ Typelib(uint count, const char **type_names, unsigned int *type_lengths)
+ {
+ TYPELIB::count= count;
+ TYPELIB::name= "";
+ TYPELIB::type_names= type_names;
+ TYPELIB::type_lengths= type_lengths;
+ }
+ uint max_octet_length() const
+ {
+ uint max_length= 0;
+ for (uint i= 0; i < TYPELIB::count; i++)
+ {
+ const uint length= TYPELIB::type_lengths[i];
+ set_if_bigger(max_length, length);
+ }
+ return max_length;
+ }
+};
+
+
+template<uint sz>
+class TypelibBuffer: public Typelib
+{
+ const char *m_type_names[sz + 1];
+ uint m_type_lengths[sz + 1];
+public:
+ TypelibBuffer(uint count, const LEX_CSTRING *values)
+ :Typelib(count, m_type_names, m_type_lengths)
+ {
+ DBUG_ASSERT(sz >= count);
+ for (uint i= 0; i < count; i++)
+ {
+ DBUG_ASSERT(values[i].str != NULL);
+ m_type_names[i]= values[i].str;
+ m_type_lengths[i]= (uint) values[i].length;
+ }
+ m_type_names[sz]= NullS; // End marker
+ m_type_lengths[sz]= 0; // End marker
+ }
+ TypelibBuffer(const LEX_CSTRING *values)
+ :TypelibBuffer(sz, values)
+ { }
+};
+
+
class Native: public Binary_string
{
public:
@@ -2622,9 +2707,7 @@ public:
{ }
void set(const DTCollation &dt)
{
- collation= dt.collation;
- derivation= dt.derivation;
- repertoire= dt.repertoire;
+ *this= dt;
}
void set(CHARSET_INFO *collation_arg, Derivation derivation_arg)
{
@@ -2640,12 +2723,6 @@ public:
derivation= derivation_arg;
repertoire= repertoire_arg;
}
- void set_numeric()
- {
- collation= &my_charset_numeric;
- derivation= DERIVATION_NUMERIC;
- repertoire= MY_REPERTOIRE_NUMERIC;
- }
void set(CHARSET_INFO *collation_arg)
{
collation= collation_arg;
@@ -2679,6 +2756,17 @@ public:
};
+class DTCollation_numeric: public DTCollation
+{
+public:
+ DTCollation_numeric()
+ :DTCollation(charset_info(), DERIVATION_NUMERIC, MY_REPERTOIRE_NUMERIC)
+ { }
+ static const CHARSET_INFO *charset_info() { return &my_charset_numeric; }
+ static const DTCollation & singleton();
+};
+
+
static inline uint32
char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg)
{
@@ -2686,38 +2774,87 @@ char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg)
return tmp > UINT_MAX32 ? (uint32) UINT_MAX32 : static_cast<uint32>(tmp);
}
-/**
- A class to store type attributes for the standard data types.
- Does not include attributes for the extended data types
- such as ENUM, SET, GEOMETRY.
-*/
-class Type_std_attributes
+
+class Type_numeric_attributes
{
public:
- DTCollation collation;
- uint decimals;
+ static uint count_unsigned(Item **item, uint nitems);
+ static uint32 find_max_char_length(Item **item, uint nitems);
+ static uint32 find_max_octet_length(Item **item, uint nitems);
+ static int find_max_decimal_int_part(Item **item, uint nitems);
+ static uint find_max_decimals(Item **item, uint nitems);
+public:
/*
The maximum value length in characters multiplied by collation->mbmaxlen.
Almost always it's the maximum value length in bytes.
*/
uint32 max_length;
+ uint decimals;
bool unsigned_flag;
- Type_std_attributes()
- :collation(&my_charset_bin, DERIVATION_COERCIBLE),
- decimals(0), max_length(0), unsigned_flag(false)
+public:
+ Type_numeric_attributes()
+ :max_length(0), decimals(0), unsigned_flag(false)
{ }
- Type_std_attributes(const Type_std_attributes *other)
- :collation(other->collation),
- decimals(other->decimals),
- max_length(other->max_length),
- unsigned_flag(other->unsigned_flag)
+ Type_numeric_attributes(uint32 max_length_arg, uint decimals_arg,
+ bool unsigned_flag_arg)
+ :max_length(max_length_arg),
+ decimals(decimals_arg),
+ unsigned_flag(unsigned_flag_arg)
{ }
- Type_std_attributes(uint32 max_length_arg, uint decimals_arg,
- bool unsigned_flag_arg, const DTCollation &dtc)
- :collation(dtc),
- decimals(decimals_arg),
- max_length(max_length_arg),
- unsigned_flag(unsigned_flag_arg)
+protected:
+ void aggregate_numeric_attributes_real(Item **item, uint nitems);
+ void aggregate_numeric_attributes_decimal(Item **item, uint nitems,
+ bool unsigned_arg);
+};
+
+
+
+class Type_temporal_attributes: public Type_numeric_attributes
+{
+public:
+ Type_temporal_attributes(uint int_part_length, uint dec, bool unsigned_arg)
+ :Type_numeric_attributes(int_part_length + (dec ? 1 : 0),
+ MY_MIN(dec, TIME_SECOND_PART_DIGITS),
+ unsigned_arg)
+ {
+ max_length+= decimals;
+ }
+};
+
+
+class Type_temporal_attributes_not_fixed_dec: public Type_numeric_attributes
+{
+public:
+ Type_temporal_attributes_not_fixed_dec(uint32 int_part_length, uint dec,
+ bool unsigned_flag)
+ :Type_numeric_attributes(int_part_length, dec, unsigned_flag)
+ {
+ if (decimals == NOT_FIXED_DEC)
+ max_length+= TIME_SECOND_PART_DIGITS + 1;
+ else if (decimals)
+ {
+ set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
+ max_length+= decimals + 1;
+ }
+ }
+};
+
+
+/**
+ A class to store type attributes for the standard data types.
+ Does not include attributes for the extended data types
+ such as ENUM, SET, GEOMETRY.
+*/
+class Type_std_attributes: public Type_numeric_attributes
+{
+public:
+ DTCollation collation;
+ Type_std_attributes()
+ :collation(&my_charset_bin, DERIVATION_COERCIBLE)
+ { }
+ Type_std_attributes(const Type_numeric_attributes &nattr,
+ const DTCollation &dtc)
+ :Type_numeric_attributes(nattr), collation(dtc)
{ }
void set(const Type_std_attributes *other)
{
@@ -2727,6 +2864,10 @@ public:
{
*this= other;
}
+ void set(const Type_numeric_attributes &nattr, const DTCollation &dtc)
+ {
+ *this= Type_std_attributes(nattr, dtc);
+ }
uint32 max_char_length() const
{ return max_length / collation.collation->mbmaxlen; }
void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs)
@@ -2739,41 +2880,11 @@ public:
max_length= char_to_byte_length_safe(max_char_length_arg,
collation.collation->mbmaxlen);
}
- void fix_char_length_temporal_not_fixed_dec(uint int_part_length, uint dec)
- {
- uint char_length= int_part_length;
- if ((decimals= dec))
- {
- if (decimals == NOT_FIXED_DEC)
- char_length+= TIME_SECOND_PART_DIGITS + 1;
- else
- {
- set_if_smaller(decimals, TIME_SECOND_PART_DIGITS);
- char_length+= decimals + 1;
- }
- }
- fix_char_length(char_length);
- }
- void fix_attributes_temporal_not_fixed_dec(uint int_part_length, uint dec)
- {
- collation.set_numeric();
- unsigned_flag= 0;
- fix_char_length_temporal_not_fixed_dec(int_part_length, dec);
- }
- void fix_attributes_time_not_fixed_dec(uint dec)
- {
- fix_attributes_temporal_not_fixed_dec(MIN_TIME_WIDTH, dec);
- }
- void fix_attributes_datetime_not_fixed_dec(uint dec)
- {
- fix_attributes_temporal_not_fixed_dec(MAX_DATETIME_WIDTH, dec);
- }
- void fix_attributes_temporal(uint int_part_length, uint dec)
+ void fix_attributes_temporal(uint32 int_part_length, uint dec)
{
- collation.set_numeric();
- unsigned_flag= 0;
- decimals= MY_MIN(dec, TIME_SECOND_PART_DIGITS);
- max_length= decimals + int_part_length + (dec ? 1 : 0);
+ *this= Type_std_attributes(
+ Type_temporal_attributes(int_part_length, dec, false),
+ DTCollation_numeric());
}
void fix_attributes_date()
{
@@ -2788,38 +2899,31 @@ public:
fix_attributes_temporal(MAX_DATETIME_WIDTH, dec);
}
- void count_only_length(Item **item, uint nitems);
- void count_octet_length(Item **item, uint nitems);
- void count_real_length(Item **item, uint nitems);
- void count_decimal_length(Item **item, uint nitems);
- bool count_string_length(const char *func_name, Item **item, uint nitems);
- uint count_max_decimals(Item **item, uint nitems);
-
void aggregate_attributes_int(Item **items, uint nitems)
{
- collation.set_numeric();
- count_only_length(items, nitems);
+ collation= DTCollation_numeric();
+ fix_char_length(find_max_char_length(items, nitems));
+ unsigned_flag= count_unsigned(items, nitems) > 0;
decimals= 0;
}
void aggregate_attributes_real(Item **items, uint nitems)
{
- collation.set_numeric();
- count_real_length(items, nitems);
+ collation= DTCollation_numeric();
+ aggregate_numeric_attributes_real(items, nitems);
}
- void aggregate_attributes_decimal(Item **items, uint nitems)
+ void aggregate_attributes_decimal(Item **items, uint nitems,
+ bool unsigned_arg)
{
- collation.set_numeric();
- count_decimal_length(items, nitems);
+ collation= DTCollation_numeric();
+ aggregate_numeric_attributes_decimal(items, nitems,
+ (unsigned_flag= unsigned_arg));
}
bool aggregate_attributes_string(const char *func_name,
- Item **item, uint nitems)
- {
- return count_string_length(func_name, item, nitems);
- }
+ Item **item, uint nitems);
void aggregate_attributes_temporal(uint int_part_length,
Item **item, uint nitems)
{
- fix_attributes_temporal(int_part_length, count_max_decimals(item, nitems));
+ fix_attributes_temporal(int_part_length, find_max_decimals(item, nitems));
}
bool agg_item_collations(DTCollation &c, const char *name,
@@ -2923,23 +3027,15 @@ public:
Type_all_attributes()
:Type_std_attributes()
{ }
- Type_all_attributes(const Type_all_attributes *other)
+ Type_all_attributes(const Type_all_attributes &other)
:Type_std_attributes(other)
{ }
virtual ~Type_all_attributes() {}
virtual void set_maybe_null(bool maybe_null_arg)= 0;
// Returns total number of decimal digits
virtual uint decimal_precision() const= 0;
- /*
- Field::geometry_type is not visible here.
- Let's use an "uint" wrapper for now. Later when we move Field_geom
- into a plugin, this method will be replaced to some generic
- datatype indepented method.
- */
- virtual uint uint_geometry_type() const= 0;
- virtual void set_geometry_type(uint type)= 0;
- virtual TYPELIB *get_typelib() const= 0;
- virtual void set_typelib(TYPELIB *typelib)= 0;
+ virtual const TYPELIB *get_typelib() const= 0;
+ virtual void set_typelib(const TYPELIB *typelib)= 0;
};
@@ -3000,6 +3096,13 @@ public:
}
const char *ptr() const { return LEX_CSTRING::str; }
uint length() const { return (uint) LEX_CSTRING::length; }
+ const LEX_CSTRING &lex_cstring() const { return *this; }
+ bool eq(const LEX_CSTRING &other) const
+ {
+ return !my_strnncoll(system_charset_info,
+ (const uchar *) LEX_CSTRING::str, LEX_CSTRING::length,
+ (const uchar *) other.str, other.length);
+ }
};
@@ -3174,11 +3277,14 @@ protected:
enum_field_types type)
const;
public:
+ static const Type_handler *handler_by_name(const LEX_CSTRING &name);
+ static const Type_handler *handler_by_name_or_error(const LEX_CSTRING &name);
static const Type_handler *odbc_literal_type_handler(const LEX_CSTRING *str);
static const Type_handler *blob_type_handler(uint max_octet_length);
static const Type_handler *string_type_handler(uint max_octet_length);
static const Type_handler *bit_and_int_mixture_handler(uint max_char_len);
- static const Type_handler *type_handler_long_or_longlong(uint max_char_len);
+ static const Type_handler *type_handler_long_or_longlong(uint max_char_len,
+ bool unsigned_flag);
/**
Return a string type handler for Item
If too_big_for_varchar() returns a BLOB variant, according to length.
@@ -3191,24 +3297,16 @@ public:
static const Type_handler *get_handler_by_field_type(enum_field_types type);
static const Type_handler *get_handler_by_real_type(enum_field_types type);
static const Type_handler *get_handler_by_cmp_type(Item_result type);
- static const Type_handler *get_handler_by_result_type(Item_result type)
- {
- /*
- As result_type() returns STRING_RESULT for temporal Items,
- type should never be equal to TIME_RESULT here.
- */
- DBUG_ASSERT(type != TIME_RESULT);
- return get_handler_by_cmp_type(type);
- }
+ virtual const Type_collection *type_collection() const;
static const
Type_handler *aggregate_for_result_traditional(const Type_handler *h1,
const Type_handler *h2);
- static const
- Type_handler *aggregate_for_num_op_traditional(const Type_handler *h1,
- const Type_handler *h2);
virtual const Name name() const= 0;
virtual const Name version() const { return m_version_default; }
+ virtual const Name &default_value() const= 0;
+ virtual uint32 flags() const { return 0; }
+ bool is_unsigned() const { return flags() & UNSIGNED_FLAG; }
virtual enum_field_types field_type() const= 0;
virtual enum_field_types real_field_type() const { return field_type(); }
/**
@@ -3230,7 +3328,7 @@ public:
*/
virtual enum_field_types traditional_merge_field_type() const
{
- DBUG_ASSERT(is_traditional_type());
+ DBUG_ASSERT(is_traditional_scalar_type());
return field_type();
}
virtual enum_field_types type_code_for_protocol() const
@@ -3240,6 +3338,8 @@ public:
virtual protocol_send_type_t protocol_send_type() const= 0;
virtual Item_result result_type() const= 0;
virtual Item_result cmp_type() const= 0;
+ virtual enum_dynamic_column_type
+ dyncol_type(const Type_all_attributes *attr) const= 0;
virtual enum_mysql_timestamp_type mysql_timestamp_type() const
{
return MYSQL_TIMESTAMP_ERROR;
@@ -3314,6 +3414,14 @@ public:
{
return this;
}
+ virtual const Type_handler *type_handler_unsigned() const
+ {
+ return this;
+ }
+ virtual const Type_handler *type_handler_signed() const
+ {
+ return this;
+ }
virtual int
stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const= 0;
virtual CHARSET_INFO *charset_for_protocol(const Item *item) const;
@@ -3327,13 +3435,10 @@ public:
}
virtual ~Type_handler() {}
/**
- Determines MariaDB traditional data types that always present
+ Determines MariaDB traditional scalar data types that always present
in the server.
*/
- virtual bool is_traditional_type() const
- {
- return true;
- }
+ bool is_traditional_scalar_type() const;
virtual bool is_scalar_type() const { return true; }
virtual bool can_return_int() const { return true; }
virtual bool can_return_decimal() const { return true; }
@@ -3386,9 +3491,12 @@ public:
This information is not available in the binary log, so
we assume that these fields are the same on the master and on the slave.
*/
- virtual Field *make_conversion_table_field(TABLE *TABLE,
+ virtual Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
const Field *target) const= 0;
+ virtual void show_binlog_type(const Conv_source &src, String *str) const;
+ virtual uint32 max_display_length_for_field(const Conv_source &src) const= 0;
/*
Performs the final data type validation for a UNION element,
after the regular "aggregation for result" was done.
@@ -3397,6 +3505,19 @@ public:
{
return false;
}
+ virtual uint Column_definition_gis_options_image(uchar *buff,
+ const Column_definition &def)
+ const
+ {
+ return 0;
+ }
+ virtual bool Column_definition_data_type_info_image(Binary_string *to,
+ const Column_definition &def)
+ const;
+ // Check if the implicit default value is Ok in the current sql_mode
+ virtual bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def)
+ const;
// Automatic upgrade, e.g. for ALTER TABLE t1 FORCE
virtual void Column_definition_implicit_upgrade(Column_definition *c) const
{ }
@@ -3445,14 +3566,45 @@ public:
virtual bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
ulonglong table_flags) const= 0;
- virtual Field *make_table_field(const LEX_CSTRING *name,
+ virtual bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const;
+ virtual bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const;
+ virtual bool Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def) const;
+ virtual bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const
+ {
+ return true; // Error
+ }
+ virtual Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const= 0;
- Field *make_and_init_table_field(const LEX_CSTRING *name,
+ Field *make_and_init_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
+ virtual Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const
+ {
+ DBUG_ASSERT(0);
+ return NULL;
+ }
virtual Field *
make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
@@ -3464,6 +3616,10 @@ public:
virtual void
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
uchar *buff) const;
+ virtual const Type_handler *type_handler_frm_unpack(const uchar *buffer) const
+ {
+ return this;
+ }
virtual bool
Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
TABLE_SHARE *share,
@@ -3561,6 +3717,10 @@ public:
Item *src,
const Item *cmp) const= 0;
virtual Item_cache *Item_get_cache(THD *thd, const Item *item) const= 0;
+ virtual Item *make_constructor_item(THD *thd, List<Item> *args) const
+ {
+ return NULL;
+ }
/**
A builder for literals with data type name prefix, e.g.:
TIME'00:00:00', DATE'2001-01-01', TIMESTAMP'2001-01-01 00:00:00'.
@@ -3590,7 +3750,6 @@ public:
virtual Item *create_typecast_item(THD *thd, Item *item,
const Type_cast_attributes &attr) const
{
- DBUG_ASSERT(0);
return NULL;
}
virtual Item_copy *create_item_copy(THD *thd, Item *item) const;
@@ -3751,64 +3910,81 @@ class Type_handler_row: public Type_handler
static const Name m_name_row;
public:
virtual ~Type_handler_row() {}
- const Name name() const { return m_name_row; }
- bool is_scalar_type() const { return false; }
- bool can_return_int() const { return false; }
- bool can_return_decimal() const { return false; }
- bool can_return_real() const { return false; }
- bool can_return_str() const { return false; }
- bool can_return_text() const { return false; }
- bool can_return_date() const { return false; }
- bool can_return_time() const { return false; }
- enum_field_types field_type() const
+ const Name name() const override { return m_name_row; }
+ const Name &default_value() const override;
+ bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def) const
+ override
+ {
+ DBUG_ASSERT(0);
+ return true;
+ }
+ const Type_collection *type_collection() const override;
+ bool is_scalar_type() const override { return false; }
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_str() const override { return false; }
+ bool can_return_text() const override { return false; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ enum_field_types field_type() const override
{
DBUG_ASSERT(0);
return MYSQL_TYPE_NULL;
};
- protocol_send_type_t protocol_send_type() const
+ protocol_send_type_t protocol_send_type() const override
{
DBUG_ASSERT(0);
return PROTOCOL_SEND_STRING;
}
- Item_result result_type() const
+ Item_result result_type() const override
{
return ROW_RESULT;
}
- Item_result cmp_type() const
+ Item_result cmp_type() const override
{
return ROW_RESULT;
}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ DBUG_ASSERT(0);
+ return DYN_COL_NULL;
+ }
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ const Item *outer) const override
{
DBUG_ASSERT(0);
return false;
}
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override
{
DBUG_ASSERT(0);
return NULL;
}
- Field *make_conversion_table_field(TABLE *TABLE,
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
uint metadata,
- const Field *target) const
+ const Field *target) const override
{
DBUG_ASSERT(0);
return NULL;
}
- bool Column_definition_fix_attributes(Column_definition *c) const
+ bool Column_definition_fix_attributes(Column_definition *c) const override
{
return false;
}
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const
+ const Field *field)
+ const override
{
DBUG_ASSERT(0);
}
@@ -3816,26 +3992,27 @@ public:
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const
+ const override
{
DBUG_ASSERT(0);
return true;
}
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return false;
}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const
+ TABLE *table) const override
{
DBUG_ASSERT(0);
return NULL;
@@ -3846,145 +4023,155 @@ public:
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void make_sort_key(uchar *to, Item *item,
const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const
+ Sort_param *param) const override
{
DBUG_ASSERT(0);
}
void sortlength(THD *thd, const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const
+ SORT_FIELD_ATTR *attr) const override
{
DBUG_ASSERT(0);
}
- uint32 max_display_length(const Item *item) const
+ uint32 max_display_length(const Item *item) const override
+ {
+ DBUG_ASSERT(0);
+ return 0;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
{
DBUG_ASSERT(0);
return 0;
}
- uint32 calc_pack_length(uint32 length) const
+ uint32 calc_pack_length(uint32 length) const override
{
DBUG_ASSERT(0);
return 0;
}
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_decimal_precision(const Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_decimal_precision(const Item *item) const override
{
DBUG_ASSERT(0);
return DECIMAL_MAX_PRECISION;
}
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
DBUG_ASSERT(0);
return true;
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override
{
DBUG_ASSERT(0);
return 1;
}
- String *print_item_value(THD *thd, Item *item, String *str) const;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const
+ Item *source_expr, Item *source_const)
+ const override
{
DBUG_ASSERT(0);
return false;
}
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- Item_copy *create_item_copy(THD *thd, Item *item) const
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ Item_copy *create_item_copy(THD *thd, Item *item) const override
{
DBUG_ASSERT(0);
return NULL;
}
- bool set_comparator_func(Arg_comparator *cmp) const;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const
+ Item **items, uint nitems)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_val_bool(Item *item) const
+ bool Item_val_bool(Item *item) const override
{
DBUG_ASSERT(0);
return false;
}
void Item_get_date(THD *thd, Item *item,
Temporal::Warn *warn, MYSQL_TIME *ltime,
- date_mode_t fuzzydate) const
+ date_mode_t fuzzydate) const override
{
DBUG_ASSERT(0);
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
- longlong Item_val_int_signed_typecast(Item *item) const
+ longlong Item_val_int_signed_typecast(Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
- longlong Item_val_int_unsigned_typecast(Item *item) const
+ longlong Item_val_int_unsigned_typecast(Item *item) const override
{
DBUG_ASSERT(0);
return 0;
}
- String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override
{
DBUG_ASSERT(0);
return NULL;
}
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const
+ String *) const override
{
DBUG_ASSERT(0);
return NULL;
}
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const
+ const override
{
DBUG_ASSERT(0);
return 0.0;
}
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const
+ const override
{
DBUG_ASSERT(0);
return 0;
}
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const
+ my_decimal *) const override
{
DBUG_ASSERT(0);
return NULL;
@@ -3993,105 +4180,116 @@ public:
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *ltime,
- date_mode_t fuzzydate) const
+ date_mode_t fuzzydate)
+ const override
{
DBUG_ASSERT(0);
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
}
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override
{
DBUG_ASSERT(0);
return NULL;
}
- double Item_func_min_max_val_real(Item_func_min_max *) const
+ double Item_func_min_max_val_real(Item_func_min_max *) const override
{
DBUG_ASSERT(0);
return 0;
}
- longlong Item_func_min_max_val_int(Item_func_min_max *) const
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override
{
DBUG_ASSERT(0);
return 0;
}
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const
+ my_decimal *) const override
{
DBUG_ASSERT(0);
return NULL;
}
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_between_fix_length_and_dec(Item_func_between *func) const
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- longlong Item_func_between_val_int(Item_func_between *func) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs)
+ const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
- bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
+ bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
+ bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
+ bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
+ bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
+ bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const
+ bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
+ const override
{
DBUG_ASSERT(0);
return true;
}
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
@@ -4101,20 +4299,23 @@ public:
class Type_handler_numeric: public Type_handler
{
public:
- String *print_item_value(THD *thd, Item *item, String *str) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ const Name &default_value() const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
virtual ~Type_handler_numeric() { }
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const;
- bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
+ Item *source_expr, Item *source_const)
+ const override;
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const override;
};
@@ -4123,81 +4324,98 @@ public:
class Type_handler_real_result: public Type_handler_numeric
{
public:
- Item_result result_type() const { return REAL_RESULT; }
- Item_result cmp_type() const { return REAL_RESULT; }
+ Item_result result_type() const override{ return REAL_RESULT; }
+ Item_result cmp_type() const override { return REAL_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DOUBLE;
+ }
virtual ~Type_handler_real_result() {}
- const Type_handler *type_handler_for_comparison() const;
+ const Type_handler *type_handler_for_comparison() const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ const Field *field)
+ const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
+ const Item *outer)
+ const override;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
+ Sort_param *param) const override;
void sortlength(THD *thd,
const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
+ SORT_FIELD_ATTR *attr) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_decimal_precision(const Item *item) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
+ Item *a, Item *b) const override;
+ uint Item_decimal_precision(const Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ const st_value *value) const override;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func,
- Item **items, uint nitems) const;
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
- bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
- bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
- bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
- bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
- bool Item_val_bool(Item *item) const;
+ Item **items, uint nitems)
+ const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *item)
+ const override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item)
+ const override;
+ bool Item_val_bool(Item *item) const override;
void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
- MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
- longlong Item_val_int_signed_typecast(Item *item) const;
- longlong Item_val_int_unsigned_typecast(Item *item) const;
- String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str)
+ const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- date_mode_t fuzzydate) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
-
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ date_mode_t fuzzydate)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
@@ -4210,6 +4428,10 @@ public:
}
Item_result result_type() const { return DECIMAL_RESULT; }
Item_result cmp_type() const { return DECIMAL_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const
+ {
+ return DYN_COL_DECIMAL;
+ }
virtual ~Type_handler_decimal_result() {};
const Type_handler *type_handler_for_comparison() const;
int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
@@ -4219,6 +4441,11 @@ public:
}
bool subquery_type_allows_materialization(const Item *inner,
const Item *outer) const;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const;
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
Sort_param *param) const;
@@ -4436,6 +4663,10 @@ class Type_handler_int_result: public Type_handler_numeric
public:
Item_result result_type() const { return INT_RESULT; }
Item_result cmp_type() const { return INT_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) const
+ {
+ return attr->unsigned_flag ? DYN_COL_UINT : DYN_COL_INT;
+ }
bool is_order_clause_position_type() const { return true; }
bool is_limit_clause_valid_type() const { return true; }
virtual ~Type_handler_int_result() {}
@@ -4516,9 +4747,11 @@ class Type_handler_general_purpose_int: public Type_handler_int_result
{
public:
bool type_can_have_auto_increment_attribute() const { return true; }
- virtual const Type_limits_int *
- type_limits_int_by_unsigned_flag(bool unsigned_flag) const= 0;
- uint32 max_display_length(const Item *item) const;
+ virtual const Type_limits_int *type_limits_int() const= 0;
+ uint32 max_display_length(const Item *item) const
+ {
+ return type_limits_int()->char_length();
+ }
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@@ -4598,130 +4831,150 @@ class Type_handler_string_result: public Type_handler
{
uint Item_temporal_precision(THD *thd, Item *item, bool is_time) const;
public:
- protocol_send_type_t protocol_send_type() const
+ const Name &default_value() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_STRING;
}
- Item_result result_type() const { return STRING_RESULT; }
- Item_result cmp_type() const { return STRING_RESULT; }
- CHARSET_INFO *charset_for_protocol(const Item *item) const;
+ Item_result result_type() const override { return STRING_RESULT; }
+ Item_result cmp_type() const override { return STRING_RESULT; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *) const
+ override
+ {
+ return DYN_COL_STRING;
+ }
+ CHARSET_INFO *charset_for_protocol(const Item *item) const override;
virtual ~Type_handler_string_result() {}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const
+ override;
const Type_handler *
type_handler_adjusted_to_max_octet_length(uint max_octet_length,
- CHARSET_INFO *cs) const;
+ CHARSET_INFO *cs) const override;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
+ Sort_param *param) const override;
void sortlength(THD *thd,
const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
- bool union_element_finalize(const Item * item) const;
+ SORT_FIELD_ATTR *attr) const override;
+ bool union_element_finalize(const Item * item) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
- uint32 max_display_length(const Item *item) const;
+ const override;
+ uint32 max_display_length(const Item *item) const override;
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
+ bool binary_cmp) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_time_precision(THD *thd, Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_time_precision(THD *thd, Item *item) const override
{
return Item_temporal_precision(thd, item, true);
}
- uint Item_datetime_precision(THD *thd, Item *item) const
+ uint Item_datetime_precision(THD *thd, Item *item) const override
{
return Item_temporal_precision(thd, item, false);
}
- uint Item_decimal_precision(const Item *item) const;
- void Item_update_null_value(Item *item) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
- void Item_param_setup_conversion(THD *thd, Item_param *) const;
+ uint Item_decimal_precision(const Item *item) const override;
+ void Item_update_null_value(Item *item) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
bool Item_param_set_from_value(THD *thd,
Item_param *param,
const Type_all_attributes *attr,
- const st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_str(item, protocol, buf);
}
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions) const
+ override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override
{
return print_item_value_csstr(thd, item, str);
}
bool can_change_cond_ref_to_const(Item_bool_func2 *target,
Item *target_expr, Item *target_value,
Item_bool_func2 *source,
- Item *source_expr, Item *source_const) const;
+ Item *source_expr, Item *source_const) const
+ override;
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ const Item *outer) const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
+ override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const;
- bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
- bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
- bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
- bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const;
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const;
- bool Item_val_bool(Item *item) const;
+ Item **items, uint nitems) const
+ override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+ override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+ override;
+ bool Item_val_bool(Item *item) const override;
void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
- MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
- longlong Item_val_int_signed_typecast(Item *item) const;
- longlong Item_val_int_unsigned_typecast(Item *item) const;
- String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
+ longlong Item_val_int_signed_typecast(Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
+ String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) const
+ override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- date_mode_t fuzzydate) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ date_mode_t fuzzydate)
+ const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
+ override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
- bool Item_func_between_fix_length_and_dec(Item_func_between *func) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- bool Item_func_in_fix_comparator_compatible_types(THD *thd,
- Item_func_in *) const;
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const;
- bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const;
- bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
- bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
- bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
+ MYSQL_TIME *, date_mode_t fuzzydate) const
+ override;
+ bool Item_func_between_fix_length_and_dec(Item_func_between *func) const
+ override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const
+ override;
+ bool Item_func_in_fix_comparator_compatible_types(THD *thd, Item_func_in *)
+ const override;
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
+ bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
+ bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
+ bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
+ bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
};
@@ -4756,135 +5009,180 @@ public:
class Type_handler_tiny: public Type_handler_general_purpose_int
{
static const Name m_name_tiny;
- static const Type_limits_int m_limits_sint8;
- static const Type_limits_int m_limits_uint8;
public:
virtual ~Type_handler_tiny() {}
- const Name name() const { return m_name_tiny; }
- enum_field_types field_type() const { return MYSQL_TYPE_TINY; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_tiny; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_TINY; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_TINY;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint8 : &m_limits_sint8;
- }
- uint32 calc_pack_length(uint32 length) const { return 1; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_limits_int *type_limits_int() const override;
+ uint32 calc_pack_length(uint32 length) const override { return 1; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 4; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_tiny(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TINY); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_utiny: public Type_handler_tiny
+{
+public:
+ const Name name() const override;
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_short: public Type_handler_general_purpose_int
{
static const Name m_name_short;
- static const Type_limits_int m_limits_sint16;
- static const Type_limits_int m_limits_uint16;
public:
virtual ~Type_handler_short() {}
- const Name name() const { return m_name_short; }
- enum_field_types field_type() const { return MYSQL_TYPE_SHORT; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_short; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_SHORT; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_SHORT;
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_short(item, protocol, buf);
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint16 : &m_limits_sint16;
- }
- uint32 calc_pack_length(uint32 length) const { return 2; }
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 6; }
+ uint32 calc_pack_length(uint32 length) const override{ return 2; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_SHORT); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_ushort: public Type_handler_short
+{
+public:
+ const Name name() const override;
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
class Type_handler_long: public Type_handler_general_purpose_int
{
static const Name m_name_int;
- static const Type_limits_int m_limits_sint32;
- static const Type_limits_int m_limits_uint32;
public:
virtual ~Type_handler_long() {}
- const Name name() const { return m_name_int; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONG; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_int; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_LONG; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONG;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint32 : &m_limits_sint32;
- }
- uint32 calc_pack_length(uint32 length) const { return 4; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 11; }
+ uint32 calc_pack_length(uint32 length) const override { return 4; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_long(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONG); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
+};
+
+
+class Type_handler_ulong: public Type_handler_long
+{
+public:
+ const Name name() const override;
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
@@ -4892,113 +5190,141 @@ class Type_handler_bool: public Type_handler_long
{
static const Name m_name_bool;
public:
- const Name name() const { return m_name_bool; }
- bool is_bool_type() const { return true; }
- void Item_update_null_value(Item *item) const;
- bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const;
+ const Name name() const override { return m_name_bool; }
+ bool is_bool_type() const override { return true; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ void Item_update_null_value(Item *item) const override;
+ bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override;
};
class Type_handler_longlong: public Type_handler_general_purpose_int
{
static const Name m_name_longlong;
- static const Type_limits_int m_limits_sint64;
- static const Type_limits_int m_limits_uint64;
public:
virtual ~Type_handler_longlong() {}
- const Name name() const { return m_name_longlong; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override{ return m_name_longlong; }
+ enum_field_types field_type() const override{ return MYSQL_TYPE_LONGLONG; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONGLONG;
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint64 : &m_limits_sint64;
- }
- uint32 calc_pack_length(uint32 length) const { return 8; }
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 20; }
+ uint32 calc_pack_length(uint32 length) const override { return 8; }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_longlong(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *TABLE, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_LONGLONG);
}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
};
-class Type_handler_vers_trx_id: public Type_handler_longlong
+class Type_handler_ulonglong: public Type_handler_longlong
+{
+public:
+ const Name name() const override;
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
+};
+
+
+class Type_handler_vers_trx_id: public Type_handler_ulonglong
{
public:
virtual ~Type_handler_vers_trx_id() {}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
};
class Type_handler_int24: public Type_handler_general_purpose_int
{
static const Name m_name_mediumint;
- static const Type_limits_int m_limits_sint24;
- static const Type_limits_int m_limits_uint24;
public:
virtual ~Type_handler_int24() {}
- const Name name() const { return m_name_mediumint; }
- enum_field_types field_type() const { return MYSQL_TYPE_INT24; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_mediumint; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_INT24; }
+ const Type_handler *type_handler_unsigned() const override;
+ const Type_handler *type_handler_signed() const override;
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_LONG;
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_long(item, protocol, buf);
}
- const Type_limits_int *type_limits_int_by_unsigned_flag(bool unsigned_fl) const
- {
- return unsigned_fl ? &m_limits_uint24 : &m_limits_sint24;
- }
- uint32 calc_pack_length(uint32 length) const { return 3; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Type_limits_int *type_limits_int() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 9; }
+ uint32 calc_pack_length(uint32 length) const override { return 3; }
+ Field *make_conversion_table_field(MEM_ROOT *mem_root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_INT24); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
+};
+
+
+class Type_handler_uint24: public Type_handler_int24
+{
+public:
+ const Name name() const override;
+ uint flags() const override { return UNSIGNED_FLAG; }
+ const Type_limits_int *type_limits_int() const override;
};
@@ -5007,47 +5333,53 @@ class Type_handler_year: public Type_handler_int_result
static const Name m_name_year;
public:
virtual ~Type_handler_year() {}
- const Name name() const { return m_name_year; }
- enum_field_types field_type() const { return MYSQL_TYPE_YEAR; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_year; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_YEAR; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_SHORT;
}
- uint32 max_display_length(const Item *item) const;
- uint32 calc_pack_length(uint32 length) const { return 1; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ uint32 max_display_length(const Item *item) const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 4; }
+ uint32 calc_pack_length(uint32 length) const override { return 1; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_short(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
+ const Field *field)
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_YEAR); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ uint32 flags) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
void Item_get_date(THD *thd, Item *item, Temporal::Warn *warn,
- MYSQL_TIME *ltime, date_mode_t fuzzydate) const;
+ MYSQL_TIME *ltime, date_mode_t fuzzydate) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *item,
Temporal::Warn *,
MYSQL_TIME *to,
- date_mode_t fuzzydate) const;
+ date_mode_t fuzzydate)
+ const override;
};
@@ -5056,50 +5388,55 @@ class Type_handler_bit: public Type_handler_int_result
static const Name m_name_bit;
public:
virtual ~Type_handler_bit() {}
- const Name name() const { return m_name_bit; }
- enum_field_types field_type() const { return MYSQL_TYPE_BIT; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_bit; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_BIT; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_STRING;
}
- uint32 max_display_length(const Item *item) const;
- uint32 calc_pack_length(uint32 length) const { return length / 8; }
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ uint32 max_display_length(const Item *item) const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length / 8; }
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_str(item, protocol, buf);
}
- String *print_item_value(THD *thd, Item *item, String *str) const
+ String *print_item_value(THD *thd, Item *item, String *str) const override
{
return print_item_value_csstr(thd, item, str);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ uint32 flags) const override;
+ bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p)
+ const override;
};
@@ -5108,47 +5445,58 @@ class Type_handler_float: public Type_handler_real_result
static const Name m_name_float;
public:
virtual ~Type_handler_float() {}
- const Name name() const { return m_name_float; }
- enum_field_types field_type() const { return MYSQL_TYPE_FLOAT; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_float; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_FLOAT; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_FLOAT;
}
- bool type_can_have_auto_increment_attribute() const { return true; }
- uint32 max_display_length(const Item *item) const { return 25; }
- uint32 calc_pack_length(uint32 length) const { return sizeof(float); }
+ bool type_can_have_auto_increment_attribute() const override { return true; }
+ uint32 max_display_length(const Item *item) const override { return 25; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 12; }
+ uint32 calc_pack_length(uint32 length) const override { return sizeof(float); }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_float(item, protocol, buf);
}
- Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *)
+ const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_FLOAT); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ String *) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *)
+ const override;
};
@@ -5157,46 +5505,59 @@ class Type_handler_double: public Type_handler_real_result
static const Name m_name_double;
public:
virtual ~Type_handler_double() {}
- const Name name() const { return m_name_double; }
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_double; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_DOUBLE; }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DOUBLE;
}
- bool type_can_have_auto_increment_attribute() const { return true; }
- uint32 max_display_length(const Item *item) const { return 53; }
- uint32 calc_pack_length(uint32 length) const { return sizeof(double); }
+ bool type_can_have_auto_increment_attribute() const override { return true; }
+ uint32 max_display_length(const Item *item) const override { return 53; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 22; }
+ uint32 calc_pack_length(uint32 length) const override
+ {
+ return sizeof(double);
+ }
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_cast_attributes &attr) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_double(item, protocol, buf);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_real(c, MYSQL_TYPE_DOUBLE); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
+ String *) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *)
+ const override;
};
@@ -5205,78 +5566,98 @@ class Type_handler_time_common: public Type_handler_temporal_result
static const Name m_name_time;
public:
virtual ~Type_handler_time_common() { }
- const Name name() const { return m_name_time; }
- enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_time; }
+ const Name &default_value() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_TIME; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_TIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_TIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_TIME;
}
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
+ const Type_cast_attributes &attr)
+ const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- uint Item_decimal_scale(const Item *item) const
+ Item *a, Item *b) const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- const Type_handler *type_handler_for_comparison() const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
- void Column_definition_implicit_upgrade(Column_definition *c) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ const Type_handler *type_handler_for_comparison() const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_time(item, protocol, buf);
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- longlong Item_val_int_unsigned_typecast(Item *item) const;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ longlong Item_val_int_unsigned_typecast(Item *item) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
- String *) const;
+ String *) const override;
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
- const;
+ const override;
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
- const;
+ const override;
my_decimal *Item_func_hybrid_field_type_val_decimal(
Item_func_hybrid_field_type *,
- my_decimal *) const;
+ my_decimal *) const override;
void Item_func_hybrid_field_type_get_date(THD *,
Item_func_hybrid_field_type *,
Temporal::Warn *,
MYSQL_TIME *,
- date_mode_t fuzzydate) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ date_mode_t fuzzydate)
+ const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len)
+ const override;
};
@@ -5287,25 +5668,29 @@ class Type_handler_time: public Type_handler_time_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_time() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mariadb53; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MIN_TIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5313,26 +5698,29 @@ class Type_handler_time2: public Type_handler_time_common
{
public:
virtual ~Type_handler_time2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_TIME2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mysql56; }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_TIME2; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_TIME2); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5341,22 +5729,28 @@ class Type_handler_temporal_with_date: public Type_handler_temporal_result
public:
virtual ~Type_handler_temporal_with_date() {}
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ Item *a, Item *b) const override;
+ int stored_field_cmp_to_item(THD *thd, Field *field, Item *item)
+ const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value)
+ const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_date(item, protocol, buf);
}
- void Item_update_null_value(Item *item) const;
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
+ void Item_update_null_value(Item *item) const override;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp)
+ const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *, const Item_func_in *, uint nargs)
+ const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
};
@@ -5365,65 +5759,86 @@ class Type_handler_date_common: public Type_handler_temporal_with_date
static const Name m_name_date;
public:
virtual ~Type_handler_date_common() {}
- const Name name() const { return m_name_date; }
- const Type_handler *type_handler_for_comparison() const;
- enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_date; }
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_DATE; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return 3; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATE;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATE;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATE;
}
- bool cond_notnull_field_isnull_to_field_eq_zero() const
+ bool cond_notnull_field_isnull_to_field_eq_zero() const override
{
return true;
}
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item_literal *create_literal_item(THD *thd, const char *str, size_t length,
- CHARSET_INFO *cs, bool send_error) const;
+ CHARSET_INFO *cs, bool send_error)
+ const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_precision(const Item *item) const;
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ const Type_cast_attributes &attr)
+ const override;
+ bool validate_implicit_default_value(THD *thd,
+ const Column_definition &def)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ uint Item_decimal_precision(const Item *item) const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ my_decimal *) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
};
class Type_handler_date: public Type_handler_date_common
{
public:
virtual ~Type_handler_date() {}
- uint32 calc_pack_length(uint32 length) const { return 4; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ uint32 calc_pack_length(uint32 length) const override { return 4; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATE); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5431,25 +5846,30 @@ class Type_handler_newdate: public Type_handler_date_common
{
public:
virtual ~Type_handler_newdate() {}
- enum_field_types real_field_type() const { return MYSQL_TYPE_NEWDATE; }
- uint32 calc_pack_length(uint32 length) const { return 3; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_NEWDATE;
+ }
+ uint32 calc_pack_length(uint32 length) const override { return 3; }
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NEWDATE); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5458,52 +5878,69 @@ class Type_handler_datetime_common: public Type_handler_temporal_with_date
static const Name m_name_datetime;
public:
virtual ~Type_handler_datetime_common() {}
- const Name name() const { return m_name_datetime; }
- const Type_handler *type_handler_for_comparison() const;
- enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_datetime; }
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ enum_field_types field_type() const override
+ {
+ return MYSQL_TYPE_DATETIME;
+ }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATETIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATETIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATETIME;
}
- bool cond_notnull_field_isnull_to_field_eq_zero() const
+ bool cond_notnull_field_isnull_to_field_eq_zero() const override
{
return true;
}
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- void Column_definition_implicit_upgrade(Column_definition *c) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_scale(const Item *item) const
+ const Type_cast_attributes &attr) const override;
+ bool validate_implicit_default_value(THD *thd, const Column_definition &def)
+ const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_datetime(item, protocol, buf);
}
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
- my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
+ my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, my_decimal *)
+ const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ Item **items, uint nitems)
+ const override;
+ void Item_param_set_param_func(Item_param *param, uchar **pos, ulong len)
+ const override;
};
@@ -5514,25 +5951,29 @@ class Type_handler_datetime: public Type_handler_datetime_common
public:
static uint hires_bytes(uint dec) { return m_hires_bytes[dec]; }
virtual ~Type_handler_datetime() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mariadb53; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MAX_DATETIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5540,26 +5981,32 @@ class Type_handler_datetime2: public Type_handler_datetime_common
{
public:
virtual ~Type_handler_datetime2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_DATETIME2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mysql56; }
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_DATETIME2;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_DATETIME2); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5570,70 +6017,83 @@ protected:
bool TIME_to_native(THD *, const MYSQL_TIME *from, Native *to, uint dec) const;
public:
virtual ~Type_handler_timestamp_common() {}
- const Name name() const { return m_name_timestamp; }
- const Type_handler *type_handler_for_comparison() const;
- const Type_handler *type_handler_for_native_format() const;
- enum_field_types field_type() const { return MYSQL_TYPE_TIMESTAMP; }
- protocol_send_type_t protocol_send_type() const
+ const Name name() const override { return m_name_timestamp; }
+ const Name &default_value() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ const Type_handler *type_handler_for_native_format() const override;
+ enum_field_types field_type() const override { return MYSQL_TYPE_TIMESTAMP; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_DATETIME;
+ }
+ protocol_send_type_t protocol_send_type() const override
{
return PROTOCOL_SEND_DATETIME;
}
- enum_mysql_timestamp_type mysql_timestamp_type() const
+ enum_mysql_timestamp_type mysql_timestamp_type() const override
{
return MYSQL_TIMESTAMP_DATETIME;
}
- bool is_timestamp_type() const
+ bool is_timestamp_type() const override
{
return true;
}
- void Column_definition_implicit_upgrade(Column_definition *c) const;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
- Item *a, Item *b) const;
- bool Item_val_native_with_conversion(THD *thd, Item *, Native *to) const;
- bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to) const;
- bool Item_param_val_native(THD *thd, Item_param *item, Native *to) const;
- int cmp_native(const Native &a, const Native &b) const;
- longlong Item_func_between_val_int(Item_func_between *func) const;
- cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const;
- in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const;
+ Item *a, Item *b) const override;
+ bool Item_val_native_with_conversion(THD *thd, Item *, Native *to)
+ const override;
+ bool Item_val_native_with_conversion_result(THD *thd, Item *, Native *to)
+ const override;
+ bool Item_param_val_native(THD *thd, Item_param *item, Native *to)
+ const override;
+ int cmp_native(const Native &a, const Native &b) const override;
+ longlong Item_func_between_val_int(Item_func_between *func) const override;
+ cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
+ in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs)
+ const override;
void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field,
- Sort_param *param) const;
+ Sort_param *param) const override;
void sortlength(THD *thd,
const Type_std_attributes *item,
- SORT_FIELD_ATTR *attr) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- uint Item_decimal_scale(const Item *item) const
+ SORT_FIELD_ATTR *attr) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ uint Item_decimal_scale(const Item *item) const override
{
return Item_decimal_scale_with_seconds(item);
}
- uint Item_decimal_precision(const Item *item) const;
- uint Item_divisor_precision_increment(const Item *item) const
+ uint Item_decimal_precision(const Item *item) const override;
+ uint Item_divisor_precision_increment(const Item *item) const override
{
return Item_divisor_precision_increment_with_seconds(item);
}
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override
{
return Item_send_timestamp(item, protocol, buf);
}
- int Item_save_in_field(Item *item, Field *field, bool no_conversions) const;
- String *print_item_value(THD *thd, Item *item, String *str) const;
- Item_cache *Item_get_cache(THD *thd, const Item *item) const;
- Item_copy *create_item_copy(THD *thd, Item *item) const;
- String *Item_func_min_max_val_str(Item_func_min_max *, String *) const;
- double Item_func_min_max_val_real(Item_func_min_max *) const;
- longlong Item_func_min_max_val_int(Item_func_min_max *) const;
+ int Item_save_in_field(Item *item, Field *field, bool no_conversions)
+ const override;
+ String *print_item_value(THD *thd, Item *item, String *str) const override;
+ Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
+ Item_copy *create_item_copy(THD *thd, Item *item) const override;
+ String *Item_func_min_max_val_str(Item_func_min_max *, String *) const override;
+ double Item_func_min_max_val_real(Item_func_min_max *) const override;
+ longlong Item_func_min_max_val_int(Item_func_min_max *) const override;
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
- my_decimal *) const;
- bool set_comparator_func(Arg_comparator *cmp) const;
+ my_decimal *) const override;
+ bool set_comparator_func(Arg_comparator *cmp) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
+ uchar **pos, ulong len) const override;
bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*,
- MYSQL_TIME *, date_mode_t fuzzydate) const;
+ MYSQL_TIME *, date_mode_t fuzzydate)
+ const override;
};
@@ -5644,25 +6104,29 @@ class Type_handler_timestamp: public Type_handler_timestamp_common
public:
static uint sec_part_bytes(uint dec) { return m_sec_part_bytes[dec]; }
virtual ~Type_handler_timestamp() {}
- const Name version() const { return m_version_mariadb53; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mariadb53; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ { return MAX_DATETIME_WIDTH; }
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5670,28 +6134,34 @@ class Type_handler_timestamp2: public Type_handler_timestamp_common
{
public:
virtual ~Type_handler_timestamp2() {}
- const Name version() const { return m_version_mysql56; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_TIMESTAMP2; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ const Name version() const override { return m_version_mysql56; }
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_TIMESTAMP2;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{
return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_TIMESTAMP2);
}
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5700,29 +6170,33 @@ class Type_handler_olddecimal: public Type_handler_decimal_result
static const Name m_name_decimal;
public:
virtual ~Type_handler_olddecimal() {}
- const Name name() const { return m_name_decimal; }
- enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; }
- uint32 calc_pack_length(uint32 length) const { return length; }
- const Type_handler *type_handler_for_tmp_table(const Item *item) const;
- const Type_handler *type_handler_for_union(const Item *item) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Name name() const override { return m_name_decimal; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_DECIMAL; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length; }
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override;
+ const Type_handler *type_handler_for_union(const Item *item) const override;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_DECIMAL); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5731,36 +6205,40 @@ class Type_handler_newdecimal: public Type_handler_decimal_result
static const Name m_name_decimal;
public:
virtual ~Type_handler_newdecimal() {}
- const Name name() const { return m_name_decimal; }
- enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ const Name name() const override { return m_name_decimal; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_NEWDECIMAL; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5769,52 +6247,63 @@ class Type_handler_null: public Type_handler_general_purpose_string
static const Name m_name_null;
public:
virtual ~Type_handler_null() {}
- const Name name() const { return m_name_null; }
- enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- const Type_handler *type_handler_for_comparison() const;
- const Type_handler *type_handler_for_tmp_table(const Item *item) const;
- const Type_handler *type_handler_for_union(const Item *) const;
- uint32 max_display_length(const Item *item) const { return 0; }
- uint32 calc_pack_length(uint32 length) const { return 0; }
+ const Name name() const override { return m_name_null; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_NULL; }
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ return DYN_COL_NULL;
+ }
+ const Type_handler *type_handler_for_comparison() const override;
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override;
+ const Type_handler *type_handler_for_union(const Item *) const override;
+ uint32 max_display_length(const Item *item) const override { return 0; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override
+ {
+ return 0;
+ }
+ uint32 calc_pack_length(uint32 length) const override { return 0; }
bool Item_const_eq(const Item_const *a, const Item_const *b,
- bool binary_cmp) const;
- bool Item_save_in_value(THD *thd, Item *item, st_value *value) const;
- bool Item_send(Item *item, Protocol *protocol, st_value *buf) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool binary_cmp) const override;
+ bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override;
+ bool Item_send(Item *item, Protocol *protocol, st_value *buf) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy(c, MYSQL_TYPE_NULL); }
- Field *make_table_field(const LEX_CSTRING *name,
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
class Type_handler_longstr: public Type_handler_general_purpose_string
{
public:
- bool type_can_have_key_part() const
+ bool type_can_have_key_part() const override
{
return true;
}
@@ -5826,31 +6315,37 @@ class Type_handler_string: public Type_handler_longstr
static const Name m_name_char;
public:
virtual ~Type_handler_string() {}
- const Name name() const { return m_name_char; }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
- bool is_param_long_data_type() const { return true; }
- uint32 calc_pack_length(uint32 length) const { return length; }
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ const Name name() const override { return m_name_char; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_STRING; }
+ bool is_param_long_data_type() const override { return true; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override { return length; }
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5860,24 +6355,26 @@ class Type_handler_var_string: public Type_handler_string
static const Name m_name_var_string;
public:
virtual ~Type_handler_var_string() {}
- const Name name() const { return m_name_var_string; }
- enum_field_types field_type() const { return MYSQL_TYPE_VAR_STRING; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_STRING; }
- enum_field_types traditional_merge_field_type() const
+ const Name name() const override { return m_name_var_string; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_VAR_STRING; }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_STRING; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_VARCHAR;
}
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- void Column_definition_implicit_upgrade(Column_definition *c) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ void Column_definition_implicit_upgrade(Column_definition *c) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const
+ ulonglong table_flags) const override
{ return Column_definition_prepare_stage2_legacy_num(c, MYSQL_TYPE_STRING); }
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return varstring_type_handler(item);
}
@@ -5889,43 +6386,54 @@ class Type_handler_varchar: public Type_handler_longstr
static const Name m_name_varchar;
public:
virtual ~Type_handler_varchar() {}
- const Name name() const { return m_name_varchar; }
- enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- enum_field_types type_code_for_protocol() const
+ const Name name() const override { return m_name_varchar; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_VARCHAR; }
+ enum_field_types type_code_for_protocol() const override
{
return MYSQL_TYPE_VAR_STRING; // Keep things compatible for old clients
}
- uint32 calc_pack_length(uint32 length) const
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override
{
return (length + (length < 256 ? 1: 2));
}
- const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ const Type_handler *type_handler_for_tmp_table(const Item *item) const override
{
return varstring_type_handler(item);
}
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return varstring_type_handler(item);
}
- bool is_param_long_data_type() const { return true; }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool is_param_long_data_type() const override { return true; }
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
- bool adjust_spparam_type(Spvar_definition *def, Item *from) const;
+ uint32 flags) const override;
+ bool adjust_spparam_type(Spvar_definition *def, Item *from) const override;
};
@@ -5934,17 +6442,30 @@ class Type_handler_hex_hybrid: public Type_handler_varchar
static const Name m_name_hex_hybrid;
public:
virtual ~Type_handler_hex_hybrid() {}
- const Name name() const { return m_name_hex_hybrid; }
- const Type_handler *cast_to_int_type_handler() const;
- const Type_handler *type_handler_for_system_time() const;
+ const Name name() const override { return m_name_hex_hybrid; }
+ const Type_handler *cast_to_int_type_handler() const override;
+ const Type_handler *type_handler_for_system_time() const override;
};
class Type_handler_varchar_compressed: public Type_handler_varchar
{
public:
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ enum_field_types real_field_type() const override
+ {
+ return MYSQL_TYPE_VARCHAR_COMPRESSED;
+ }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
+ {
+ DBUG_ASSERT(0);
+ return DYN_COL_STRING;
+ }
};
@@ -5952,43 +6473,68 @@ class Type_handler_blob_common: public Type_handler_longstr
{
public:
virtual ~Type_handler_blob_common() { }
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
+ virtual uint length_bytes() const= 0;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
const Type_handler *type_handler_for_tmp_table(const Item *item) const
+ override
{
return blob_type_handler(item);
}
- const Type_handler *type_handler_for_union(const Item *item) const
+ const Type_handler *type_handler_for_union(const Item *item) const override
{
return blob_type_handler(item);
}
bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ const Item *outer) const override
{
return false; // Materialization does not work with BLOB columns
}
- bool is_param_long_data_type() const { return true; }
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ bool is_param_long_data_type() const override { return true; }
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
+ const Field *field) const
+ override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_ft(Key_part_spec *part,
+ const Column_definition &def) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
- void Item_param_setup_conversion(THD *thd, Item_param *) const;
-
+ Item **items, uint nitems) const
+ override;
+ void Item_param_setup_conversion(THD *thd, Item_param *) const override;
+
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -5997,14 +6543,17 @@ class Type_handler_tiny_blob: public Type_handler_blob_common
static const Name m_name_tinyblob;
public:
virtual ~Type_handler_tiny_blob() {}
- const Name name() const { return m_name_tinyblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_TINY_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 1; }
+ const Name name() const override { return m_name_tinyblob; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_TINY_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX8; }
+ TABLE *table) const override;
+ uint max_octet_length() const override { return UINT_MAX8; }
};
@@ -6013,14 +6562,17 @@ class Type_handler_medium_blob: public Type_handler_blob_common
static const Name m_name_mediumblob;
public:
virtual ~Type_handler_medium_blob() {}
- const Name name() const { return m_name_mediumblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_MEDIUM_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 3; }
+ const Name name() const override { return m_name_mediumblob; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_MEDIUM_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX24; }
+ TABLE *table) const override;
+ uint max_octet_length() const override { return UINT_MAX24; }
};
@@ -6029,16 +6581,19 @@ class Type_handler_long_blob: public Type_handler_blob_common
static const Name m_name_longblob;
public:
virtual ~Type_handler_long_blob() {}
- const Name name() const { return m_name_longblob; }
- enum_field_types field_type() const { return MYSQL_TYPE_LONG_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
+ uint length_bytes() const override { return 4; }
+ const Name name() const override { return m_name_longblob; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_LONG_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ const Type_cast_attributes &attr) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX32; }
+ TABLE *table) const override;
+ uint max_octet_length() const override { return UINT_MAX32; }
};
@@ -6047,152 +6602,74 @@ class Type_handler_blob: public Type_handler_blob_common
static const Name m_name_blob;
public:
virtual ~Type_handler_blob() {}
- const Name name() const { return m_name_blob; }
- enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
- uint32 calc_pack_length(uint32 length) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ uint length_bytes() const override { return 2; }
+ const Name name() const override { return m_name_blob; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_BLOB; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
- uint max_octet_length() const { return UINT_MAX16; }
+ TABLE *table) const override;
+ uint max_octet_length() const override { return UINT_MAX16; }
};
class Type_handler_blob_compressed: public Type_handler_blob
{
public:
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
-};
-
-
-#ifdef HAVE_SPATIAL
-class Type_handler_geometry: public Type_handler_string_result
-{
- static const Name m_name_geometry;
-public:
- virtual ~Type_handler_geometry() {}
- const Name name() const { return m_name_geometry; }
- enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
- bool is_param_long_data_type() const { return true; }
- uint32 calc_pack_length(uint32 length) const;
- const Type_handler *type_handler_for_comparison() const;
- bool type_can_have_key_part() const
+ enum_field_types real_field_type() const override
{
- return true;
+ return MYSQL_TYPE_BLOB_COMPRESSED;
}
- bool subquery_type_allows_materialization(const Item *inner,
- const Item *outer) const
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ void show_binlog_type(const Conv_source &src, String *str) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr)
+ const override
{
- return false; // Materialization does not work with GEOMETRY columns
- }
- void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
- bool Item_param_set_from_value(THD *thd,
- Item_param *param,
- const Type_all_attributes *attr,
- const st_value *value) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- void
- Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
- uchar *buff) const;
- bool
- Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
- TABLE_SHARE *share,
- const uchar *buffer,
- LEX_CUSTRING *gis_options) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
- void Column_definition_reuse_fix_attributes(THD *thd,
- Column_definition *c,
- const Field *field) const;
- bool Column_definition_prepare_stage1(THD *thd,
- MEM_ROOT *mem_root,
- Column_definition *c,
- handler *file,
- ulonglong table_flags) const;
- bool Column_definition_prepare_stage2(Column_definition *c,
- handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
- const Record_addr &addr,
- const Type_all_attributes &attr,
- TABLE *table) const;
-
- Field *make_table_field_from_def(TABLE_SHARE *share,
- MEM_ROOT *mem_root,
- const LEX_CSTRING *name,
- const Record_addr &addr,
- const Bit_addr &bit,
- const Column_definition_attributes *attr,
- uint32 flags) const;
-
- bool can_return_int() const { return false; }
- bool can_return_decimal() const { return false; }
- bool can_return_real() const { return false; }
- bool can_return_text() const { return false; }
- bool can_return_date() const { return false; }
- bool can_return_time() const { return false; }
- bool is_traditional_type() const
- {
- return false;
+ DBUG_ASSERT(0);
+ return DYN_COL_STRING;
}
- bool Item_func_round_fix_length_and_dec(Item_func_round *) const;
- bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const;
- bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const;
- bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const;
- bool Item_hybrid_func_fix_attributes(THD *thd,
- const char *name,
- Type_handler_hybrid_field_type *h,
- Type_all_attributes *attr,
- Item **items, uint nitems) const;
- bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const;
- bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const;
- bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const;
-
- bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const;
- bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const;
- bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const;
- bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const;
- bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const;
- bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const;
- bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const;
- bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const;
- bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const;
};
-extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry;
-#endif
-
class Type_handler_typelib: public Type_handler_general_purpose_string
{
public:
virtual ~Type_handler_typelib() { }
- enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
- const Type_handler *type_handler_for_item_field() const;
- const Type_handler *cast_to_int_type_handler() const;
+ enum_field_types field_type() const override { return MYSQL_TYPE_STRING; }
+ const Type_handler *type_handler_for_item_field() const override;
+ const Type_handler *cast_to_int_type_handler() const override;
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
bool Item_hybrid_func_fix_attributes(THD *thd,
const char *name,
Type_handler_hybrid_field_type *,
Type_all_attributes *atrr,
- Item **items, uint nitems) const;
+ Item **items, uint nitems)
+ const override;
void Column_definition_reuse_fix_attributes(THD *thd,
Column_definition *c,
- const Field *field) const;
+ const Field *field)
+ const override;
bool Column_definition_prepare_stage1(THD *thd,
MEM_ROOT *mem_root,
Column_definition *c,
handler *file,
- ulonglong table_flags) const;
+ ulonglong table_flags)
+ const override;
bool Column_definition_redefine_stage1(Column_definition *def,
const Column_definition *dup,
const handler *file,
const Schema_specification_st *schema)
- const;
+ const override;
void Item_param_set_param_func(Item_param *param,
- uchar **pos, ulong len) const;
- bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
+ uchar **pos, ulong len) const override;
+ bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p)
+ const override;
};
@@ -6201,30 +6678,38 @@ class Type_handler_enum: public Type_handler_typelib
static const Name m_name_enum;
public:
virtual ~Type_handler_enum() {}
- const Name name() const { return m_name_enum; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_ENUM; }
- enum_field_types traditional_merge_field_type() const
+ const Name name() const override { return m_name_enum; }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_ENUM; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_ENUM;
}
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
+ Field *make_schema_field(MEM_ROOT *root,
+ TABLE *table,
+ const Record_addr &addr,
+ const ST_FIELD_INFO &def,
+ bool show_field) const override;
};
@@ -6233,30 +6718,33 @@ class Type_handler_set: public Type_handler_typelib
static const Name m_name_set;
public:
virtual ~Type_handler_set() {}
- const Name name() const { return m_name_set; }
- enum_field_types real_field_type() const { return MYSQL_TYPE_SET; }
- enum_field_types traditional_merge_field_type() const
+ const Name name() const override { return m_name_set; }
+ enum_field_types real_field_type() const override { return MYSQL_TYPE_SET; }
+ enum_field_types traditional_merge_field_type() const override
{
return MYSQL_TYPE_SET;
}
- uint32 calc_pack_length(uint32 length) const;
- Field *make_conversion_table_field(TABLE *, uint metadata,
- const Field *target) const;
- bool Column_definition_fix_attributes(Column_definition *c) const;
+ uint32 calc_pack_length(uint32 length) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target)
+ const override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
bool Column_definition_prepare_stage2(Column_definition *c,
handler *file,
- ulonglong table_flags) const;
- Field *make_table_field(const LEX_CSTRING *name,
+ ulonglong table_flags) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
const Record_addr &addr,
const Type_all_attributes &attr,
- TABLE *table) const;
+ TABLE *table) const override;
Field *make_table_field_from_def(TABLE_SHARE *share,
MEM_ROOT *mem_root,
const LEX_CSTRING *name,
const Record_addr &addr,
const Bit_addr &bit,
const Column_definition_attributes *attr,
- uint32 flags) const;
+ uint32 flags) const override;
};
@@ -6265,10 +6753,42 @@ class Type_handler_interval_DDhhmmssff: public Type_handler_long_blob
{
public:
Item *create_typecast_item(THD *thd, Item *item,
- const Type_cast_attributes &attr) const;
+ const Type_cast_attributes &attr) const override;
};
+class Function_collection
+{
+public:
+ virtual ~Function_collection() {}
+ virtual bool init()= 0;
+ virtual void cleanup()= 0;
+ virtual Create_func *find_native_function_builder(THD *thd,
+ const LEX_CSTRING &name)
+ const= 0;
+};
+
+
+class Type_collection
+{
+public:
+ virtual ~Type_collection() {}
+ virtual bool init(Type_handler_data *data)= 0;
+ virtual const Type_handler *handler_by_name(const LEX_CSTRING &name) const= 0;
+ virtual const Type_handler *aggregate_for_result(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_comparison(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_min_max(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+ virtual const Type_handler *aggregate_for_num_op(const Type_handler *h1,
+ const Type_handler *h2)
+ const= 0;
+};
+
/**
A handler for hybrid type functions, e.g.
@@ -6314,19 +6834,6 @@ public:
{
m_type_handler= other;
}
- const Type_handler *set_handler_by_result_type(Item_result type)
- {
- return (m_type_handler= Type_handler::get_handler_by_result_type(type));
- }
- const Type_handler *set_handler_by_result_type(Item_result type,
- uint max_octet_length,
- CHARSET_INFO *cs)
- {
- m_type_handler= Type_handler::get_handler_by_result_type(type);
- return m_type_handler=
- m_type_handler->type_handler_adjusted_to_max_octet_length(max_octet_length,
- cs);
- }
const Type_handler *set_handler_by_field_type(enum_field_types type)
{
return (m_type_handler= Type_handler::get_handler_by_field_type(type));
@@ -6363,20 +6870,29 @@ extern MYSQL_PLUGIN_IMPORT Type_handler_set type_handler_set;
extern MYSQL_PLUGIN_IMPORT Type_handler_string type_handler_string;
extern MYSQL_PLUGIN_IMPORT Type_handler_var_string type_handler_var_string;
extern MYSQL_PLUGIN_IMPORT Type_handler_varchar type_handler_varchar;
+extern MYSQL_PLUGIN_IMPORT Type_handler_varchar_compressed
+ type_handler_varchar_compressed;
extern MYSQL_PLUGIN_IMPORT Type_handler_hex_hybrid type_handler_hex_hybrid;
extern MYSQL_PLUGIN_IMPORT Type_handler_tiny_blob type_handler_tiny_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_medium_blob type_handler_medium_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_long_blob type_handler_long_blob;
extern MYSQL_PLUGIN_IMPORT Type_handler_blob type_handler_blob;
+extern MYSQL_PLUGIN_IMPORT Type_handler_blob_compressed
+ type_handler_blob_compressed;
extern MYSQL_PLUGIN_IMPORT Type_handler_bool type_handler_bool;
-extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_tiny;
-extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_short;
-extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_int24;
-extern MYSQL_PLUGIN_IMPORT Type_handler_long type_handler_long;
-extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_longlong;
-extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_ulonglong;
+extern MYSQL_PLUGIN_IMPORT Type_handler_tiny type_handler_stiny;
+extern MYSQL_PLUGIN_IMPORT Type_handler_short type_handler_sshort;
+extern MYSQL_PLUGIN_IMPORT Type_handler_int24 type_handler_sint24;
+extern MYSQL_PLUGIN_IMPORT Type_handler_long type_handler_slong;
+extern MYSQL_PLUGIN_IMPORT Type_handler_longlong type_handler_slonglong;
+
+extern MYSQL_PLUGIN_IMPORT Type_handler_utiny type_handler_utiny;
+extern MYSQL_PLUGIN_IMPORT Type_handler_ushort type_handler_ushort;
+extern MYSQL_PLUGIN_IMPORT Type_handler_uint24 type_handler_uint24;
+extern MYSQL_PLUGIN_IMPORT Type_handler_ulong type_handler_ulong;
+extern MYSQL_PLUGIN_IMPORT Type_handler_ulonglong type_handler_ulonglong;
extern MYSQL_PLUGIN_IMPORT Type_handler_vers_trx_id type_handler_vers_trx_id;
extern MYSQL_PLUGIN_IMPORT Type_handler_newdecimal type_handler_newdecimal;
diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc
new file mode 100644
index 00000000000..9bd8e3935b8
--- /dev/null
+++ b/sql/sql_type_geom.cc
@@ -0,0 +1,915 @@
+/*
+ Copyright (c) 2015 MariaDB Foundation
+ Copyright (c) 2019 MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#include "mariadb.h"
+
+#ifdef HAVE_SPATIAL
+
+#include "sql_class.h"
+#include "sql_type_geom.h"
+#include "item_geofunc.h"
+
+const Name
+ Type_handler_geometry::
+ m_name_geometry(STRING_WITH_LEN("geometry")),
+ Type_handler_point::
+ m_name_point(STRING_WITH_LEN("point")),
+ Type_handler_linestring::
+ m_name_linestring(STRING_WITH_LEN("linestring")),
+ Type_handler_polygon::
+ m_name_polygon(STRING_WITH_LEN("polygon")),
+ Type_handler_multipoint::
+ m_name_multipoint(STRING_WITH_LEN("multipoint")),
+ Type_handler_multilinestring::
+ m_name_multilinestring(STRING_WITH_LEN("multilinestring")),
+ Type_handler_multipolygon::
+ m_name_multipolygon(STRING_WITH_LEN("multipolygon")),
+ Type_handler_geometrycollection::
+ m_name_geometrycollection(STRING_WITH_LEN("geometrycollection"));
+
+
+Type_handler_geometry type_handler_geometry;
+Type_handler_point type_handler_point;
+Type_handler_linestring type_handler_linestring;
+Type_handler_polygon type_handler_polygon;
+Type_handler_multipoint type_handler_multipoint;
+Type_handler_multilinestring type_handler_multilinestring;
+Type_handler_multipolygon type_handler_multipolygon;
+Type_handler_geometrycollection type_handler_geometrycollection;
+
+
+Type_collection_geometry type_collection_geometry;
+
+
+const Type_handler_geometry *
+Type_handler_geometry::type_handler_geom_by_type(uint type)
+{
+ switch (type) {
+ case Type_handler_geometry::GEOM_POINT:
+ return &type_handler_point;
+ case Type_handler_geometry::GEOM_LINESTRING:
+ return &type_handler_linestring;
+ case Type_handler_geometry::GEOM_POLYGON:
+ return &type_handler_polygon;
+ case Type_handler_geometry::GEOM_MULTIPOINT:
+ return &type_handler_multipoint;
+ case Type_handler_geometry::GEOM_MULTILINESTRING:
+ return &type_handler_multilinestring;
+ case Type_handler_geometry::GEOM_MULTIPOLYGON:
+ return &type_handler_multipolygon;
+ case Type_handler_geometry::GEOM_GEOMETRYCOLLECTION:
+ return &type_handler_geometrycollection;
+ case Type_handler_geometry::GEOM_GEOMETRY:
+ break;
+ }
+ return &type_handler_geometry;
+}
+
+
+const Type_handler *
+Type_collection_geometry::handler_by_name(const LEX_CSTRING &name) const
+{
+ if (type_handler_point.name().eq(name))
+ return &type_handler_point;
+ if (type_handler_linestring.name().eq(name))
+ return &type_handler_linestring;
+ if (type_handler_polygon.name().eq(name))
+ return &type_handler_polygon;
+ if (type_handler_multipoint.name().eq(name))
+ return &type_handler_multipoint;
+ if (type_handler_multilinestring.name().eq(name))
+ return &type_handler_multilinestring;
+ if (type_handler_multipolygon.name().eq(name))
+ return &type_handler_multipolygon;
+ if (type_handler_geometry.name().eq(name))
+ return &type_handler_geometry;
+ if (type_handler_geometrycollection.name().eq(name))
+ return &type_handler_geometrycollection;
+ return NULL;
+}
+
+
+const Type_collection *Type_handler_geometry::type_collection() const
+{
+ return &type_collection_geometry;
+}
+
+
+const Type_handler *
+Type_handler_geometry::type_handler_frm_unpack(const uchar *buffer) const
+{
+ // charset and geometry_type share the same byte in frm
+ return type_handler_geom_by_type((uint) buffer[14]);
+}
+
+
+bool Type_collection_geometry::init_aggregators(Type_handler_data *data,
+ const Type_handler *geom) const
+{
+ Type_aggregator *r= &data->m_type_aggregator_for_result;
+ Type_aggregator *c= &data->m_type_aggregator_for_comparison;
+ return
+ r->add(geom, &type_handler_null, geom) ||
+ r->add(geom, &type_handler_hex_hybrid, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_tiny_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_medium_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_long_blob, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_varchar, &type_handler_long_blob) ||
+ r->add(geom, &type_handler_string, &type_handler_long_blob) ||
+ c->add(geom, &type_handler_null, geom) ||
+ c->add(geom, &type_handler_long_blob, &type_handler_long_blob);
+}
+
+
+bool Type_collection_geometry::init(Type_handler_data *data)
+{
+#ifndef DBUG_OFF
+ /*
+ The rules (geometry,geometry)->geometry and (pont,point)->geometry
+ are needed here to make sure
+ (in gis-debug.test) that they do not affect anything, and these pairs
+ returns an error in an expression like (POINT(0,0)+POINT(0,0)).
+ Both sides are from the same type collection here,
+ so aggregation goes only through Type_collection_xxx::aggregate_yyy()
+ and never reaches Type_aggregator::find_handler().
+ */
+ Type_aggregator *nct= &data->m_type_aggregator_non_commutative_test;
+ if (nct->add(&type_handler_geometry,
+ &type_handler_geometry,
+ &type_handler_geometry) ||
+ nct->add(&type_handler_point,
+ &type_handler_point,
+ &type_handler_geometry) ||
+ nct->add(&type_handler_point,
+ &type_handler_varchar,
+ &type_handler_long_blob))
+ return true;
+#endif // DBUG_OFF
+ return
+ init_aggregators(data, &type_handler_geometry) ||
+ init_aggregators(data, &type_handler_geometrycollection) ||
+ init_aggregators(data, &type_handler_point) ||
+ init_aggregators(data, &type_handler_linestring) ||
+ init_aggregators(data, &type_handler_polygon) ||
+ init_aggregators(data, &type_handler_multipoint) ||
+ init_aggregators(data, &type_handler_multilinestring) ||
+ init_aggregators(data, &type_handler_multipolygon);
+}
+
+
+bool Type_handler_geometry::check_type_geom_or_binary(const char *opname,
+ const Item *item)
+{
+ const Type_handler *handler= item->type_handler();
+ if (handler->type_handler_for_comparison() == &type_handler_geometry ||
+ (handler->is_general_purpose_string_type() &&
+ item->collation.collation == &my_charset_bin))
+ return false;
+ my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
+ handler->name().ptr(), opname);
+ return true;
+}
+
+
+bool Type_handler_geometry::check_types_geom_or_binary(const char *opname,
+ Item* const *args,
+ uint start, uint end)
+{
+ for (uint i= start; i < end ; i++)
+ {
+ if (check_type_geom_or_binary(opname, args[i]))
+ return true;
+ }
+ return false;
+}
+
+
+const Type_handler *Type_handler_geometry::type_handler_for_comparison() const
+{
+ return &type_handler_geometry;
+}
+
+
+Field *Type_handler_geometry::make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table,
+ uint metadata,
+ const Field *target)
+ const
+{
+ DBUG_ASSERT(target->type() == MYSQL_TYPE_GEOMETRY);
+ /*
+ We do not do not update feature_gis statistics here:
+ status_var_increment(target->table->in_use->status_var.feature_gis);
+ as this is only a temporary field.
+ The statistics was already incremented when "target" was created.
+ */
+ const Field_geom *fg= static_cast<const Field_geom*>(target);
+ return new (root)
+ Field_geom(NULL, (uchar *) "", 1, Field::NONE, &empty_clex_str,
+ table->s, 4, fg->type_handler_geom(), fg->srid);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_fix_attributes(Column_definition *def) const
+{
+ def->flags|= BLOB_FLAG;
+ return false;
+}
+
+void Type_handler_geometry::
+ Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *def,
+ const Field *field) const
+{
+ def->srid= ((Field_geom*) field)->srid;
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ def->create_length_to_internal_length_string();
+ return def->prepare_blob_field(thd);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_prepare_stage2(Column_definition *def,
+ handler *file,
+ ulonglong table_flags) const
+{
+ if (!(table_flags & HA_CAN_GEOMETRY))
+ {
+ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY");
+ return true;
+ }
+ return def->prepare_stage2_blob(file, table_flags, FIELDFLAG_GEOM);
+}
+
+bool Type_handler_geometry::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->check_primary_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ if (!part->length)
+ *hash_field_needed= true;
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->init_multiple_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ return part->check_foreign_key_for_blob(file);
+}
+
+
+bool Type_handler_geometry::Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def)
+ const
+{
+ if (part->length)
+ {
+ my_error(ER_WRONG_SUB_KEY, MYF(0));
+ return true;
+ }
+ /*
+ 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ part->length= 4 * sizeof(double);
+ return false;
+}
+
+
+Item *
+Type_handler_geometry::create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr)
+ const
+{
+ DBUG_EXECUTE_IF("emulate_geometry_create_typecast_item",
+ return new (thd->mem_root) Item_func_geometry_from_text(thd, item);
+ );
+
+ return NULL;
+}
+
+bool Type_handler_point::Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ /*
+ QQ:
+ The below assignment (here and in all other Key_part_spec_init_xxx methods)
+ overrides the explicitly given key part length, so in this query:
+ CREATE OR REPLACE TABLE t1 (a POINT, KEY(a(10)));
+ the key becomes KEY(a(25)).
+ This might be a bug.
+ */
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *hash_field_needed) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+bool Type_handler_point::Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const
+{
+ part->length= octet_length();
+ return part->check_key_for_blob(file);
+}
+
+
+Item *
+Type_handler_point::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ if (!args || args->elements != 2)
+ return NULL;
+ Item_args tmp(thd, *args);
+ return new (thd->mem_root) Item_func_point(thd,
+ tmp.arguments()[0],
+ tmp.arguments()[1]);
+}
+
+
+Item *
+Type_handler_linestring::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_linestring(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_polygon::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_polygon(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_multipoint::make_constructor_item(THD *thd, List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multipoint(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_multilinestring::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multilinestring(thd, *args) :
+ NULL;
+}
+
+
+Item *
+Type_handler_multipolygon::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_multipolygon(thd, *args) : NULL;
+}
+
+
+Item *
+Type_handler_geometrycollection::make_constructor_item(THD *thd,
+ List<Item> *args) const
+{
+ return args ? new (thd->mem_root) Item_func_geometrycollection(thd, *args) :
+ NULL;
+}
+
+
+uint32 Type_handler_geometry::calc_pack_length(uint32 length) const
+{
+ return 4 + portable_sizeof_char_ptr;
+}
+
+
+Field *Type_handler_geometry::make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const
+{
+ return new (root)
+ Field_geom(addr.ptr(), addr.null_ptr(), addr.null_bit(),
+ Field::NONE, name, table->s, 4, this, 0);
+}
+
+
+bool Type_handler_geometry::
+ Item_hybrid_func_fix_attributes(THD *thd,
+ const char *func_name,
+ Type_handler_hybrid_field_type *handler,
+ Type_all_attributes *func,
+ Item **items, uint nitems) const
+{
+ DBUG_ASSERT(nitems > 0);
+ func->collation.set(&my_charset_bin);
+ func->unsigned_flag= false;
+ func->decimals= 0;
+ func->max_length= (uint32) UINT_MAX32;
+ func->set_maybe_null(true);
+ return false;
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_sum_fix_length_and_dec(Item_sum_sum *item) const
+{
+ return Item_func_or_sum_illegal_param("sum");
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_avg_fix_length_and_dec(Item_sum_avg *item) const
+{
+ return Item_func_or_sum_illegal_param("avg");
+}
+
+
+bool Type_handler_geometry::
+ Item_sum_variance_fix_length_and_dec(Item_sum_variance *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_round_fix_length_and_dec(Item_func_round *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+
+bool Type_handler_geometry::
+ Item_func_signed_fix_length_and_dec(Item_func_signed *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const
+{
+ if (item->cast_charset() != &my_charset_bin)
+ return Item_func_or_sum_illegal_param(item); // CAST(geom AS CHAR)
+ item->fix_length_and_dec_str();
+ return false; // CAST(geom AS BINARY)
+}
+
+
+bool Type_handler_geometry::
+ Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+
+bool Type_handler_geometry::
+ Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const
+{
+ return Item_func_or_sum_illegal_param(item);
+}
+
+
+bool Type_handler_geometry::
+ Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item)
+ const
+{
+ return Item_func_or_sum_illegal_param(item);
+
+}
+
+
+bool Type_handler_geometry::
+ Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *val) const
+{
+ param->unsigned_flag= false;
+ param->setup_conversion_blob(thd);
+ return param->set_str(val->m_string.ptr(), val->m_string.length(),
+ &my_charset_bin, &my_charset_bin);
+}
+
+
+void Type_handler_geometry::Item_param_set_param_func(Item_param *param,
+ uchar **pos,
+ ulong len) const
+{
+ param->set_null(); // Not possible type code in the client-server protocol
+}
+
+
+Field *Type_handler_geometry::
+ make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &rec, const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const
+{
+ status_var_increment(current_thd->status_var.feature_gis);
+ return new (root)
+ Field_geom(rec.ptr(), rec.null_ptr(), rec.null_bit(),
+ attr->unireg_check, name, share,
+ attr->pack_flag_to_pack_length(), this, attr->srid);
+}
+
+
+void Type_handler_geometry::
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *def,
+ uchar *buff) const
+{
+ def->frm_pack_basic(buff);
+ buff[11]= 0;
+ buff[14]= (uchar) geometry_type();
+}
+
+
+
+/* Values 1-40 reserved for 1-byte options,
+ 41-80 for 2-byte options,
+ 81-120 for 4-byte options,
+ 121-160 for 8-byte options,
+ other - varied length in next 1-3 bytes.
+*/
+enum extra2_gis_field_options {
+ FIELDGEOM_END=0,
+ FIELDGEOM_STORAGE_MODEL=1,
+ FIELDGEOM_PRECISION=2,
+ FIELDGEOM_SCALE=3,
+ FIELDGEOM_SRID=81,
+};
+
+
+uint
+Type_handler_geometry::
+ Column_definition_gis_options_image(uchar *cbuf,
+ const Column_definition &def) const
+{
+ if (cbuf)
+ {
+ cbuf[0]= FIELDGEOM_STORAGE_MODEL;
+ cbuf[1]= (uchar) Field_geom::GEOM_STORAGE_WKB;
+
+ cbuf[2]= FIELDGEOM_PRECISION;
+ cbuf[3]= (uchar) def.length;
+
+ cbuf[4]= FIELDGEOM_SCALE;
+ cbuf[5]= (uchar) def.decimals;
+
+ cbuf[6]= FIELDGEOM_SRID;
+ int4store(cbuf + 7, ((uint32) def.srid));
+
+ cbuf[11]= FIELDGEOM_END;
+ }
+ return 12;
+}
+
+
+static uint gis_field_options_read(const uchar *buf, size_t buf_len,
+ Field_geom::storage_type *st_type,
+ uint *precision, uint *scale, uint *srid)
+{
+ const uchar *buf_end= buf + buf_len;
+ const uchar *cbuf= buf;
+ int option_id;
+
+ *precision= *scale= *srid= 0;
+ *st_type= Field_geom::GEOM_STORAGE_WKB;
+
+ if (!buf) /* can only happen with the old FRM file */
+ goto end_of_record;
+
+ while (cbuf < buf_end)
+ {
+ switch ((option_id= *(cbuf++)))
+ {
+ case FIELDGEOM_STORAGE_MODEL:
+ *st_type= (Field_geom::storage_type) cbuf[0];
+ break;
+ case FIELDGEOM_PRECISION:
+ *precision= cbuf[0];
+ break;
+ case FIELDGEOM_SCALE:
+ *scale= cbuf[0];
+ break;
+ case FIELDGEOM_SRID:
+ *srid= uint4korr(cbuf);
+ break;
+ case FIELDGEOM_END:
+ goto end_of_record;
+ }
+ if (option_id > 0 && option_id <= 40)
+ cbuf+= 1;
+ else if (option_id > 40 && option_id <= 80)
+ cbuf+= 2;
+ else if (option_id > 80 && option_id <= 120)
+ cbuf+= 4;
+ else if (option_id > 120 && option_id <= 160)
+ cbuf+= 8;
+ else /* > 160 and <=255 */
+ cbuf+= cbuf[0] ? 1 + cbuf[0] : 3 + uint2korr(cbuf+1);
+ }
+
+end_of_record:
+ return (uint)(cbuf - buf);
+}
+
+
+bool Type_handler_geometry::
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options)
+ const
+{
+ uint gis_opt_read, gis_length, gis_decimals;
+ Field_geom::storage_type st_type;
+ attr->frm_unpack_basic(buffer);
+ gis_opt_read= gis_field_options_read(gis_options->str,
+ gis_options->length,
+ &st_type, &gis_length,
+ &gis_decimals, &attr->srid);
+ gis_options->str+= gis_opt_read;
+ gis_options->length-= gis_opt_read;
+ return false;
+}
+
+
+uint32
+Type_handler_geometry::max_display_length_for_field(const Conv_source &src)
+ const
+{
+ return (uint32) my_set_bits(4 * 8);
+}
+
+
+enum_conv_type
+Field_geom::rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const
+{
+ return binlog_type() == source.real_field_type() ?
+ rpl_conv_type_from_same_data_type(source.metadata(), rli, param) :
+ CONV_TYPE_IMPOSSIBLE;
+}
+
+
+/*****************************************************************/
+void Field_geom::sql_type(String &res) const
+{
+ CHARSET_INFO *cs= &my_charset_latin1;
+ const Name tmp= m_type_handler->name();
+ res.set(tmp.ptr(), tmp.length(), cs);
+}
+
+
+int Field_geom::store(double nr)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store(longlong nr, bool unsigned_val)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store_decimal(const my_decimal *)
+{
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+ return -1;
+}
+
+
+int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs)
+{
+ if (!length)
+ bzero(ptr, Field_blob::pack_length());
+ else
+ {
+ if (from == Geometry::bad_geometry_data.ptr())
+ goto err;
+ // Check given WKB
+ uint32 wkb_type;
+ if (length < SRID_SIZE + WKB_HEADER_SIZE + 4)
+ goto err;
+ wkb_type= uint4korr(from + SRID_SIZE + 1);
+ if (wkb_type < (uint32) Geometry::wkb_point ||
+ wkb_type > (uint32) Geometry::wkb_last)
+ goto err;
+
+ if (m_type_handler->geometry_type() != Type_handler_geometry::GEOM_GEOMETRY &&
+ m_type_handler->geometry_type() != Type_handler_geometry::GEOM_GEOMETRYCOLLECTION &&
+ (uint32) m_type_handler->geometry_type() != wkb_type)
+ {
+ const char *db= table->s->db.str;
+ const char *tab_name= table->s->table_name.str;
+
+ if (!db)
+ db= "";
+ if (!tab_name)
+ tab_name= "";
+
+ my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0),
+ Geometry::ci_collection[m_type_handler->geometry_type()]->m_name.str,
+ Geometry::ci_collection[wkb_type]->m_name.str,
+ db, tab_name, field_name.str,
+ (ulong) table->in_use->get_stmt_da()->
+ current_row_for_warning());
+ goto err_exit;
+ }
+
+ Field_blob::store_length(length);
+ if ((table->copy_blobs || length <= MAX_FIELD_WIDTH) &&
+ from != value.ptr())
+ { // Must make a copy
+ value.copy(from, length, cs);
+ from= value.ptr();
+ }
+ bmove(ptr + packlength, &from, sizeof(char*));
+ }
+ return 0;
+
+err:
+ my_message(ER_CANT_CREATE_GEOMETRY_OBJECT,
+ ER_THD(get_thd(), ER_CANT_CREATE_GEOMETRY_OBJECT), MYF(0));
+err_exit:
+ bzero(ptr, Field_blob::pack_length());
+ return -1;
+}
+
+
+bool Field_geom::is_equal(const Column_definition &new_field) const
+{
+ /*
+ - Allow ALTER..INPLACE to supertype (GEOMETRY),
+ e.g. POINT to GEOMETRY or POLYGON to GEOMETRY.
+ - Allow ALTER..INPLACE to the same geometry type: POINT -> POINT
+ */
+ if (new_field.type_handler() == m_type_handler)
+ return true;
+ const Type_handler_geometry *gth=
+ dynamic_cast<const Type_handler_geometry*>(new_field.type_handler());
+ return gth && gth->is_binary_compatible_geom_super_type_for(m_type_handler);
+}
+
+
+bool Field_geom::can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const
+{
+ return item->cmp_type() == STRING_RESULT;
+}
+
+
+bool Field_geom::load_data_set_no_data(THD *thd, bool fixed_format)
+{
+ return Field_geom::load_data_set_null(thd);
+}
+
+
+bool Field_geom::load_data_set_null(THD *thd)
+{
+ Field_blob::reset();
+ if (!maybe_null())
+ {
+ my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field_name.str,
+ thd->get_stmt_da()->current_row_for_warning());
+ return true;
+ }
+ set_null();
+ set_has_explicit_value(); // Do not auto-update this field
+ return false;
+}
+
+
+uint Field_geom::get_key_image(uchar *buff,uint length, imagetype type_arg)
+{
+ if (type_arg == itMBR)
+ {
+ LEX_CSTRING tmp;
+ tmp.str= (const char *) get_ptr();
+ tmp.length= get_length(ptr);
+ return Geometry::get_key_image_itMBR(tmp, buff, length);
+ }
+ return Field_blob::get_key_image_itRAW(buff, length);
+}
+
+#endif // HAVE_SPATIAL
diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h
new file mode 100644
index 00000000000..699b5280611
--- /dev/null
+++ b/sql/sql_type_geom.h
@@ -0,0 +1,442 @@
+#ifndef SQL_TYPE_GEOM_H_INCLUDED
+#define SQL_TYPE_GEOM_H_INCLUDED
+/*
+ Copyright (c) 2015 MariaDB Foundation
+ Copyright (c) 2019 MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ 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 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 Street, Fifth Floor, Boston, MA 02111-1301 USA */
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mariadb.h"
+#include "sql_type.h"
+
+#ifdef HAVE_SPATIAL
+class Type_handler_geometry: public Type_handler_string_result
+{
+ static const Name m_name_geometry;
+public:
+ enum geometry_types
+ {
+ GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3,
+ GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6,
+ GEOM_GEOMETRYCOLLECTION = 7
+ };
+ static bool check_type_geom_or_binary(const char *opname, const Item *item);
+ static bool check_types_geom_or_binary(const char *opname,
+ Item * const *args,
+ uint start, uint end);
+ static const Type_handler_geometry *type_handler_geom_by_type(uint type);
+public:
+ virtual ~Type_handler_geometry() {}
+ const Name name() const override { return m_name_geometry; }
+ enum_field_types field_type() const override { return MYSQL_TYPE_GEOMETRY; }
+ bool is_param_long_data_type() const override { return true; }
+ uint32 max_display_length_for_field(const Conv_source &src) const override;
+ uint32 calc_pack_length(uint32 length) const override;
+ const Type_collection *type_collection() const override;
+ const Type_handler *type_handler_for_comparison() const override;
+ virtual geometry_types geometry_type() const { return GEOM_GEOMETRY; }
+ virtual Item *create_typecast_item(THD *thd, Item *item,
+ const Type_cast_attributes &attr)
+ const override;
+ const Type_handler *type_handler_frm_unpack(const uchar *buffer)
+ const override;
+ bool is_binary_compatible_geom_super_type_for(const Type_handler_geometry *th)
+ const
+ {
+ return geometry_type() == GEOM_GEOMETRY ||
+ geometry_type() == th->geometry_type();
+ }
+ bool type_can_have_key_part() const override { return true; }
+ bool subquery_type_allows_materialization(const Item *inner,
+ const Item *outer) const override
+ {
+ return false; // Materialization does not work with GEOMETRY columns
+ }
+ void Item_param_set_param_func(Item_param *param,
+ uchar **pos, ulong len) const override;
+ bool Item_param_set_from_value(THD *thd,
+ Item_param *param,
+ const Type_all_attributes *attr,
+ const st_value *value) const override;
+ Field *make_conversion_table_field(MEM_ROOT *root,
+ TABLE *table, uint metadata,
+ const Field *target) const override;
+ uint Column_definition_gis_options_image(uchar *buff,
+ const Column_definition &def)
+ const override;
+ void
+ Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
+ uchar *buff) const override;
+ bool
+ Column_definition_attributes_frm_unpack(Column_definition_attributes *attr,
+ TABLE_SHARE *share,
+ const uchar *buffer,
+ LEX_CUSTRING *gis_options) const
+ override;
+ bool Column_definition_fix_attributes(Column_definition *c) const override;
+ void Column_definition_reuse_fix_attributes(THD *thd,
+ Column_definition *c,
+ const Field *field) const
+ override;
+ bool Column_definition_prepare_stage1(THD *thd,
+ MEM_ROOT *mem_root,
+ Column_definition *c,
+ handler *file,
+ ulonglong table_flags) const override;
+ bool Column_definition_prepare_stage2(Column_definition *c,
+ handler *file,
+ ulonglong table_flags) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_spatial(Key_part_spec *part,
+ const Column_definition &def) const override;
+ Field *make_table_field(MEM_ROOT *root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Type_all_attributes &attr,
+ TABLE *table) const override;
+
+ Field *make_table_field_from_def(TABLE_SHARE *share,
+ MEM_ROOT *mem_root,
+ const LEX_CSTRING *name,
+ const Record_addr &addr,
+ const Bit_addr &bit,
+ const Column_definition_attributes *attr,
+ uint32 flags) const override;
+
+ bool can_return_int() const override { return false; }
+ bool can_return_decimal() const override { return false; }
+ bool can_return_real() const override { return false; }
+ bool can_return_text() const override { return false; }
+ bool can_return_date() const override { return false; }
+ bool can_return_time() const override { return false; }
+ bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
+ bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const override;
+ bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
+ bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
+ bool Item_hybrid_func_fix_attributes(THD *thd,
+ const char *name,
+ Type_handler_hybrid_field_type *h,
+ Type_all_attributes *attr,
+ Item **items, uint nitems) const
+ override;
+ bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override;
+ bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override;
+ bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override;
+
+ bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override;
+ bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
+ override;
+ bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
+ override;
+ bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
+ override;
+ bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
+ override;
+ bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
+ override;
+ bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
+ override;
+ bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
+ override;
+ bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *) const
+ override;
+};
+
+
+class Type_handler_point: public Type_handler_geometry
+{
+ static const Name m_name_point;
+ // Binary length of a POINT value: 4 byte SRID + 21 byte WKB POINT
+ static uint octet_length() { return 25; }
+public:
+ geometry_types geometry_type() const override { return GEOM_POINT; }
+ const Name name() const override { return m_name_point; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+ bool Key_part_spec_init_primary(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_unique(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file,
+ bool *has_key_needed) const override;
+ bool Key_part_spec_init_multiple(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+ bool Key_part_spec_init_foreign(Key_part_spec *part,
+ const Column_definition &def,
+ const handler *file) const override;
+};
+
+
+class Type_handler_linestring: public Type_handler_geometry
+{
+ static const Name m_name_linestring;
+public:
+ geometry_types geometry_type() const override { return GEOM_LINESTRING; }
+ const Name name() const override { return m_name_linestring; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_polygon: public Type_handler_geometry
+{
+ static const Name m_name_polygon;
+public:
+ geometry_types geometry_type() const override { return GEOM_POLYGON; }
+ const Name name() const override { return m_name_polygon; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multipoint: public Type_handler_geometry
+{
+ static const Name m_name_multipoint;
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTIPOINT; }
+ const Name name() const override { return m_name_multipoint; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multilinestring: public Type_handler_geometry
+{
+ static const Name m_name_multilinestring;
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTILINESTRING; }
+ const Name name() const override { return m_name_multilinestring; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_multipolygon: public Type_handler_geometry
+{
+ static const Name m_name_multipolygon;
+public:
+ geometry_types geometry_type() const override { return GEOM_MULTIPOLYGON; }
+ const Name name() const override { return m_name_multipolygon; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+class Type_handler_geometrycollection: public Type_handler_geometry
+{
+ static const Name m_name_geometrycollection;
+public:
+ geometry_types geometry_type() const override { return GEOM_GEOMETRYCOLLECTION; }
+ const Name name() const override { return m_name_geometrycollection; }
+ Item *make_constructor_item(THD *thd, List<Item> *args) const override;
+};
+
+
+extern MYSQL_PLUGIN_IMPORT Type_handler_geometry type_handler_geometry;
+extern MYSQL_PLUGIN_IMPORT Type_handler_point type_handler_point;
+extern MYSQL_PLUGIN_IMPORT Type_handler_linestring type_handler_linestring;
+extern MYSQL_PLUGIN_IMPORT Type_handler_polygon type_handler_polygon;
+extern MYSQL_PLUGIN_IMPORT Type_handler_multipoint type_handler_multipoint;
+extern MYSQL_PLUGIN_IMPORT Type_handler_multilinestring type_handler_multilinestring;
+extern MYSQL_PLUGIN_IMPORT Type_handler_multipolygon type_handler_multipolygon;
+extern MYSQL_PLUGIN_IMPORT Type_handler_geometrycollection type_handler_geometrycollection;
+
+
+class Function_collection_geometry: public Function_collection
+{
+public:
+ bool init() override;
+ void cleanup() override;
+ Create_func *find_native_function_builder(THD *thd,
+ const LEX_CSTRING &name)
+ const override;
+};
+
+
+class Type_collection_geometry: public Type_collection
+{
+ const Type_handler *aggregate_common(const Type_handler *a,
+ const Type_handler *b) const
+ {
+ if (a == b)
+ return a;
+ DBUG_ASSERT(dynamic_cast<const Type_handler_geometry*>(a));
+ DBUG_ASSERT(dynamic_cast<const Type_handler_geometry*>(b));
+ return &type_handler_geometry;
+ }
+ bool init_aggregators(Type_handler_data *data, const Type_handler *geom) const;
+public:
+ bool init(Type_handler_data *data) override;
+ const Type_handler *handler_by_name(const LEX_CSTRING &name) const override;
+ const Type_handler *aggregate_for_result(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_common(a, b);
+ }
+ const Type_handler *aggregate_for_comparison(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_common(a, b);
+ }
+ const Type_handler *aggregate_for_min_max(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return aggregate_common(a, b);
+ }
+ const Type_handler *aggregate_for_num_op(const Type_handler *a,
+ const Type_handler *b)
+ const override
+ {
+ return NULL;
+ }
+};
+
+
+extern MYSQL_PLUGIN_IMPORT
+ Function_collection_geometry function_collection_geometry;
+
+extern MYSQL_PLUGIN_IMPORT Type_collection_geometry type_collection_geometry;
+
+
+#include "field.h"
+
+class Field_geom :public Field_blob
+{
+ const Type_handler_geometry *m_type_handler;
+public:
+ uint srid;
+ uint precision;
+ enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1};
+ enum storage_type storage;
+
+ Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
+ enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
+ TABLE_SHARE *share, uint blob_pack_length,
+ const Type_handler_geometry *gth,
+ uint field_srid)
+ :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, share, blob_pack_length, &my_charset_bin),
+ m_type_handler(gth)
+ { srid= field_srid; }
+ enum_conv_type rpl_conv_type_from(const Conv_source &source,
+ const Relay_log_info *rli,
+ const Conv_param &param) const override;
+ enum ha_base_keytype key_type() const override
+ {
+ return HA_KEYTYPE_VARBINARY2;
+ }
+ const Type_handler *type_handler() const override
+ {
+ return m_type_handler;
+ }
+ const Type_handler_geometry *type_handler_geom() const
+ {
+ return m_type_handler;
+ }
+ void set_type_handler(const Type_handler_geometry *th)
+ {
+ m_type_handler= th;
+ }
+ enum_field_types type() const override
+ {
+ return MYSQL_TYPE_GEOMETRY;
+ }
+ enum_field_types real_type() const override
+ {
+ return MYSQL_TYPE_GEOMETRY;
+ }
+ Information_schema_character_attributes
+ information_schema_character_attributes() const override
+ {
+ return Information_schema_character_attributes();
+ }
+ void make_send_field(Send_field *to) override
+ {
+ Field_longstr::make_send_field(to);
+ }
+ bool can_optimize_range(const Item_bool_func *cond,
+ const Item *item,
+ bool is_eq_func) const override;
+ void sql_type(String &str) const override;
+ Copy_func *get_copy_func(const Field *from) const override
+ {
+ const Type_handler_geometry *fth=
+ dynamic_cast<const Type_handler_geometry*>(from->type_handler());
+ if (fth && m_type_handler->is_binary_compatible_geom_super_type_for(fth))
+ return get_identical_copy_func();
+ return do_conv_blob;
+ }
+ bool memcpy_field_possible(const Field *from) const override
+ {
+ const Type_handler_geometry *fth=
+ dynamic_cast<const Type_handler_geometry*>(from->type_handler());
+ return fth &&
+ m_type_handler->is_binary_compatible_geom_super_type_for(fth) &&
+ !table->copy_blobs;
+ }
+ bool is_equal(const Column_definition &new_field) const override;
+ bool can_be_converted_by_engine(const Column_definition &new_type)
+ const override
+ {
+ return false; // Override the Field_blob behavior
+ }
+
+ int store(const char *to, size_t length, CHARSET_INFO *charset) override;
+ int store(double nr) override;
+ int store(longlong nr, bool unsigned_val) override;
+ int store_decimal(const my_decimal *) override;
+ uint size_of() const override{ return sizeof(*this); }
+ /**
+ Key length is provided only to support hash joins. (compared byte for byte)
+ Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2.
+
+ The comparison is not very relevant, as identical geometry might be
+ represented differently, but we need to support it either way.
+ */
+ uint32 key_length() const override{ return packlength; }
+ uint get_key_image(uchar *buff,uint length, imagetype type_arg) override;
+
+ /**
+ Non-nullable GEOMETRY types cannot have defaults,
+ but the underlying blob must still be reset.
+ */
+ int reset(void) override{ return Field_blob::reset() || !maybe_null(); }
+ bool load_data_set_null(THD *thd) override;
+ bool load_data_set_no_data(THD *thd, bool fixed_format) override;
+
+ uint get_srid() const { return srid; }
+ void print_key_value(String *out, uint32 length) override
+ {
+ out->append(STRING_WITH_LEN("unprintable_geometry_value"));
+ }
+};
+
+#endif // HAVE_SPATIAL
+
+#endif // SQL_TYPE_GEOM_H_INCLUDED
diff --git a/sql/sql_type_json.cc b/sql/sql_type_json.cc
index f53a247d816..a804366ec03 100644
--- a/sql/sql_type_json.cc
+++ b/sql/sql_type_json.cc
@@ -35,8 +35,10 @@ Type_handler_json_longtext::make_json_valid_expr(THD *thd,
Lex_ident_sys_st str;
Item *field, *expr;
str.set_valid_utf8(field_name);
- if (unlikely(!(field= thd->lex->create_item_ident_field(thd, NullS, NullS,
- &str))))
+ if (unlikely(!(field= thd->lex->create_item_ident_field(thd,
+ Lex_ident_sys(),
+ Lex_ident_sys(),
+ str))))
return 0;
if (unlikely(!(expr= new (thd->mem_root) Item_func_json_valid(thd, field))))
return 0;
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index b130fbc099b..ca66da1fd0d 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -556,7 +556,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
while ((item= it++, name= nm++))
{
- item->set_name(thd, name->str, (uint) name->length, system_charset_info);
+ item->set_name(thd, *name);
item->is_autogenerated_name= FALSE;
}
}
@@ -926,16 +926,13 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
view_query.length(0);
is_query.length(0);
{
- sql_mode_t sql_mode= thd->variables.sql_mode & MODE_ANSI_QUOTES;
- thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
+ Sql_mode_instant_remove sms(thd, MODE_ANSI_QUOTES);
lex->unit.print(&view_query, enum_query_type(QT_VIEW_INTERNAL |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
lex->unit.print(&is_query, enum_query_type(QT_TO_SYSTEM_CHARSET |
QT_WITHOUT_INTRODUCERS |
QT_ITEM_ORIGINAL_FUNC_NULLIF));
-
- thd->variables.sql_mode|= sql_mode;
}
DBUG_PRINT("info", ("View: %.*s", view_query.length(), view_query.ptr()));
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 9cf1bdd5e3e..edf6b761e48 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -289,7 +289,7 @@ int LEX::case_stmt_action_then()
bool
LEX::set_system_variable(enum enum_var_type var_type,
- sys_var *sysvar, const LEX_CSTRING *base_name,
+ sys_var *sysvar, const Lex_ident_sys_st *base_name,
Item *val)
{
set_var *setvar;
@@ -299,7 +299,7 @@ LEX::set_system_variable(enum enum_var_type var_type,
sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (val && val->type() == Item::FIELD_ITEM &&
- ((Item_field*)val)->table_name)
+ ((Item_field*)val)->table_name.str)
{
my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), sysvar->name.str);
return TRUE;
@@ -339,7 +339,7 @@ bool LEX::set_trigger_new_row(const LEX_CSTRING *name, Item *val)
trg_fld= new (thd->mem_root)
Item_trigger_field(thd, current_context(),
Item_trigger_field::NEW_ROW,
- name, UPDATE_ACL, FALSE);
+ *name, UPDATE_ACL, FALSE);
if (unlikely(trg_fld == NULL))
return TRUE;
@@ -506,34 +506,22 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
@see sp_create_assignment_instr
@param thd Thread context
- @param no_lookahead True if the parser has no lookahead
+ @param pos The position in the raw SQL buffer
*/
-void sp_create_assignment_lex(THD *thd, bool no_lookahead)
-{
- LEX *lex= thd->lex;
- if (lex->sphead)
+bool sp_create_assignment_lex(THD *thd, const char *pos)
+{
+ if (thd->lex->sphead)
{
- Lex_input_stream *lip= &thd->m_parser_state->m_lip;
- LEX *old_lex= lex;
- lex->sphead->reset_lex(thd);
- lex= thd->lex;
-
- /* Set new LEX as if we at start of set rule. */
- lex->sql_command= SQLCOM_SET_OPTION;
- mysql_init_select(lex);
- lex->var_list.empty();
- lex->autocommit= 0;
- /* get_ptr() is only correct with no lookahead. */
- if (no_lookahead)
- lex->sphead->m_tmp_query= lip->get_ptr();
- else
- lex->sphead->m_tmp_query= lip->get_tok_end();
- /* Inherit from outer lex. */
- lex->option_type= old_lex->option_type;
- lex->main_select_push();
+ sp_lex_local *new_lex;
+ if (!(new_lex= new (thd->mem_root) sp_lex_set_var(thd, thd->lex)) ||
+ new_lex->main_select_push())
+ return true;
+ new_lex->sphead->m_tmp_query= pos;
+ return thd->lex->sphead->reset_lex(thd, new_lex);
}
+ return false;
}
@@ -542,13 +530,15 @@ void sp_create_assignment_lex(THD *thd, bool no_lookahead)
@see sp_create_assignment_lex
- @param thd Thread context
- @param no_lookahead True if the parser has no lookahead
-
+ @param thd - Thread context
+ @param no_lookahead - True if the parser has no lookahead
+ @param need_set_keyword - if a SET statement "SET a=10",
+ or a direct assignment overwise "a:=10"
@return false if success, true otherwise.
*/
-bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
+bool sp_create_assignment_instr(THD *thd, bool no_lookahead,
+ bool need_set_keyword)
{
LEX *lex= thd->lex;
@@ -557,6 +547,24 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
if (!lex->var_list.is_empty())
{
/*
+ - Every variable assignment from the same SET command, e.g.:
+ SET @var1=expr1, @var2=expr2;
+ produce each own sp_create_assignment_instr() call
+ lex->var_list.elements is 1 in this case.
+ - This query:
+ SET TRANSACTION READ ONLY, ISOLATION LEVEL SERIALIZABLE;
+ in translated to:
+ SET tx_read_only=1, tx_isolation=ISO_SERIALIZABLE;
+ but produces a single sp_create_assignment_instr() call
+ which includes the query fragment covering both options.
+ */
+ DBUG_ASSERT(lex->var_list.elements >= 1 && lex->var_list.elements <= 2);
+ /*
+ sql_mode=ORACLE's direct assignment of a global variable
+ is not possible by the grammar.
+ */
+ DBUG_ASSERT(Lex->option_type != OPT_GLOBAL || need_set_keyword);
+ /*
We have assignment to user or system variable or
option setting, so we should construct sp_instr_stmt
for it.
@@ -568,10 +576,15 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead)
end is either lip->ptr, if there was no lookahead,
lip->tok_end otherwise.
*/
- static const LEX_CSTRING setsp= { STRING_WITH_LEN("SET ") };
+ static const LEX_CSTRING setlc= { STRING_WITH_LEN("SET ") };
+ static const LEX_CSTRING setgl= { STRING_WITH_LEN("SET GLOBAL ") };
const char *qend= no_lookahead ? lip->get_ptr() : lip->get_tok_end();
Lex_cstring qbuf(lex->sphead->m_tmp_query, qend);
- if (lex->new_sp_instr_stmt(thd, setsp, qbuf))
+ if (lex->new_sp_instr_stmt(thd,
+ Lex->option_type == OPT_GLOBAL ? setgl :
+ need_set_keyword ? setlc :
+ null_clex_str,
+ qbuf))
return true;
}
lex->pop_select();
@@ -779,7 +792,6 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name;
enum Diagnostics_information::Which_area diag_area;
- enum Field::geometry_type geom_type;
enum enum_fk_option m_fk_option;
enum Item_udftype udf_type;
enum Key::Keytype key_type;
@@ -817,10 +829,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 47 shift/reduce conflicts.
+ Currently there are 46 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 47
+%expect 46
/*
Comments for TOKENS.
@@ -842,6 +854,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
+%token <lex_str> '@'
+
/*
Reserved keywords and operators
*/
@@ -874,7 +888,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token CASE_SYM /* SQL-2003-R */
%token CAST_SYM /* SQL-2003-R */
%token CHANGE
-%token CHAR_SYM /* SQL-2003-R */
+%token <kwd> CHAR_SYM /* SQL-2003-R */
%token CHECK_SYM /* SQL-2003-R */
%token COLLATE_SYM /* SQL-2003-R */
%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
@@ -903,7 +917,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token DECIMAL_SYM /* SQL-2003-R */
%token DECLARE_MARIADB_SYM /* SQL-2003-R */
%token DECLARE_ORACLE_SYM /* Oracle-R */
-%token DEFAULT /* SQL-2003-R */
+%token <kwd> DEFAULT /* SQL-2003-R */
%token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM
@@ -1308,8 +1322,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> FUNCTION_SYM /* SQL-2003-R, Oracle-R */
%token <kwd> GENERAL
%token <kwd> GENERATED_SYM
-%token <kwd> GEOMETRYCOLLECTION
-%token <kwd> GEOMETRY_SYM
%token <kwd> GET_FORMAT /* MYSQL-FUNC */
%token <kwd> GET_SYM /* SQL-2003-R */
%token <kwd> GLOBAL_SYM /* SQL-2003-R */
@@ -1349,7 +1361,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> LEAVES
%token <kwd> LESS_SYM
%token <kwd> LEVEL_SYM
-%token <kwd> LINESTRING
%token <kwd> LIST_SYM
%token <kwd> LOCAL_SYM /* SQL-2003-R */
%token <kwd> LOCKS_SYM
@@ -1395,9 +1406,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> MODE_SYM
%token <kwd> MODIFY_SYM
%token <kwd> MONTH_SYM /* SQL-2003-R */
-%token <kwd> MULTILINESTRING
-%token <kwd> MULTIPOINT
-%token <kwd> MULTIPOLYGON
%token <kwd> MUTEX_SYM
%token <kwd> MYSQL_SYM
%token <kwd> MYSQL_ERRNO_SYM
@@ -1444,8 +1452,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> PHASE_SYM
%token <kwd> PLUGINS_SYM
%token <kwd> PLUGIN_SYM
-%token <kwd> POINT_SYM
-%token <kwd> POLYGON
%token <kwd> PORT_SYM
%token <kwd> PRECEDES_SYM /* MYSQL */
%token <kwd> PRECEDING_SYM /* SQL-2011-N */
@@ -1702,7 +1708,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
and until NEXT_SYM / PREVIOUS_SYM.
*/
%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
-%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER
+%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER COMMENT_SYM
/*
@@ -1748,7 +1754,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ident
label_ident
sp_decl_ident
- ident_set_usual_case
ident_or_empty
ident_table_alias
ident_sysvar_name
@@ -1766,6 +1771,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
IDENT_QUOTED
IDENT_cli
ident_cli
+ ident_cli_set_usual_case
%type <kwd>
keyword_data_type
@@ -1782,6 +1788,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
keyword_sysvar_type
keyword_table_alias
keyword_verb_clause
+ charset
%type <table>
table_ident table_ident_nodb references xid
@@ -1816,8 +1823,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <create_field> field_spec column_def
-%type <geom_type> spatial_type
-
%type <num>
order_dir lock_option
udf_type opt_local opt_no_write_to_binlog
@@ -1859,6 +1864,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ws_level_flag_desc ws_level_flag_reverse ws_level_flags
opt_ws_levels ws_level_list ws_level_list_item ws_level_number
ws_level_range ws_level_list_or_range bool
+ field_options last_field_options
%type <ulonglong_number>
ulonglong_num real_ulonglong_num size_number
@@ -1880,7 +1886,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
primary_expr string_factor_expr mysql_concatenation_expr
select_sublist_qualified_asterisk
expr_or_default set_expr_or_default
- geometry_function signed_literal expr_or_literal
+ signed_literal expr_or_literal
opt_escape
sp_opt_default
simple_ident_nospvar
@@ -2054,7 +2060,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
opt_ignore opt_column opt_restrict
- grant revoke set lock unlock string_list field_options
+ grant revoke set lock unlock string_list
opt_binary table_lock_list table_lock
ref_list opt_match_clause opt_on_update_delete use
opt_delete_options opt_delete_option varchar nchar nvarchar
@@ -2073,7 +2079,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
- opt_and charset
+ opt_and
select_var_list select_var_list_init help
opt_extended_describe shutdown
opt_format_json
@@ -2799,6 +2805,7 @@ create:
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -6035,6 +6042,11 @@ create_database_options:
create_database_option:
default_collation {}
| default_charset {}
+ | COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.schema_comment= thd->make_clex_string($3);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
;
opt_if_not_exists_table_element:
@@ -6649,7 +6661,7 @@ field_type_or_serial:
field_def
| SERIAL_SYM
{
- Lex->last_field->set_handler(&type_handler_longlong);
+ Lex->last_field->set_handler(&type_handler_ulonglong);
Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG
| UNSIGNED_FLAG | UNIQUE_KEY_FLAG;
}
@@ -6820,12 +6832,23 @@ field_type:
| field_type_string
| field_type_lob
| field_type_misc
+ | IDENT_sys float_options srid_option
+ {
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error($1)))
+ MYSQL_YYABORT;
+ $$.set(h, $2);
+ Lex->charset= &my_charset_bin;
+ }
;
field_type_numeric:
- int_type opt_field_length field_options { $$.set($1, $2); }
- | real_type opt_precision field_options { $$.set($1, $2); }
- | FLOAT_SYM float_options field_options
+ int_type opt_field_length last_field_options
+ {
+ $$.set_handler_length_flags($1, $2, (uint32) $3);
+ }
+ | real_type opt_precision last_field_options { $$.set($1, $2); }
+ | FLOAT_SYM float_options last_field_options
{
$$.set(&type_handler_float, $2);
if ($2.length() && !$2.dec())
@@ -6847,24 +6870,24 @@ field_type_numeric:
}
| BOOL_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
| BOOLEAN_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
- | DECIMAL_SYM float_options field_options
+ | DECIMAL_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | NUMBER_ORACLE_SYM float_options field_options
+ | NUMBER_ORACLE_SYM float_options last_field_options
{
if ($2.length() != 0)
$$.set(&type_handler_newdecimal, $2);
else
$$.set(&type_handler_double);
}
- | NUMERIC_SYM float_options field_options
+ | NUMERIC_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | FIXED_SYM float_options field_options
+ | FIXED_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
;
@@ -6917,7 +6940,7 @@ field_type_string:
;
field_type_temporal:
- YEAR_SYM opt_field_length field_options
+ YEAR_SYM opt_field_length last_field_options
{
if ($2)
{
@@ -6995,17 +7018,6 @@ field_type_lob:
Lex->charset=&my_charset_bin;
$$.set(&type_handler_long_blob);
}
- | spatial_type float_options srid_option
- {
-#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
- Lex->last_field->geom_type= $1;
- $$.set(&type_handler_geometry, $2);
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
| MEDIUMBLOB opt_compressed
{
Lex->charset=&my_charset_bin;
@@ -7049,17 +7061,6 @@ field_type_misc:
{ $$.set(&type_handler_set); }
;
-spatial_type:
- GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
- | GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { $$= Field::GEOM_POINT; }
- | MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
- | LINESTRING { $$= Field::GEOM_LINESTRING; }
- | MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
- | POLYGON { $$= Field::GEOM_POLYGON; }
- | MULTIPOLYGON { $$= Field::GEOM_MULTIPOLYGON; }
- ;
-
char:
CHAR_SYM {}
;
@@ -7083,11 +7084,11 @@ nvarchar:
;
int_type:
- INT_SYM { $$= &type_handler_long; }
- | TINYINT { $$= &type_handler_tiny; }
- | SMALLINT { $$= &type_handler_short; }
- | MEDIUMINT { $$= &type_handler_int24; }
- | BIGINT { $$= &type_handler_longlong; }
+ INT_SYM { $$= &type_handler_slong; }
+ | TINYINT { $$= &type_handler_stiny; }
+ | SMALLINT { $$= &type_handler_sshort; }
+ | MEDIUMINT { $$= &type_handler_sint24; }
+ | BIGINT { $$= &type_handler_slonglong; }
;
real_type:
@@ -7122,12 +7123,16 @@ precision:
;
field_options:
- /* empty */ {}
- | SIGNED_SYM {}
- | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;}
- | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | UNSIGNED ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | ZEROFILL UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ /* empty */ { $$= 0; }
+ | SIGNED_SYM { $$= 0; }
+ | UNSIGNED { $$= UNSIGNED_FLAG; }
+ | ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | UNSIGNED ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | ZEROFILL UNSIGNED { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ ;
+
+last_field_options:
+ field_options { Lex->last_field->flags|= ($$= $1); }
;
field_length:
@@ -7308,8 +7313,8 @@ type_with_opt_collate:
;
charset:
- CHAR_SYM SET {}
- | CHARSET {}
+ CHAR_SYM SET { $$= $1; }
+ | CHARSET { $$= $1; }
;
charset_name:
@@ -7800,6 +7805,7 @@ alter:
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -7814,6 +7820,22 @@ alter:
MYSQL_YYABORT;
Lex->pop_select(); //main select
}
+ | ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.used_fields= 0;
+ Lex->create_info.schema_comment= thd->make_clex_string($5);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
+ opt_create_database_options
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_ALTER_DB;
+ lex->name= Lex_ident_sys();
+ if (lex->name.str == NULL &&
+ unlikely(lex->copy_db_to(&lex->name)))
+ MYSQL_YYABORT;
+ }
| ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
{
LEX *lex= Lex;
@@ -8058,7 +8080,8 @@ opt_ev_sql_stmt:
;
ident_or_empty:
- /* empty */ { $$= Lex_ident_sys(); }
+ /* empty */
+ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE { $$= Lex_ident_sys(); }
| ident
;
@@ -9567,7 +9590,7 @@ select_item_list:
{
Item *item= new (thd->mem_root)
Item_field(thd, &thd->lex->current_select->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_item_to_list(thd, item)))
@@ -9594,7 +9617,7 @@ select_item:
check_column_name($4.str)))
my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str));
$2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->set_name(thd, $4);
}
else if (!$2->name.str || $2->name.str == item_empty_name)
{
@@ -10272,7 +10295,8 @@ column_default_non_parenthesized_expr:
}
| CAST_SYM '(' expr AS cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CASE_SYM when_list_opt_else END
@@ -10288,7 +10312,8 @@ column_default_non_parenthesized_expr:
}
| CONVERT_SYM '(' expr ',' cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
@@ -10996,78 +11021,6 @@ function_call_conflict:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | geometry_function
- {
-#ifdef HAVE_SPATIAL
- $$= $1;
- /* $1 may be NULL, GEOM_NEW not tested for out of memory */
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- ;
-
-geometry_function:
- CONTAINS_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_CONTAINS_FUNC));
- }
- | GEOMETRYCOLLECTION '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_geometrycollection,
- Geometry::wkb_point));
- }
- | LINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_linestring,
- Geometry::wkb_point));
- }
- | MULTILINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multilinestring,
- Geometry::wkb_linestring));
- }
- | MULTIPOINT '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipoint,
- Geometry::wkb_point));
- }
- | MULTIPOLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipolygon,
- Geometry::wkb_polygon));
- }
- | POINT_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_point(thd, $3, $5));
- }
- | POLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_polygon,
- Geometry::wkb_linestring));
- }
- | WITHIN '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_WITHIN_FUNC));
- }
;
/*
@@ -11101,6 +11054,7 @@ function_call_generic:
}
opt_udf_expr_list ')'
{
+ const Type_handler *h;
Create_func *builder;
Item *item= NULL;
@@ -11116,8 +11070,12 @@ function_call_generic:
This will be revised with WL#2128 (SQL PATH)
*/
- builder= find_native_function_builder(thd, &$1);
- if (builder)
+ if ((h= Type_handler::handler_by_name($1)) &&
+ (item= h->make_constructor_item(thd, $4)))
+ {
+ // Found a constructor with a proper argument count
+ }
+ else if ((builder= find_native_function_builder(thd, &$1)))
{
item= builder->create_func(thd, &$1, $4);
}
@@ -11148,6 +11106,18 @@ function_call_generic:
if (unlikely(! ($$= item)))
MYSQL_YYABORT;
}
+ | CONTAINS_SYM '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
+ | WITHIN '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
| ident_cli '.' ident_cli '(' opt_expr_list ')'
{
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
@@ -11204,7 +11174,7 @@ udf_expr:
if ($4.str)
{
$2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->set_name(thd, $4);
}
/*
A field has to have its proper name in order for name
@@ -11750,12 +11720,20 @@ cast_type:
}
| cast_type_numeric { $$= $1; Lex->charset= NULL; }
| cast_type_temporal { $$= $1; Lex->charset= NULL; }
+ | IDENT_sys
+ {
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error($1)))
+ MYSQL_YYABORT;
+ $$.set(h);
+ Lex->charset= NULL;
+ }
;
cast_type_numeric:
- INT_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); }
+ INT_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM INT_SYM { $$.set(&type_handler_slonglong); }
| UNSIGNED { $$.set(&type_handler_ulonglong); }
| UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); }
| DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); }
@@ -12933,7 +12911,7 @@ procedure_clause:
lex->proc_list.next= &lex->proc_list.first;
Item_field *item= new (thd->mem_root)
Item_field(thd, &lex->current_select->context,
- NULL, NULL, &$2);
+ $2);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_proc_to_list(thd, item)))
@@ -14172,20 +14150,26 @@ show_param:
}
| ALL SLAVES STATUS_SYM
{
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status(true)))
+ MYSQL_YYABORT;
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 1;
}
| SLAVE STATUS_SYM
{
LEX *lex= thd->lex;
lex->mi.connection_name= null_clex_str;
+ if (!(lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- lex->verbose= 0;
}
| SLAVE connection_name STATUS_SYM
{
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 0;
}
| CREATE PROCEDURE_SYM sp_name
{
@@ -15138,8 +15122,8 @@ literal:
will include the introducer and the original hex/bin notation.
*/
item_str= new (thd->mem_root)
- Item_string_with_introducer(thd, NULL, $2->ptr(), $2->length(),
- $1);
+ Item_string_with_introducer(thd, null_clex_str,
+ $2->lex_cstring(), $1);
if (unlikely(!item_str ||
!item_str->check_well_formed_result(true)))
MYSQL_YYABORT;
@@ -15539,13 +15523,9 @@ ident_table_alias:
}
;
-ident_set_usual_case:
- IDENT_sys
- | keyword_set_usual_case
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
+ident_cli_set_usual_case:
+ IDENT_cli { $$= $1; }
+ | keyword_set_usual_case { $$= $1; }
;
ident_sysvar_name:
@@ -15886,21 +15866,13 @@ keyword_data_type:
| DATETIME
| ENUM
| FIXED_SYM
- | GEOMETRYCOLLECTION
- | GEOMETRY_SYM
| JSON_SYM
- | LINESTRING
| MEDIUM_SYM
- | MULTILINESTRING
- | MULTIPOINT
- | MULTIPOLYGON
| NATIONAL_SYM
| NCHAR_SYM
| NUMBER_MARIADB_SYM
| NUMBER_ORACLE_SYM
| NVARCHAR_SYM
- | POINT_SYM
- | POLYGON
| RAW_MARIADB_SYM
| RAW_ORACLE_SYM
| ROW_SYM
@@ -16255,111 +16227,78 @@ set:
if (lex->main_select_push())
MYSQL_YYABORT;
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
- start_option_value_list
+ set_param
{
Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
- | SET STATEMENT_SYM
+ ;
+
+set_param:
+ option_value_no_option_type
+ | option_value_no_option_type ',' option_value_list
+ | TRANSACTION_SYM
{
- if (Lex->main_select_push())
+ Lex->option_type= OPT_DEFAULT;
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ transaction_characteristics
+ {
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
- Lex->set_stmt_init();
}
- set_stmt_option_value_following_option_type_list
+ | option_type
+ {
+ Lex->option_type= $1;
+ }
+ start_option_value_list_following_option_type
+ | STATEMENT_SYM
+ set_stmt_option_list
{
LEX *lex= Lex;
if (unlikely(lex->table_or_sp_used()))
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
lex->stmt_var_list= lex->var_list;
lex->var_list.empty();
- Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
- {}
;
-set_stmt_option_value_following_option_type_list:
+set_stmt_option_list:
/*
Only system variables can be used here. If this condition is changed
please check careful code under lex->option_type == OPT_STATEMENT
condition on wrong type casts.
*/
- option_value_following_option_type
- | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type
- ;
-
-/* Start of option value list */
-start_option_value_list:
- option_value_no_option_type
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- option_value_list_continued
- | TRANSACTION_SYM
- {
- Lex->option_type= OPT_DEFAULT;
- }
- transaction_characteristics
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_type
- {
- Lex->option_type= $1;
- }
- start_option_value_list_following_option_type
+ set_stmt_option
+ | set_stmt_option_list ',' set_stmt_option
;
-
/* Start of option value list, option_type was given */
start_option_value_list_following_option_type:
option_value_following_option_type
+ | option_value_following_option_type ',' option_value_list
+ | TRANSACTION_SYM
{
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- option_value_list_continued
- | TRANSACTION_SYM transaction_characteristics
+ transaction_characteristics
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
-/* Remainder of the option value list after first option value. */
-option_value_list_continued:
- /* empty */
- | ',' option_value_list
- ;
-
/* Repeating list of option values after first option value. */
option_value_list:
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_value_list ','
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
+ | option_value_list ',' option_value
;
/* Wrapper around option values following the first option value in the stmt. */
@@ -16392,16 +16331,21 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-/* Option values with preceding option_type. */
-option_value_following_option_type:
- ident equal set_expr_or_default
+/*
+ SET STATEMENT options do not need their own LEX or Query_arena.
+ Let's put them to the main ones.
+*/
+set_stmt_option:
+ ident_cli equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3)))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ | ident_cli '.' ident equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5)))
MYSQL_YYABORT;
}
| DEFAULT '.' ident equal set_expr_or_default
@@ -16411,45 +16355,132 @@ option_value_following_option_type:
}
;
+
+/* Option values with preceding option_type. */
+option_value_following_option_type:
+ ident_cli equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | ident_cli '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ ;
+
/* Option values without preceding option_type. */
option_value_no_option_type:
- ident_set_usual_case equal set_expr_or_default
+ ident_cli_set_usual_case equal
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_variable(&$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | DEFAULT '.' ident equal set_expr_or_default
+ | ident_cli_set_usual_case '.' ident equal
{
- if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | '@' ident_or_text equal expr
+ | DEFAULT '.' ident equal
{
- if (unlikely(Lex->set_user_variable(thd, &$2, $4)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_system_variable($3, &$4, $6)))
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)))
+ MYSQL_YYABORT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default
+ | '@' ident_or_text equal
{
- if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8)))
+ if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
+ expr
{
- if (unlikely(Lex->set_default_system_variable($3, &$6, $8)))
+ if (unlikely(Lex->set_user_variable(thd, &$2, $5)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident_sysvar_name equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_system_variable($3, &$4, $7)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| charset old_or_new_charset_name_or_default
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= thd->lex;
CHARSET_INFO *cs2;
cs2= $2 ? $2: global_system_variables.character_set_client;
@@ -16461,6 +16492,8 @@ option_value_no_option_type:
if (unlikely(var == NULL))
MYSQL_YYABORT;
lex->var_list.push_back(var, thd->mem_root);
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| NAMES_SYM equal expr
{
@@ -16475,6 +16508,8 @@ option_value_no_option_type:
}
| NAMES_SYM charset_name_or_default opt_collate
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= Lex;
CHARSET_INFO *cs2;
CHARSET_INFO *cs3;
@@ -16489,11 +16524,14 @@ option_value_no_option_type:
set_var_collation_client *var;
var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
LEX_USER *user;
if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
@@ -16509,9 +16547,13 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role FOR_SYM user
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_default_role *var= (new (thd->mem_root)
set_var_default_role($5, $3->user));
@@ -16521,22 +16563,36 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| ROLE_SYM ident_or_text
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_role *var= new (thd->mem_root) set_var_role($2);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | ROLE_SYM equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | ROLE_SYM equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| PASSWORD_SYM opt_for_user text_or_password
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_password *var= (new (thd->mem_root)
set_var_password(lex->definer));
@@ -16546,6 +16602,8 @@ option_value_no_option_type:
lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
;
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index e04554d4e88..f938bcfd9d5 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -259,7 +259,6 @@ void ORAerror(THD *thd, const char *s)
enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name;
enum Diagnostics_information::Which_area diag_area;
- enum Field::geometry_type geom_type;
enum enum_fk_option m_fk_option;
enum Item_udftype udf_type;
enum Key::Keytype key_type;
@@ -295,10 +294,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%parse-param { THD *thd }
%lex-param { THD *thd }
/*
- Currently there are 50 shift/reduce conflicts.
+ Currently there are 49 shift/reduce conflicts.
We should not introduce new conflicts any more.
*/
-%expect 50
+%expect 49
/*
Comments for TOKENS.
@@ -320,6 +319,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/
+%token <lex_str> '@'
+
/*
Reserved keywords and operators
*/
@@ -352,7 +353,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token CASE_SYM /* SQL-2003-R */
%token CAST_SYM /* SQL-2003-R */
%token CHANGE
-%token CHAR_SYM /* SQL-2003-R */
+%token <kwd> CHAR_SYM /* SQL-2003-R */
%token CHECK_SYM /* SQL-2003-R */
%token COLLATE_SYM /* SQL-2003-R */
%token CONDITION_SYM /* SQL-2003-R, SQL-2008-R */
@@ -381,7 +382,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token DECIMAL_SYM /* SQL-2003-R */
%token DECLARE_MARIADB_SYM /* SQL-2003-R */
%token DECLARE_ORACLE_SYM /* Oracle-R */
-%token DEFAULT /* SQL-2003-R */
+%token <kwd> DEFAULT /* SQL-2003-R */
%token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM
@@ -786,8 +787,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> FUNCTION_SYM /* SQL-2003-R, Oracle-R */
%token <kwd> GENERAL
%token <kwd> GENERATED_SYM
-%token <kwd> GEOMETRYCOLLECTION
-%token <kwd> GEOMETRY_SYM
%token <kwd> GET_FORMAT /* MYSQL-FUNC */
%token <kwd> GET_SYM /* SQL-2003-R */
%token <kwd> GLOBAL_SYM /* SQL-2003-R */
@@ -827,7 +826,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> LEAVES
%token <kwd> LESS_SYM
%token <kwd> LEVEL_SYM
-%token <kwd> LINESTRING
%token <kwd> LIST_SYM
%token <kwd> LOCAL_SYM /* SQL-2003-R */
%token <kwd> LOCKS_SYM
@@ -873,9 +871,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> MODE_SYM
%token <kwd> MODIFY_SYM
%token <kwd> MONTH_SYM /* SQL-2003-R */
-%token <kwd> MULTILINESTRING
-%token <kwd> MULTIPOINT
-%token <kwd> MULTIPOLYGON
%token <kwd> MUTEX_SYM
%token <kwd> MYSQL_SYM
%token <kwd> MYSQL_ERRNO_SYM
@@ -922,8 +917,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <kwd> PHASE_SYM
%token <kwd> PLUGINS_SYM
%token <kwd> PLUGIN_SYM
-%token <kwd> POINT_SYM
-%token <kwd> POLYGON
%token <kwd> PORT_SYM
%token <kwd> PRECEDES_SYM /* MYSQL */
%token <kwd> PRECEDING_SYM /* SQL-2011-N */
@@ -1180,7 +1173,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
and until NEXT_SYM / PREVIOUS_SYM.
*/
%left PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE
-%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER
+%left TRANSACTION_SYM TIMESTAMP PERIOD_SYM SYSTEM USER COMMENT_SYM
/*
@@ -1228,7 +1221,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ident
label_ident
sp_decl_ident
- ident_set_usual_case
ident_or_empty
ident_table_alias
ident_sysvar_name
@@ -1247,6 +1239,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
IDENT_QUOTED
IDENT_cli
ident_cli
+ ident_cli_set_usual_case
+ ident_cli_directly_assignable
%type <kwd>
keyword_data_type
@@ -1264,6 +1258,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
keyword_table_alias
keyword_verb_clause
keyword_directly_assignable
+ charset
%type <table>
table_ident table_ident_nodb references xid
@@ -1301,8 +1296,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%type <create_field> field_spec column_def
-%type <geom_type> spatial_type
-
%type <num>
order_dir lock_option
udf_type opt_local opt_no_write_to_binlog
@@ -1344,6 +1337,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
ws_level_flag_desc ws_level_flag_reverse ws_level_flags
opt_ws_levels ws_level_list ws_level_list_item ws_level_number
ws_level_range ws_level_list_or_range bool
+ field_options last_field_options
%type <ulonglong_number>
ulonglong_num real_ulonglong_num size_number
@@ -1365,7 +1359,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
primary_expr string_factor_expr mysql_concatenation_expr
select_sublist_qualified_asterisk
expr_or_default set_expr_or_default
- geometry_function signed_literal expr_or_literal
+ signed_literal expr_or_literal
opt_escape
sp_opt_default
simple_ident_nospvar
@@ -1541,7 +1535,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
procedure_list procedure_list2 procedure_item
field_def handler opt_generated_always
opt_ignore opt_column opt_restrict
- grant revoke set lock unlock string_list field_options
+ grant revoke set lock unlock string_list
opt_binary table_lock_list table_lock
ref_list opt_match_clause opt_on_update_delete use
opt_delete_options opt_delete_option varchar nchar nvarchar
@@ -1560,7 +1554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild
- opt_and charset
+ opt_and
select_var_list select_var_list_init help
opt_extended_describe shutdown
opt_format_json
@@ -2303,6 +2297,7 @@ create:
| create_or_replace DATABASE opt_if_not_exists ident
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -4035,16 +4030,18 @@ sp_proc_stmt_if:
sp_statement:
statement
- | ident_directly_assignable
+ | ident_cli_directly_assignable
{
// Direct procedure call (without the CALL keyword)
- if (unlikely(Lex->call_statement_start(thd, &$1)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->call_statement_start(thd, &tmp)))
MYSQL_YYABORT;
}
opt_sp_cparam_list
- | ident_directly_assignable '.' ident
+ | ident_cli_directly_assignable '.' ident
{
- if (unlikely(Lex->call_statement_start(thd, &$1, &$3)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->call_statement_start(thd, &tmp, &$3)))
MYSQL_YYABORT;
}
opt_sp_cparam_list
@@ -6044,6 +6041,11 @@ create_database_options:
create_database_option:
default_collation {}
| default_charset {}
+ | COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.schema_comment= thd->make_clex_string($3);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
;
opt_if_not_exists_table_element:
@@ -6658,7 +6660,7 @@ field_type_or_serial:
field_def
| SERIAL_SYM
{
- Lex->last_field->set_handler(&type_handler_longlong);
+ Lex->last_field->set_handler(&type_handler_ulonglong);
Lex->last_field->flags|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG
| UNSIGNED_FLAG | UNIQUE_KEY_FLAG;
}
@@ -6829,6 +6831,14 @@ field_type:
| field_type_string
| field_type_lob
| field_type_misc
+ | IDENT_sys float_options srid_option
+ {
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error($1)))
+ MYSQL_YYABORT;
+ $$.set(h, $2);
+ Lex->charset= &my_charset_bin;
+ }
;
@@ -6842,9 +6852,12 @@ sp_param_field_type:
field_type_numeric:
- int_type opt_field_length field_options { $$.set($1, $2); }
- | real_type opt_precision field_options { $$.set($1, $2); }
- | FLOAT_SYM float_options field_options
+ int_type opt_field_length last_field_options
+ {
+ $$.set_handler_length_flags($1, $2, (uint32) $3);
+ }
+ | real_type opt_precision last_field_options { $$.set($1, $2); }
+ | FLOAT_SYM float_options last_field_options
{
$$.set(&type_handler_float, $2);
if ($2.length() && !$2.dec())
@@ -6866,24 +6879,24 @@ field_type_numeric:
}
| BOOL_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
| BOOLEAN_SYM
{
- $$.set(&type_handler_tiny, "1");
+ $$.set(&type_handler_stiny, "1");
}
- | DECIMAL_SYM float_options field_options
+ | DECIMAL_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | NUMBER_ORACLE_SYM float_options field_options
+ | NUMBER_ORACLE_SYM float_options last_field_options
{
if ($2.length() != 0)
$$.set(&type_handler_newdecimal, $2);
else
$$.set(&type_handler_double);
}
- | NUMERIC_SYM float_options field_options
+ | NUMERIC_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
- | FIXED_SYM float_options field_options
+ | FIXED_SYM float_options last_field_options
{ $$.set(&type_handler_newdecimal, $2);}
;
@@ -6978,7 +6991,7 @@ sp_param_field_type_string:
field_type_temporal:
- YEAR_SYM opt_field_length field_options
+ YEAR_SYM opt_field_length last_field_options
{
if ($2)
{
@@ -7056,17 +7069,6 @@ field_type_lob:
Lex->charset=&my_charset_bin;
$$.set(&type_handler_long_blob);
}
- | spatial_type float_options srid_option
- {
-#ifdef HAVE_SPATIAL
- Lex->charset=&my_charset_bin;
- Lex->last_field->geom_type= $1;
- $$.set(&type_handler_geometry, $2);
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
| MEDIUMBLOB opt_compressed
{
Lex->charset=&my_charset_bin;
@@ -7110,17 +7112,6 @@ field_type_misc:
{ $$.set(&type_handler_set); }
;
-spatial_type:
- GEOMETRY_SYM { $$= Field::GEOM_GEOMETRY; }
- | GEOMETRYCOLLECTION { $$= Field::GEOM_GEOMETRYCOLLECTION; }
- | POINT_SYM { $$= Field::GEOM_POINT; }
- | MULTIPOINT { $$= Field::GEOM_MULTIPOINT; }
- | LINESTRING { $$= Field::GEOM_LINESTRING; }
- | MULTILINESTRING { $$= Field::GEOM_MULTILINESTRING; }
- | POLYGON { $$= Field::GEOM_POLYGON; }
- | MULTIPOLYGON { $$= Field::GEOM_MULTIPOLYGON; }
- ;
-
char:
CHAR_SYM {}
;
@@ -7144,11 +7135,11 @@ nvarchar:
;
int_type:
- INT_SYM { $$= &type_handler_long; }
- | TINYINT { $$= &type_handler_tiny; }
- | SMALLINT { $$= &type_handler_short; }
- | MEDIUMINT { $$= &type_handler_int24; }
- | BIGINT { $$= &type_handler_longlong; }
+ INT_SYM { $$= &type_handler_slong; }
+ | TINYINT { $$= &type_handler_stiny; }
+ | SMALLINT { $$= &type_handler_sshort; }
+ | MEDIUMINT { $$= &type_handler_sint24; }
+ | BIGINT { $$= &type_handler_slonglong; }
;
real_type:
@@ -7183,12 +7174,16 @@ precision:
;
field_options:
- /* empty */ {}
- | SIGNED_SYM {}
- | UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG;}
- | ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | UNSIGNED ZEROFILL { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
- | ZEROFILL UNSIGNED { Lex->last_field->flags|= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ /* empty */ { $$= 0; }
+ | SIGNED_SYM { $$= 0; }
+ | UNSIGNED { $$= UNSIGNED_FLAG; }
+ | ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | UNSIGNED ZEROFILL { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ | ZEROFILL UNSIGNED { $$= UNSIGNED_FLAG | ZEROFILL_FLAG; }
+ ;
+
+last_field_options:
+ field_options { Lex->last_field->flags|= ($$= $1); }
;
field_length:
@@ -7409,8 +7404,8 @@ sp_param_type_with_opt_collate:
;
charset:
- CHAR_SYM SET {}
- | CHARSET {}
+ CHAR_SYM SET { $$= $1; }
+ | CHARSET { $$= $1; }
;
charset_name:
@@ -7901,6 +7896,7 @@ alter:
| ALTER DATABASE ident_or_empty
{
Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.schema_comment= NULL;
Lex->create_info.used_fields= 0;
if (Lex->main_select_push())
MYSQL_YYABORT;
@@ -7915,6 +7911,22 @@ alter:
MYSQL_YYABORT;
Lex->pop_select(); //main select
}
+ | ALTER DATABASE COMMENT_SYM opt_equal TEXT_STRING_sys
+ {
+ Lex->create_info.default_table_charset= NULL;
+ Lex->create_info.used_fields= 0;
+ Lex->create_info.schema_comment= thd->make_clex_string($5);
+ Lex->create_info.used_fields|= HA_CREATE_USED_COMMENT;
+ }
+ opt_create_database_options
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_ALTER_DB;
+ lex->name= Lex_ident_sys();
+ if (lex->name.str == NULL &&
+ unlikely(lex->copy_db_to(&lex->name)))
+ MYSQL_YYABORT;
+ }
| ALTER DATABASE ident UPGRADE_SYM DATA_SYM DIRECTORY_SYM NAME_SYM
{
LEX *lex= Lex;
@@ -8159,7 +8171,8 @@ opt_ev_sql_stmt:
;
ident_or_empty:
- /* empty */ { $$= Lex_ident_sys(); }
+ /* empty */
+ %prec PREC_BELOW_IDENTIFIER_OPT_SPECIAL_CASE { $$= Lex_ident_sys(); }
| ident
;
@@ -9668,7 +9681,7 @@ select_item_list:
{
Item *item= new (thd->mem_root)
Item_field(thd, &thd->lex->current_select->context,
- NULL, NULL, &star_clex_str);
+ star_clex_str);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_item_to_list(thd, item)))
@@ -9695,7 +9708,7 @@ select_item:
check_column_name($4.str)))
my_yyabort_error((ER_WRONG_COLUMN_NAME, MYF(0), $4.str));
$2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->set_name(thd, $4);
}
else if (!$2->name.str || $2->name.str == item_empty_name)
{
@@ -10382,7 +10395,8 @@ column_default_non_parenthesized_expr:
}
| CAST_SYM '(' expr AS cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CASE_SYM when_list_opt_else END
@@ -10398,7 +10412,8 @@ column_default_non_parenthesized_expr:
}
| CONVERT_SYM '(' expr ',' cast_type ')'
{
- if (unlikely(!($$= $5.create_typecast_item(thd, $3, Lex->charset))))
+ if (unlikely(!($$= $5.create_typecast_item_or_error(thd, $3,
+ Lex->charset))))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr USING charset_name ')'
@@ -11106,78 +11121,6 @@ function_call_conflict:
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
- | geometry_function
- {
-#ifdef HAVE_SPATIAL
- $$= $1;
- /* $1 may be NULL, GEOM_NEW not tested for out of memory */
- if (unlikely($$ == NULL))
- MYSQL_YYABORT;
-#else
- my_yyabort_error((ER_FEATURE_DISABLED, MYF(0), sym_group_geom.name,
- sym_group_geom.needed_define));
-#endif
- }
- ;
-
-geometry_function:
- CONTAINS_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_CONTAINS_FUNC));
- }
- | GEOMETRYCOLLECTION '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_geometrycollection,
- Geometry::wkb_point));
- }
- | LINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_linestring,
- Geometry::wkb_point));
- }
- | MULTILINESTRING '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multilinestring,
- Geometry::wkb_linestring));
- }
- | MULTIPOINT '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipoint,
- Geometry::wkb_point));
- }
- | MULTIPOLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_multipolygon,
- Geometry::wkb_polygon));
- }
- | POINT_SYM '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_point(thd, $3, $5));
- }
- | POLYGON '(' expr_list ')'
- {
- $$= GEOM_NEW(thd,
- Item_func_spatial_collection(thd, *$3,
- Geometry::wkb_polygon,
- Geometry::wkb_linestring));
- }
- | WITHIN '(' expr ',' expr ')'
- {
- $$= GEOM_NEW(thd, Item_func_spatial_precise_rel(thd, $3, $5,
- Item_func::SP_WITHIN_FUNC));
- }
;
/*
@@ -11211,6 +11154,7 @@ function_call_generic:
}
opt_udf_expr_list ')'
{
+ const Type_handler *h;
Create_func *builder;
Item *item= NULL;
@@ -11226,8 +11170,12 @@ function_call_generic:
This will be revised with WL#2128 (SQL PATH)
*/
- builder= find_native_function_builder(thd, &$1);
- if (builder)
+ if ((h= Type_handler::handler_by_name($1)) &&
+ (item= h->make_constructor_item(thd, $4)))
+ {
+ // Found a constructor with a proper argument count
+ }
+ else if ((builder= find_native_function_builder(thd, &$1)))
{
item= builder->create_func(thd, &$1, $4);
}
@@ -11258,6 +11206,18 @@ function_call_generic:
if (unlikely(! ($$= item)))
MYSQL_YYABORT;
}
+ | CONTAINS_SYM '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
+ | WITHIN '(' opt_expr_list ')'
+ {
+ if (!($$= Lex->make_item_func_call_native_or_parse_error(thd,
+ $1, $3)))
+ MYSQL_YYABORT;
+ }
| ident_cli '.' ident_cli '(' opt_expr_list ')'
{
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
@@ -11314,7 +11274,7 @@ udf_expr:
if ($4.str)
{
$2->is_autogenerated_name= FALSE;
- $2->set_name(thd, $4.str, $4.length, system_charset_info);
+ $2->set_name(thd, $4);
}
/*
A field has to have its proper name in order for name
@@ -11860,12 +11820,20 @@ cast_type:
}
| cast_type_numeric { $$= $1; Lex->charset= NULL; }
| cast_type_temporal { $$= $1; Lex->charset= NULL; }
+ | IDENT_sys
+ {
+ const Type_handler *h;
+ if (!(h= Type_handler::handler_by_name_or_error($1)))
+ MYSQL_YYABORT;
+ $$.set(h);
+ Lex->charset= NULL;
+ }
;
cast_type_numeric:
- INT_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM { $$.set(&type_handler_longlong); }
- | SIGNED_SYM INT_SYM { $$.set(&type_handler_longlong); }
+ INT_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM { $$.set(&type_handler_slonglong); }
+ | SIGNED_SYM INT_SYM { $$.set(&type_handler_slonglong); }
| UNSIGNED { $$.set(&type_handler_ulonglong); }
| UNSIGNED INT_SYM { $$.set(&type_handler_ulonglong); }
| DECIMAL_SYM float_options { $$.set(&type_handler_newdecimal, $2); }
@@ -13043,7 +13011,7 @@ procedure_clause:
lex->proc_list.next= &lex->proc_list.first;
Item_field *item= new (thd->mem_root)
Item_field(thd, &lex->current_select->context,
- NULL, NULL, &$2);
+ $2);
if (unlikely(item == NULL))
MYSQL_YYABORT;
if (unlikely(add_proc_to_list(thd, item)))
@@ -14306,19 +14274,25 @@ show_param:
| ALL SLAVES STATUS_SYM
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 1;
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status(true)))
+ MYSQL_YYABORT;
}
| SLAVE STATUS_SYM
{
LEX *lex= thd->lex;
lex->mi.connection_name= null_clex_str;
lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- lex->verbose= 0;
+ if (!(lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
}
| SLAVE connection_name STATUS_SYM
{
Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT;
- Lex->verbose= 0;
+ if (!(Lex->m_sql_cmd= new (thd->mem_root)
+ Sql_cmd_show_slave_status()))
+ MYSQL_YYABORT;
}
| CREATE PROCEDURE_SYM sp_name
{
@@ -15270,8 +15244,8 @@ literal:
will include the introducer and the original hex/bin notation.
*/
item_str= new (thd->mem_root)
- Item_string_with_introducer(thd, NULL, $2->ptr(), $2->length(),
- $1);
+ Item_string_with_introducer(thd, null_clex_str,
+ $2->lex_cstring(), $1);
if (unlikely(!item_str ||
!item_str->check_well_formed_result(true)))
MYSQL_YYABORT;
@@ -15671,13 +15645,9 @@ ident_table_alias:
}
;
-ident_set_usual_case:
- IDENT_sys
- | keyword_set_usual_case
- {
- if (unlikely($$.copy_keyword(thd, &$1)))
- MYSQL_YYABORT;
- }
+ident_cli_set_usual_case:
+ IDENT_cli { $$= $1; }
+ | keyword_set_usual_case { $$= $1; }
;
ident_sysvar_name:
@@ -15714,6 +15684,12 @@ ident_directly_assignable:
;
+ident_cli_directly_assignable:
+ IDENT_cli
+ | keyword_directly_assignable { $$= $1; }
+ ;
+
+
label_ident:
IDENT_sys
| keyword_label
@@ -16056,21 +16032,13 @@ keyword_data_type:
| DATETIME
| ENUM
| FIXED_SYM
- | GEOMETRYCOLLECTION
- | GEOMETRY_SYM
| JSON_SYM
- | LINESTRING
| MEDIUM_SYM
- | MULTILINESTRING
- | MULTIPOINT
- | MULTIPOLYGON
| NATIONAL_SYM
| NCHAR_SYM
| NUMBER_MARIADB_SYM
| NUMBER_ORACLE_SYM
| NVARCHAR_SYM
- | POINT_SYM
- | POLYGON
| RAW_MARIADB_SYM
| RAW_ORACLE_SYM
| ROW_SYM
@@ -16424,63 +16392,79 @@ set:
if (lex->main_select_push())
MYSQL_YYABORT;
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
}
- start_option_value_list
+ set_param
{
Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
- | SET STATEMENT_SYM
+ ;
+
+set_param:
+ option_value_no_option_type
+ | option_value_no_option_type ',' option_value_list
+ | TRANSACTION_SYM
+ {
+ Lex->option_type= OPT_DEFAULT;
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ transaction_characteristics
{
- if (Lex->main_select_push())
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
- Lex->set_stmt_init();
}
- set_stmt_option_value_following_option_type_list
+ | option_type
+ {
+ Lex->option_type= $1;
+ }
+ start_option_value_list_following_option_type
+ | STATEMENT_SYM
+ set_stmt_option_list
{
LEX *lex= Lex;
if (unlikely(lex->table_or_sp_used()))
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "SET STATEMENT"));
lex->stmt_var_list= lex->var_list;
lex->var_list.empty();
- Lex->pop_select(); //main select
if (Lex->check_main_unit_semantics())
MYSQL_YYABORT;
}
FOR_SYM verb_clause
- {}
;
set_assign:
- ident_directly_assignable SET_VAR
+ ident_cli_directly_assignable SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
}
set_expr_or_default
{
- if (unlikely(Lex->set_variable(&$1, $4)) ||
- unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
MYSQL_YYABORT;
}
- | ident_directly_assignable '.' ident SET_VAR
+ | ident_cli_directly_assignable '.' ident SET_VAR
{
LEX *lex=Lex;
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
}
set_expr_or_default
{
LEX *lex= Lex;
DBUG_ASSERT(lex->var_list.is_empty());
- if (unlikely(lex->set_variable(&$1, &$3, $6)) ||
- unlikely(lex->sphead->restore_lex(thd)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(lex->set_variable(&tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
MYSQL_YYABORT;
}
| COLON_ORACLE_SYM ident '.' ident SET_VAR
@@ -16492,93 +16476,49 @@ set_assign:
MYSQL_YYABORT;
}
lex->set_stmt_init();
- lex->var_list.empty();
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
}
set_expr_or_default
{
LEX_CSTRING tmp= { $2.str, $2.length };
if (unlikely(Lex->set_trigger_field(&tmp, &$4, $7)) ||
- unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
+ false)))
MYSQL_YYABORT;
}
;
-set_stmt_option_value_following_option_type_list:
+set_stmt_option_list:
/*
Only system variables can be used here. If this condition is changed
please check careful code under lex->option_type == OPT_STATEMENT
condition on wrong type casts.
*/
- option_value_following_option_type
- | set_stmt_option_value_following_option_type_list ',' option_value_following_option_type
- ;
-
-/* Start of option value list */
-start_option_value_list:
- option_value_no_option_type
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- option_value_list_continued
- | TRANSACTION_SYM
- {
- Lex->option_type= OPT_DEFAULT;
- }
- transaction_characteristics
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_type
- {
- Lex->option_type= $1;
- }
- start_option_value_list_following_option_type
+ set_stmt_option
+ | set_stmt_option_list ',' set_stmt_option
;
-
/* Start of option value list, option_type was given */
start_option_value_list_following_option_type:
option_value_following_option_type
+ | option_value_following_option_type ',' option_value_list
+ | TRANSACTION_SYM
{
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- option_value_list_continued
- | TRANSACTION_SYM transaction_characteristics
+ transaction_characteristics
{
if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
;
-/* Remainder of the option value list after first option value. */
-option_value_list_continued:
- /* empty */
- | ',' option_value_list
- ;
-
/* Repeating list of option values after first option value. */
option_value_list:
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
- option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
- | option_value_list ','
- {
- sp_create_assignment_lex(thd, yychar == YYEMPTY);
- }
option_value
- {
- if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
- MYSQL_YYABORT;
- }
+ | option_value_list ',' option_value
;
/* Wrapper around option values following the first option value in the stmt. */
@@ -16611,16 +16551,21 @@ opt_var_ident_type:
| SESSION_SYM '.' { $$=OPT_SESSION; }
;
-/* Option values with preceding option_type. */
-option_value_following_option_type:
- ident equal set_expr_or_default
+/*
+ SET STATEMENT options do not need their own LEX or Query_arena.
+ Let's put them to the main ones.
+*/
+set_stmt_option:
+ ident_cli equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(Lex->option_type, &$1, $3)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $3)))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ | ident_cli '.' ident equal set_expr_or_default
{
- if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $5)))
MYSQL_YYABORT;
}
| DEFAULT '.' ident equal set_expr_or_default
@@ -16630,45 +16575,132 @@ option_value_following_option_type:
}
;
+
+/* Option values with preceding option_type. */
+option_value_following_option_type:
+ ident_cli equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(Lex->option_type, &tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | ident_cli '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_system_variable(thd, Lex->option_type, &tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ ;
+
/* Option values without preceding option_type. */
option_value_no_option_type:
- ident_set_usual_case equal set_expr_or_default
+ ident_cli_set_usual_case equal
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
MYSQL_YYABORT;
}
- | ident '.' ident equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_variable(&$1, &$3, $5)))
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | DEFAULT '.' ident equal set_expr_or_default
+ | ident_cli_set_usual_case '.' ident equal
{
- if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $5)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, &$3, $6)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | DEFAULT '.' ident equal
+ {
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_default_system_variable(Lex->option_type, &$3, $6)))
+ MYSQL_YYABORT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' ident_or_text equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
+ MYSQL_YYABORT;
+ }
+ expr
+ {
+ if (unlikely(Lex->set_user_variable(thd, &$2, $5)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident_sysvar_name equal
+ {
+ if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
- | '@' ident_or_text equal expr
+ set_expr_or_default
+ {
+ if (unlikely(Lex->set_system_variable($3, &$4, $7)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
+ }
+ | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal
{
- if (unlikely(Lex->set_user_variable(thd, &$2, $4)))
+ if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_system_variable($3, &$4, $6)))
+ if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type ident_sysvar_name '.' ident equal set_expr_or_default
+ | '@' '@' opt_var_ident_type DEFAULT '.' ident equal
{
- if (unlikely(Lex->set_system_variable(thd, $3, &$4, &$6, $8)))
+ if (sp_create_assignment_lex(thd, $1.str))
MYSQL_YYABORT;
}
- | '@' '@' opt_var_ident_type DEFAULT '.' ident equal set_expr_or_default
+ set_expr_or_default
{
- if (unlikely(Lex->set_default_system_variable($3, &$6, $8)))
+ if (unlikely(Lex->set_default_system_variable($3, &$6, $9)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| charset old_or_new_charset_name_or_default
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= thd->lex;
CHARSET_INFO *cs2;
cs2= $2 ? $2: global_system_variables.character_set_client;
@@ -16680,6 +16712,8 @@ option_value_no_option_type:
if (unlikely(var == NULL))
MYSQL_YYABORT;
lex->var_list.push_back(var, thd->mem_root);
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| NAMES_SYM equal expr
{
@@ -16694,6 +16728,8 @@ option_value_no_option_type:
}
| NAMES_SYM charset_name_or_default opt_collate
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex= Lex;
CHARSET_INFO *cs2;
CHARSET_INFO *cs3;
@@ -16708,11 +16744,14 @@ option_value_no_option_type:
set_var_collation_client *var;
var= new (thd->mem_root) set_var_collation_client(cs3, cs3, cs3);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
LEX_USER *user;
if (unlikely(!(user=(LEX_USER *) thd->calloc(sizeof(LEX_USER)))))
@@ -16728,9 +16767,13 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| DEFAULT ROLE_SYM grant_role FOR_SYM user
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_default_role *var= (new (thd->mem_root)
set_var_default_role($5, $3->user));
@@ -16740,22 +16783,36 @@ option_value_no_option_type:
thd->lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
| ROLE_SYM ident_or_text
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_role *var= new (thd->mem_root) set_var_role($2);
if (unlikely(var == NULL) ||
- unlikely(lex->var_list.push_back(var, thd->mem_root)))
+ unlikely(lex->var_list.push_back(var, thd->mem_root)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
- | ROLE_SYM equal set_expr_or_default
+ | ROLE_SYM equal
{
- if (unlikely(Lex->set_variable(&$1, $3)))
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
+ }
+ set_expr_or_default
+ {
+ Lex_ident_sys tmp(thd, &$1);
+ if (unlikely(Lex->set_variable(&tmp, $4)) ||
+ unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
MYSQL_YYABORT;
}
| PASSWORD_SYM opt_for_user text_or_password
{
+ if (sp_create_assignment_lex(thd, $1.pos()))
+ MYSQL_YYABORT;
LEX *lex = Lex;
set_var_password *var= (new (thd->mem_root)
set_var_password(lex->definer));
@@ -16765,6 +16822,8 @@ option_value_no_option_type:
lex->autocommit= TRUE;
if (lex->sphead)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
+ if (unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY)))
+ MYSQL_YYABORT;
}
;
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 99ff9c50588..61f6078c875 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -45,7 +45,8 @@
static const char field_separator=',';
-ulonglong find_set(TYPELIB *lib, const char *str, size_t length, CHARSET_INFO *cs,
+ulonglong find_set(const TYPELIB *lib,
+ const char *str, size_t length, CHARSET_INFO *cs,
char **err_pos, uint *err_len, bool *set_warning)
{
CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
diff --git a/sql/strfunc.h b/sql/strfunc.h
index d66d4c63444..b2b293e153f 100644
--- a/sql/strfunc.h
+++ b/sql/strfunc.h
@@ -18,7 +18,8 @@
typedef struct st_typelib TYPELIB;
-ulonglong find_set(TYPELIB *lib, const char *x, size_t length, CHARSET_INFO *cs,
+ulonglong find_set(const TYPELIB *lib,
+ const char *x, size_t length, CHARSET_INFO *cs,
char **err_pos, uint *err_len, bool *set_warning);
ulonglong find_set_from_flags(TYPELIB *lib, uint default_name,
ulonglong cur_set, ulonglong default_set,
diff --git a/sql/structs.h b/sql/structs.h
index 0c00aeec33a..f6d63051dfe 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -618,6 +618,8 @@ public:
m_handler= handler;
Lex_length_and_dec_st::operator=(length_and_dec);
}
+ void set_handler_length_flags(const Type_handler *handler, const char *length,
+ uint32 flags);
void set(const Type_handler *handler, const char *length)
{
set(handler, length, 0);
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index f2a6000843d..2e7c5e7f442 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3756,7 +3756,7 @@ static Sys_var_uint Sys_threadpool_stall_limit(
"If a worker thread is stalled, additional worker thread "
"may be created to handle remaining clients.",
GLOBAL_VAR(threadpool_stall_limit), CMD_LINE(REQUIRED_ARG),
- VALID_RANGE(10, UINT_MAX), DEFAULT(500), BLOCK_SIZE(1),
+ VALID_RANGE(1, UINT_MAX), DEFAULT(DEFAULT_THREADPOOL_STALL_LIMIT), BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_threadpool_stall_limit)
);
@@ -3776,6 +3776,20 @@ static Sys_var_uint Sys_threadpool_threadpool_prio_kickup_timer(
GLOBAL_VAR(threadpool_prio_kickup_timer), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(1000), BLOCK_SIZE(1)
);
+
+static Sys_var_mybool Sys_threadpool_exact_stats(
+ "thread_pool_exact_stats",
+ "If set to 1, provides better statistics in information_schema threadpool tables",
+ GLOBAL_VAR(threadpool_exact_stats), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG
+);
+
+static Sys_var_mybool Sys_threadpool_dedicated_listener(
+ "thread_pool_dedicated_listener",
+ "If set to 1,listener thread will not pick up queries",
+ GLOBAL_VAR(threadpool_dedicated_listener), CMD_LINE(OPT_ARG), DEFAULT(FALSE),
+ NO_MUTEX_GUARD, NOT_IN_BINLOG
+);
#endif /* HAVE_POOL_OF_THREADS */
/**
diff --git a/sql/table.cc b/sql/table.cc
index 1ab4df0f7cf..6951b21c53d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -59,6 +59,7 @@ struct extra2_fields
LEX_CUSTRING field_flags;
LEX_CUSTRING system_period;
LEX_CUSTRING application_period;
+ LEX_CUSTRING field_data_type_info;
void reset()
{ bzero((void*)this, sizeof(*this)); }
};
@@ -1077,7 +1078,6 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
Field **vfield_ptr= table->vfield;
Field **dfield_ptr= table->default_field;
Virtual_column_info **check_constraint_ptr= table->check_constraints;
- sql_mode_t saved_mode= thd->variables.sql_mode;
Query_arena backup_arena;
Virtual_column_info *vcol= 0;
StringBuffer<MAX_FIELD_WIDTH> expr_str;
@@ -1103,7 +1103,7 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table,
thd->stmt_arena= table->expr_arena;
thd->update_charset(&my_charset_utf8mb4_general_ci, table->s->table_charset);
expr_str.append(&parse_vcol_keyword);
- thd->variables.sql_mode &= ~MODE_NO_BACKSLASH_ESCAPES;
+ Sql_mode_instant_remove sms(thd, MODE_NO_BACKSLASH_ESCAPES);
while (pos < end)
{
@@ -1271,7 +1271,6 @@ end:
thd->stmt_arena= backup_stmt_arena_ptr;
if (save_character_set_client)
thd->update_charset(save_character_set_client, save_collation);
- thd->variables.sql_mode= saved_mode;
DBUG_RETURN(res);
}
@@ -1510,6 +1509,12 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
fields->application_period.str= extra2;
fields->application_period.length= length;
break;
+ case EXTRA2_FIELD_DATA_TYPE_INFO:
+ if (fields->field_data_type_info.str)
+ DBUG_RETURN(true);
+ fields->field_data_type_info.str= extra2;
+ fields->field_data_type_info.length= length;
+ break;
default:
/* abort frm parsing if it's an unknown but important extra2 value */
if (type >= EXTRA2_ENGINE_IMPORTANT)
@@ -1524,6 +1529,86 @@ bool read_extra2(const uchar *frm_image, size_t len, extra2_fields *fields)
}
+class Field_data_type_info_array
+{
+public:
+ class Elem
+ {
+ LEX_CSTRING m_type_info;
+ public:
+ void set(const LEX_CSTRING &type_info)
+ {
+ m_type_info= type_info;
+ }
+ const LEX_CSTRING &type_info() const
+ {
+ return m_type_info;
+ }
+ };
+private:
+ Elem *m_array;
+ uint m_count;
+ bool alloc(MEM_ROOT *root, uint count)
+ {
+ DBUG_ASSERT(!m_array);
+ DBUG_ASSERT(!m_count);
+ size_t nbytes= sizeof(Elem) * count;
+ if (!(m_array= (Elem*) alloc_root(root, nbytes)))
+ return true;
+ m_count= count;
+ bzero((void*) m_array, nbytes);
+ return false;
+ }
+ static uint32 read_length(uchar **pos, const uchar *end)
+ {
+ ulonglong num= safe_net_field_length_ll(pos, end - *pos);
+ if (num > UINT_MAX32)
+ return 0;
+ return (uint32) num;
+ }
+ static bool read_string(LEX_CSTRING *to, uchar **pos, const uchar *end)
+ {
+ to->length= read_length(pos, end);
+ if (*pos + to->length > end)
+ return true; // Not enough data
+ to->str= (const char *) *pos;
+ *pos+= to->length;
+ return false;
+ }
+public:
+ Field_data_type_info_array()
+ :m_array(NULL), m_count(0)
+ { }
+ uint count() const
+ {
+ return m_count;
+ }
+ const Elem element(uint i) const
+ {
+ DBUG_ASSERT(i < m_count);
+ return m_array[i];
+ }
+ bool parse(MEM_ROOT *root, uint count, LEX_CUSTRING &image)
+ {
+ const uchar *pos= image.str;
+ const uchar *end= pos + image.length;
+ if (alloc(root, count))
+ return true;
+ for (uint i= 0; i < count && pos < end; i++)
+ {
+ LEX_CSTRING type_info;
+ uint fieldnr= read_length((uchar**) &pos, end);
+ if ((fieldnr == 0 && i > 0) || fieldnr >= count)
+ return true; // Bad data
+ if (read_string(&type_info, (uchar**) &pos, end) || type_info.length == 0)
+ return true; // Bad data
+ m_array[fieldnr].set(type_info);
+ }
+ return pos < end; // Error if some data is still left
+ }
+};
+
+
/**
Read data from a binary .frm file image into a TABLE_SHARE
@@ -1574,6 +1659,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
uint ext_key_parts= 0;
plugin_ref se_plugin= 0;
bool vers_can_native= false;
+ Field_data_type_info_array field_data_type_info_array;
MEM_ROOT *old_root= thd->mem_root;
Virtual_column_info **table_check_constraints;
@@ -1769,7 +1855,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
name.length= str_db_type_length;
plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name, false);
- if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin))
+ if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin) &&
+ legacy_db_type != DB_TYPE_S3)
{
if (se_plugin)
{
@@ -2112,6 +2199,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
status_var_increment(thd->status_var.feature_application_time_periods);
}
+ if (extra2.field_data_type_info.length &&
+ field_data_type_info_array.parse(old_root, share->fields,
+ extra2.field_data_type_info))
+ goto err;
+
for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++)
{
uint interval_nr= 0, recpos;
@@ -2191,10 +2283,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
enum_field_types field_type= (enum_field_types) strpos[13];
if (!(handler= Type_handler::get_handler_by_real_type(field_type)))
goto err; // Not supported field type
+ handler= handler->type_handler_frm_unpack(strpos);
if (handler->Column_definition_attributes_frm_unpack(&attr, share,
strpos,
&extra2.gis))
goto err;
+
+ if (field_data_type_info_array.count())
+ {
+ DBUG_EXECUTE_IF("frm_data_type_info",
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR, "DBUG: [%u] name='%s' type_info='%.*s'",
+ i, share->fieldnames.type_names[i],
+ (uint) field_data_type_info_array.element(i).type_info().length,
+ field_data_type_info_array.element(i).type_info().str););
+ }
}
if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD)
@@ -2554,7 +2657,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
KEY_PART_INFO *new_key_part= (keyinfo-1)->key_part +
(keyinfo-1)->ext_key_parts;
uint add_keyparts_for_this_key= add_first_key_parts;
- uint length_bytes= 0, len_null_byte= 0, ext_key_length= 0;
+ uint len_null_byte= 0, ext_key_length= 0;
Field *field;
if ((keyinfo-1)->algorithm == HA_KEY_ALG_LONG_HASH)
@@ -2566,19 +2669,15 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
*/
for (i= 0; i < keyinfo->user_defined_key_parts; i++)
{
+ uint length_bytes= 0;
uint fieldnr= keyinfo->key_part[i].fieldnr;
field= share->field[fieldnr-1];
if (field->null_ptr)
len_null_byte= HA_KEY_NULL_LENGTH;
- if ((field->type() == MYSQL_TYPE_BLOB ||
- field->real_type() == MYSQL_TYPE_VARCHAR ||
- field->type() == MYSQL_TYPE_GEOMETRY) &&
- keyinfo->algorithm != HA_KEY_ALG_LONG_HASH )
- {
- length_bytes= HA_KEY_BLOB_LENGTH;
- }
+ if (keyinfo->algorithm != HA_KEY_ALG_LONG_HASH)
+ length_bytes= field->key_part_length_bytes();
ext_key_length+= keyinfo->key_part[i].length + len_null_byte
+ length_bytes;
@@ -2667,20 +2766,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
keyinfo->flags|=HA_NULL_PART_KEY;
keyinfo->key_length+= HA_KEY_NULL_LENGTH;
}
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->real_type() == MYSQL_TYPE_VARCHAR ||
- field->type() == MYSQL_TYPE_GEOMETRY)
- {
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->type() == MYSQL_TYPE_GEOMETRY)
- key_part->key_part_flag|= HA_BLOB_PART;
- else
- key_part->key_part_flag|= HA_VAR_LENGTH_PART;
- key_part->store_length+=HA_KEY_BLOB_LENGTH;
- keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
- }
- if (field->type() == MYSQL_TYPE_BIT)
- key_part->key_part_flag|= HA_BIT_PART;
+
+ key_part->key_part_flag|= field->key_part_flag();
+ uint16 key_part_length_bytes= field->key_part_length_bytes();
+ key_part->store_length+= key_part_length_bytes;
+ keyinfo->key_length+= key_part_length_bytes;
if (i == 0 && key != primary_key)
field->flags |= (((keyinfo->flags & HA_NOSAME ||
@@ -3075,7 +3165,6 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine,
int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
const char *sql, size_t sql_length)
{
- sql_mode_t saved_mode= thd->variables.sql_mode;
CHARSET_INFO *old_cs= thd->variables.character_set_client;
Parser_state parser_state;
bool error;
@@ -3103,7 +3192,7 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write,
if (parser_state.init(thd, sql_copy, sql_length))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
- thd->variables.sql_mode= MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE;
+ Sql_mode_instant_set sms(thd, MODE_NO_ENGINE_SUBSTITUTION | MODE_NO_DIR_IN_CREATE);
thd->variables.character_set_client= system_charset_info;
tmp_disable_binlog(thd);
old_lex= thd->lex;
@@ -3152,7 +3241,6 @@ ret:
if (arena)
thd->restore_active_arena(arena, &backup);
reenable_binlog(thd);
- thd->variables.sql_mode= saved_mode;
thd->variables.character_set_client= old_cs;
if (unlikely(thd->is_error() || error))
{
@@ -4402,21 +4490,17 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
StringBuffer<MAX_FIELD_WIDTH> str;
bool rc;
THD *thd= field->get_thd();
- sql_mode_t sql_mode_backup= thd->variables.sql_mode;
- thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+ Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH);
field->val_str(&str);
if ((rc= !str.length() ||
!(to= strmake_root(mem, str.ptr(), str.length()))))
{
res->length(0);
- goto ex;
+ return rc;
}
res->set(to, str.length(), field->charset());
-
-ex:
- thd->variables.sql_mode= sql_mode_backup;
- return rc;
+ return false;
}
@@ -6401,8 +6485,8 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref,
&view->view->first_select_lex()->context:
&thd->lex->first_select_lex()->context);
Item *item= (new (thd->mem_root)
- Item_direct_view_ref(thd, context, field_ref, view->alias.str,
- name, view));
+ Item_direct_view_ref(thd, context, field_ref, view->alias,
+ *name, view));
if (!item)
return NULL;
/*
@@ -7502,14 +7586,9 @@ void TABLE::create_key_part_by_field(KEY_PART_INFO *key_part_info,
{
key_part_info->store_length+= HA_KEY_NULL_LENGTH;
}
- if (field->type() == MYSQL_TYPE_BLOB ||
- field->type() == MYSQL_TYPE_GEOMETRY ||
- field->real_type() == MYSQL_TYPE_VARCHAR)
- {
- key_part_info->store_length+= HA_KEY_BLOB_LENGTH;
- key_part_info->key_part_flag|=
- field->type() == MYSQL_TYPE_BLOB ? HA_BLOB_PART: HA_VAR_LENGTH_PART;
- }
+
+ key_part_info->key_part_flag|= field->key_part_flag();
+ key_part_info->store_length+= field->key_part_length_bytes();
key_part_info->type= (uint8) field->key_type();
key_part_info->key_type =
@@ -9399,7 +9478,7 @@ bool TR_table::check(bool error)
}
Field_enum *iso_level= static_cast<Field_enum *>(table->field[FLD_ISO_LEVEL]);
- st_typelib *typelib= iso_level->typelib;
+ const st_typelib *typelib= iso_level->typelib;
if (typelib->count != 4)
goto wrong_enum;
diff --git a/sql/table.h b/sql/table.h
index 2562f9632a5..2b866159fe0 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -31,6 +31,7 @@
#include "thr_lock.h" /* thr_lock_type */
#include "filesort_utils.h"
#include "parse_file.h"
+#include "sql_i_s.h"
/* Structs that defines the TABLE */
@@ -1094,9 +1095,6 @@ struct st_cond_statistic;
#define CHECK_ROW_FOR_NULLS_TO_REJECT (1 << 0)
#define REJECT_ROW_DUE_TO_NULL_FIELDS (1 << 1)
-/* Bitmap of table's fields */
-typedef Bitmap<MAX_FIELDS> Field_map;
-
class SplM_opt_info;
struct vers_select_conds_t;
@@ -1663,71 +1661,6 @@ typedef struct st_foreign_key_info
LEX_CSTRING *fk_option_name(enum_fk_option opt);
bool fk_modifies_child(enum_fk_option opt);
-#define MY_I_S_MAYBE_NULL 1U
-#define MY_I_S_UNSIGNED 2U
-
-
-#define SKIP_OPEN_TABLE 0U // do not open table
-#define OPEN_FRM_ONLY 1U // open FRM file only
-#define OPEN_FULL_TABLE 2U // open FRM,MYD, MYI files
-
-typedef struct st_field_info
-{
- /**
- This is used as column name.
- */
- const char* field_name;
- /**
- For string-type columns, this is the maximum number of
- characters. Otherwise, it is the 'display-length' for the column.
- */
- uint field_length;
- /**
- This denotes data type for the column. For the most part, there seems to
- be one entry in the enum for each SQL data type, although there seem to
- be a number of additional entries in the enum.
- */
- enum enum_field_types field_type;
- int value;
- /**
- This is used to set column attributes. By default, columns are @c NOT
- @c NULL and @c SIGNED, and you can deviate from the default
- by setting the appopriate flags. You can use either one of the flags
- @c MY_I_S_MAYBE_NULL and @cMY_I_S_UNSIGNED or
- combine them using the bitwise or operator @c |. Both flags are
- defined in table.h.
- */
- uint field_flags; // Field atributes(maybe_null, signed, unsigned etc.)
- const char* old_name;
- /**
- This should be one of @c SKIP_OPEN_TABLE,
- @c OPEN_FRM_ONLY or @c OPEN_FULL_TABLE.
- */
- uint open_method;
-} ST_FIELD_INFO;
-
-
-struct TABLE_LIST;
-typedef class Item COND;
-
-typedef struct st_schema_table
-{
- const char *table_name;
- ST_FIELD_INFO *fields_info;
- /* for FLUSH table_name */
- int (*reset_table) ();
- /* Fill table with data */
- int (*fill_table) (THD *thd, TABLE_LIST *tables, COND *cond);
- /* Handle fileds for old SHOW */
- int (*old_format) (THD *thd, struct st_schema_table *schema_table);
- int (*process_table) (THD *thd, TABLE_LIST *tables, TABLE *table,
- bool res, const LEX_CSTRING *db_name,
- const LEX_CSTRING *table_name);
- int idx_field1, idx_field2;
- bool hidden;
- uint i_s_requested_object; /* the object we need to open(TABLE | VIEW) */
-} ST_SCHEMA_TABLE;
-
class IS_table_read_plan;
/*
diff --git a/sql/thread_pool_info.cc b/sql/thread_pool_info.cc
new file mode 100644
index 00000000000..99ac3cd148c
--- /dev/null
+++ b/sql/thread_pool_info.cc
@@ -0,0 +1,357 @@
+/* Copyright(C) 2019 MariaDB
+
+This program is free software; you can redistribute itand /or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; version 2 of the License.
+
+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 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 Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
+
+#include <mysql_version.h>
+#include <mysql/plugin.h>
+
+#include <my_global.h>
+#include <sql_class.h>
+#include <sql_i_s.h>
+#include <mysql/plugin.h>
+#include <sql_show.h>
+#include <threadpool_generic.h>
+
+namespace Show {
+
+static ST_FIELD_INFO groups_fields_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("CONNECTIONS", SLong(6), NOT_NULL),
+ Column("THREADS", SLong(6), NOT_NULL),
+ Column("ACTIVE_THREADS", SLong(6), NOT_NULL),
+ Column("STANDBY_THREADS", SLong(6), NOT_NULL),
+ Column("QUEUE_LENGTH", SLong(6), NOT_NULL),
+ Column("HAS_LISTENER", STiny(1), NOT_NULL),
+ Column("IS_STALLED", STiny(1), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+
+static int groups_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ thread_group_t* group = &all_groups[i];
+ /* ID */
+ table->field[0]->store(i, true);
+ /* CONNECTION_COUNT */
+ table->field[1]->store(group->connection_count, true);
+ /* THREAD_COUNT */
+ table->field[2]->store(group->thread_count, true);
+ /* ACTIVE_THREAD_COUNT */
+ table->field[3]->store(group->active_thread_count, true);
+ /* STANDBY_THREAD_COUNT */
+ table->field[4]->store(group->waiting_threads.elements(), true);
+ /* QUEUE LENGTH */
+ uint queue_len = group->queues[TP_PRIORITY_LOW].elements()
+ + group->queues[TP_PRIORITY_HIGH].elements();
+ table->field[5]->store(queue_len, true);
+ /* HAS_LISTENER */
+ table->field[6]->store((longlong)(group->listener != 0), true);
+ /* IS_STALLED */
+ table->field[7]->store(group->stalled, true);
+
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+
+static int groups_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::groups_fields_info;
+ schema->fill_table = groups_fill_table;
+ return 0;
+}
+
+
+namespace Show {
+
+static ST_FIELD_INFO queues_field_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("POSITION", SLong(6), NOT_NULL),
+ Column("PRIORITY", SLong(1), NOT_NULL),
+ Column("CONNECTION_ID", ULonglong(19), NOT_NULL),
+ Column("QUEUEING_TIME_MICROSECONDS", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+typedef connection_queue_t::Iterator connection_queue_iterator;
+
+static int queues_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint group_id = 0;
+ group_id < threadpool_max_size && all_groups[group_id].pollfd != INVALID_HANDLE_VALUE;
+ group_id++)
+ {
+ thread_group_t* group = &all_groups[group_id];
+
+ mysql_mutex_lock(&group->mutex);
+ bool err = false;
+ int pos = 0;
+ ulonglong now = microsecond_interval_timer();
+ for (uint prio = 0; prio < NQUEUES && !err; prio++)
+ {
+ connection_queue_iterator it(group->queues[prio]);
+ TP_connection_generic* c;
+ while ((c = it++) != 0)
+ {
+ /* GROUP_ID */
+ table->field[0]->store(group_id, true);
+ /* POSITION */
+ table->field[1]->store(pos++, true);
+ /* PRIORITY */
+ table->field[2]->store(prio, true);
+ /* CONNECTION_ID */
+ table->field[3]->store(c->thd->thread_id, true);
+ /* QUEUEING_TIME */
+ table->field[4]->store(now - c->enqueue_time, true);
+
+ err = schema_table_store_record(thd, table);
+ if (err)
+ break;
+ }
+ }
+ mysql_mutex_unlock(&group->mutex);
+ if (err)
+ return 1;
+ }
+ return 0;
+}
+
+static int queues_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::queues_field_info;
+ schema->fill_table = queues_fill_table;
+ return 0;
+}
+
+namespace Show {
+
+static ST_FIELD_INFO stats_fields_info[] =
+{
+ Column("GROUP_ID", SLong(6), NOT_NULL),
+ Column("THREAD_CREATIONS", SLonglong(19), NOT_NULL),
+ Column("THREAD_CREATIONS_DUE_TO_STALL", SLonglong(19), NOT_NULL),
+ Column("WAKES", SLonglong(19), NOT_NULL),
+ Column("WAKES_DUE_TO_STALL", SLonglong(19), NOT_NULL),
+ Column("THROTTLES", SLonglong(19), NOT_NULL),
+ Column("STALLS", SLonglong(19), NOT_NULL),
+ Column("POLLS_BY_LISTENER", SLonglong(19), NOT_NULL),
+ Column("POLLS_BY_WORKER", SLonglong(19), NOT_NULL),
+ Column("DEQUEUES_BY_LISTENER", SLonglong(19), NOT_NULL),
+ Column("DEQUEUES_BY_WORKER", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+
+static int stats_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ table->field[0]->store(i, true);
+ thread_group_t* group = &all_groups[i];
+
+ mysql_mutex_lock(&group->mutex);
+ thread_group_counters_t* counters = &group->counters;
+ table->field[1]->store(counters->thread_creations, true);
+ table->field[2]->store(counters->thread_creations_due_to_stall, true);
+ table->field[3]->store(counters->wakes, true);
+ table->field[4]->store(counters->wakes_due_to_stall, true);
+ table->field[5]->store(counters->throttles, true);
+ table->field[6]->store(counters->stalls, true);
+ table->field[7]->store(counters->polls_by_listener, true);
+ table->field[8]->store(counters->polls_by_worker, true);
+ table->field[9]->store(counters->dequeues_by_listener, true);
+ table->field[10]->store(counters->dequeues_by_worker, true);
+ mysql_mutex_unlock(&group->mutex);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int stats_reset_table()
+{
+ for (uint i = 0; i < threadpool_max_size && all_groups[i].pollfd != INVALID_HANDLE_VALUE; i++)
+ {
+ thread_group_t* group = &all_groups[i];
+ mysql_mutex_lock(&group->mutex);
+ memset(&group->counters, 0, sizeof(group->counters));
+ mysql_mutex_unlock(&group->mutex);
+ }
+ return 0;
+}
+
+static int stats_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::stats_fields_info;
+ schema->fill_table = stats_fill_table;
+ schema->reset_table = stats_reset_table;
+ return 0;
+}
+
+
+namespace Show {
+
+static ST_FIELD_INFO waits_fields_info[] =
+{
+ Column("REASON", Varchar(16), NOT_NULL),
+ Column("COUNT", SLonglong(19), NOT_NULL),
+ CEnd()
+};
+
+} // namespace Show
+
+/* See thd_wait_type enum for explanation*/
+static const LEX_CSTRING wait_reasons[THD_WAIT_LAST] =
+{
+ {STRING_WITH_LEN("UNKNOWN")},
+ {STRING_WITH_LEN("SLEEP")},
+ {STRING_WITH_LEN("DISKIO")},
+ {STRING_WITH_LEN("ROW_LOCK")},
+ {STRING_WITH_LEN("GLOBAL_LOCK")},
+ {STRING_WITH_LEN("META_DATA_LOCK")},
+ {STRING_WITH_LEN("TABLE_LOCK")},
+ {STRING_WITH_LEN("USER_LOCK")},
+ {STRING_WITH_LEN("BINLOG")},
+ {STRING_WITH_LEN("GROUP_COMMIT")},
+ {STRING_WITH_LEN("SYNC")},
+ {STRING_WITH_LEN("NET")}
+};
+
+extern Atomic_counter<unsigned long long> tp_waits[THD_WAIT_LAST];
+
+static int waits_fill_table(THD* thd, TABLE_LIST* tables, COND*)
+{
+ if (!all_groups)
+ return 0;
+
+ TABLE* table = tables->table;
+ for (auto i = 0; i < THD_WAIT_LAST; i++)
+ {
+ table->field[0]->store(wait_reasons[i].str, wait_reasons[i].length, system_charset_info);
+ table->field[1]->store(tp_waits[i], true);
+ if (schema_table_store_record(thd, table))
+ return 1;
+ }
+ return 0;
+}
+
+static int waits_reset_table()
+{
+ for (auto i = 0; i < THD_WAIT_LAST; i++)
+ tp_waits[i] = 0;
+
+ return 0;
+}
+
+static int waits_init(void* p)
+{
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*)p;
+ schema->fields_info = Show::waits_fields_info;
+ schema->fill_table = waits_fill_table;
+ schema->reset_table = waits_reset_table;
+ return 0;
+}
+
+static struct st_mysql_information_schema plugin_descriptor =
+{ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+maria_declare_plugin(thread_pool_info)
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_GROUPS",
+ "Vladislav Vaintroub",
+ "Provides information about threadpool groups.",
+ PLUGIN_LICENSE_GPL,
+ groups_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_QUEUES",
+ "Vladislav Vaintroub",
+ "Provides information about threadpool queues.",
+ PLUGIN_LICENSE_GPL,
+ queues_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_STATS",
+ "Vladislav Vaintroub",
+ "Provides performance counter information for threadpool.",
+ PLUGIN_LICENSE_GPL,
+ stats_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &plugin_descriptor,
+ "THREAD_POOL_WAITS",
+ "Vladislav Vaintroub",
+ "Provides wait counters for threadpool.",
+ PLUGIN_LICENSE_GPL,
+ waits_init,
+ 0,
+ 0x0100,
+ NULL,
+ NULL,
+ "1.0",
+ MariaDB_PLUGIN_MATURITY_STABLE
+}
+maria_declare_plugin_end;
diff --git a/sql/threadpool.h b/sql/threadpool.h
index 6299510d002..fe77100a82a 100644
--- a/sql/threadpool.h
+++ b/sql/threadpool.h
@@ -24,16 +24,19 @@ extern uint threadpool_min_threads; /* Minimum threads in pool */
extern uint threadpool_idle_timeout; /* Shutdown idle worker threads after this timeout */
extern uint threadpool_size; /* Number of parallel executing threads */
extern uint threadpool_max_size;
-extern uint threadpool_stall_limit; /* time interval in 10 ms units for stall checks*/
+extern uint threadpool_stall_limit; /* time interval in milliseconds for stall checks*/
extern uint threadpool_max_threads; /* Maximum threads in pool */
extern uint threadpool_oversubscribe; /* Maximum active threads in group */
extern uint threadpool_prio_kickup_timer; /* Time before low prio item gets prio boost */
+extern my_bool threadpool_exact_stats; /* Better queueing time stats for information_schema, at small performance cost */
+extern my_bool threadpool_dedicated_listener; /* Listener thread does not pick up work items. */
#ifdef _WIN32
extern uint threadpool_mode; /* Thread pool implementation , windows or generic */
#define TP_MODE_WINDOWS 0
#define TP_MODE_GENERIC 1
#endif
+#define DEFAULT_THREADPOOL_STALL_LIMIT 500U
struct TP_connection;
extern void tp_callback(TP_connection *c);
@@ -64,8 +67,6 @@ extern int tp_get_thread_count();
/* Activate threadpool scheduler */
extern void tp_scheduler(void);
-extern int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
- enum enum_var_type scope);
enum TP_PRIORITY {
TP_PRIORITY_HIGH,
@@ -88,6 +89,8 @@ enum TP_STATE
inside threadpool_win.cc and threadpool_unix.cc
*/
+class CONNECT;
+
struct TP_connection
{
THD* thd;
diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index cfb831e2f55..ec889851b78 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -23,7 +23,7 @@
#include <sql_audit.h>
#include <debug_sync.h>
#include <threadpool.h>
-
+#include <my_counter.h>
/* Threadpool parameters */
@@ -36,6 +36,8 @@ uint threadpool_max_threads;
uint threadpool_oversubscribe;
uint threadpool_mode;
uint threadpool_prio_kickup_timer;
+my_bool threadpool_exact_stats;
+my_bool threadpool_dedicated_listener;
/* Stats */
TP_STATISTICS tp_stats;
@@ -153,9 +155,8 @@ static TP_PRIORITY get_priority(TP_connection *c)
DBUG_ASSERT(c->thd == current_thd);
TP_PRIORITY prio= (TP_PRIORITY)c->thd->variables.threadpool_priority;
if (prio == TP_PRIORITY_AUTO)
- {
- return c->thd->transaction.is_active() ? TP_PRIORITY_HIGH : TP_PRIORITY_LOW;
- }
+ prio= c->thd->transaction.is_active() ? TP_PRIORITY_HIGH : TP_PRIORITY_LOW;
+
return prio;
}
@@ -381,19 +382,6 @@ end:
}
-
-/* Dummy functions, do nothing */
-
-static bool tp_init_new_connection_thread()
-{
- return 0;
-}
-
-static bool tp_end_thread(THD *, bool)
-{
- return 0;
-}
-
static TP_pool *pool;
static bool tp_init()
@@ -477,12 +465,17 @@ void tp_timeout_handler(TP_connection *c)
mysql_mutex_unlock(&thd->LOCK_thd_kill);
}
+MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) Atomic_counter<unsigned long long> tp_waits[THD_WAIT_LAST];
static void tp_wait_begin(THD *thd, int type)
{
TP_connection *c = get_TP_connection(thd);
if (c)
+ {
+ DBUG_ASSERT(type > 0 && type < THD_WAIT_LAST);
+ tp_waits[type]++;
c->wait_begin(type);
+ }
}
@@ -513,18 +506,16 @@ static scheduler_functions tp_scheduler_functions=
NULL,
NULL,
tp_init, // init
- tp_init_new_connection_thread, // init_new_connection_thread
tp_add_connection, // add_connection
tp_wait_begin, // thd_wait_begin
tp_wait_end, // thd_wait_end
tp_post_kill_notification, // post kill notification
- tp_end_thread, // Dummy function
tp_end // end
};
void pool_of_threads_scheduler(struct scheduler_functions *func,
ulong *arg_max_connections,
- uint *arg_connection_count)
+ Atomic_counter<uint> *arg_connection_count)
{
*func = tp_scheduler_functions;
func->max_threads= threadpool_max_threads;
diff --git a/sql/threadpool_generic.cc b/sql/threadpool_generic.cc
index eb92846ed07..768dbab4e6b 100644
--- a/sql/threadpool_generic.cc
+++ b/sql/threadpool_generic.cc
@@ -13,56 +13,28 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+#if (defined HAVE_POOL_OF_THREADS) && !defined(EMBEDDED_LIBRARY)
+
+#include "threadpool_generic.h"
#include "mariadb.h"
#include <violite.h>
#include <sql_priv.h>
#include <sql_class.h>
#include <my_pthread.h>
#include <scheduler.h>
-
-#ifdef HAVE_POOL_OF_THREADS
-
-#ifdef _WIN32
-/* AIX may define this, too ?*/
-#define HAVE_IOCP
-#endif
-
-#ifdef HAVE_IOCP
-#define OPTIONAL_IO_POLL_READ_PARAM this
-#else
-#define OPTIONAL_IO_POLL_READ_PARAM 0
-#endif
-
-#ifdef _WIN32
-typedef HANDLE TP_file_handle;
-#else
-typedef int TP_file_handle;
-#define INVALID_HANDLE_VALUE -1
-#endif
-
-
#include <sql_connect.h>
#include <mysqld.h>
#include <debug_sync.h>
#include <time.h>
#include <sql_plist.h>
#include <threadpool.h>
-#include <time.h>
-#ifdef __linux__
-#include <sys/epoll.h>
-typedef struct epoll_event native_event;
-#elif defined(HAVE_KQUEUE)
-#include <sys/event.h>
-typedef struct kevent native_event;
-#elif defined (__sun)
-#include <port.h>
-typedef port_event_t native_event;
-#elif defined (HAVE_IOCP)
-typedef OVERLAPPED_ENTRY native_event;
-#else
-#error threadpool is not available on this platform
-#endif
+#include <algorithm>
+#ifdef HAVE_IOCP
+#define OPTIONAL_IO_POLL_READ_PARAM this
+#else
+#define OPTIONAL_IO_POLL_READ_PARAM 0
+#endif
static void io_poll_close(TP_file_handle fd)
{
@@ -119,86 +91,7 @@ static PSI_thread_info thread_list[] =
#define PSI_register(X) /* no-op */
#endif
-
-struct thread_group_t;
-
-/* Per-thread structure for workers */
-struct worker_thread_t
-{
- ulonglong event_count; /* number of request handled by this thread */
- thread_group_t* thread_group;
- worker_thread_t *next_in_list;
- worker_thread_t **prev_in_list;
-
- mysql_cond_t cond;
- bool woken;
-};
-
-typedef I_P_List<worker_thread_t, I_P_List_adapter<worker_thread_t,
- &worker_thread_t::next_in_list,
- &worker_thread_t::prev_in_list>
- >
-worker_list_t;
-
-struct TP_connection_generic:public TP_connection
-{
- TP_connection_generic(CONNECT *c);
- ~TP_connection_generic();
-
- virtual int init(){ return 0; };
- virtual void set_io_timeout(int sec);
- virtual int start_io();
- virtual void wait_begin(int type);
- virtual void wait_end();
-
- thread_group_t *thread_group;
- TP_connection_generic *next_in_queue;
- TP_connection_generic **prev_in_queue;
- ulonglong abs_wait_timeout;
- ulonglong dequeue_time;
- TP_file_handle fd;
- bool bound_to_poll_descriptor;
- int waiting;
-#ifdef HAVE_IOCP
- OVERLAPPED overlapped;
-#endif
-#ifdef _WIN32
- enum_vio_type vio_type;
-#endif
-};
-
-
-typedef I_P_List<TP_connection_generic,
- I_P_List_adapter<TP_connection_generic,
- &TP_connection_generic::next_in_queue,
- &TP_connection_generic::prev_in_queue>,
- I_P_List_null_counter,
- I_P_List_fast_push_back<TP_connection_generic> >
-connection_queue_t;
-
-const int NQUEUES=2; /* We have high and low priority queues*/
-
-struct MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) thread_group_t
-{
- mysql_mutex_t mutex;
- connection_queue_t queues[NQUEUES];
- worker_list_t waiting_threads;
- worker_thread_t *listener;
- pthread_attr_t *pthread_attr;
- TP_file_handle pollfd;
- int thread_count;
- int active_thread_count;
- int connection_count;
- /* Stats for the deadlock detection timer routine.*/
- int io_event_count;
- int queue_event_count;
- ulonglong last_thread_creation_time;
- int shutdown_pipe[2];
- bool shutdown;
- bool stalled;
-};
-
-static thread_group_t *all_groups;
+thread_group_t *all_groups;
static uint group_count;
static int32 shutdown_group_count;
@@ -224,9 +117,9 @@ static pool_timer_t pool_timer;
static void queue_put(thread_group_t *thread_group, TP_connection_generic *connection);
static void queue_put(thread_group_t *thread_group, native_event *ev, int cnt);
-static int wake_thread(thread_group_t *thread_group);
-static int wake_or_create_thread(thread_group_t *thread_group);
-static int create_worker(thread_group_t *thread_group);
+static int wake_thread(thread_group_t *thread_group,bool due_to_stall);
+static int wake_or_create_thread(thread_group_t *thread_group, bool due_to_stall=false);
+static int create_worker(thread_group_t *thread_group, bool due_to_stall);
static void *worker_main(void *param);
static void check_stall(thread_group_t *thread_group);
static void set_next_timeout_check(ulonglong abstime);
@@ -563,11 +456,11 @@ static void queue_init(thread_group_t *thread_group)
static void queue_put(thread_group_t *thread_group, native_event *ev, int cnt)
{
- ulonglong now= pool_timer.current_microtime;
+ ulonglong now= threadpool_exact_stats?microsecond_interval_timer():pool_timer.current_microtime;
for(int i=0; i < cnt; i++)
{
TP_connection_generic *c = (TP_connection_generic *)native_event_get_userdata(&ev[i]);
- c->dequeue_time= now;
+ c->enqueue_time= now;
thread_group->queues[c->priority].push_back(c);
}
}
@@ -681,7 +574,7 @@ void check_stall(thread_group_t *thread_group)
for (;;)
{
c= thread_group->queues[TP_PRIORITY_LOW].front();
- if (c && pool_timer.current_microtime - c->dequeue_time > 1000ULL * threadpool_prio_kickup_timer)
+ if (c && pool_timer.current_microtime - c->enqueue_time > 1000ULL * threadpool_prio_kickup_timer)
{
thread_group->queues[TP_PRIORITY_LOW].remove(c);
thread_group->queues[TP_PRIORITY_HIGH].push_back(c);
@@ -698,7 +591,7 @@ void check_stall(thread_group_t *thread_group)
*/
if (!thread_group->listener && !thread_group->io_event_count)
{
- wake_or_create_thread(thread_group);
+ wake_or_create_thread(thread_group, true);
mysql_mutex_unlock(&thread_group->mutex);
return;
}
@@ -735,7 +628,8 @@ void check_stall(thread_group_t *thread_group)
if (!is_queue_empty(thread_group) && !thread_group->queue_event_count)
{
thread_group->stalled= true;
- wake_or_create_thread(thread_group);
+ TP_INCREMENT_GROUP_COUNTER(thread_group,stalls);
+ wake_or_create_thread(thread_group,true);
}
/* Reset queue event count */
@@ -790,13 +684,13 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
break;
cnt = io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, -1);
-
+ TP_INCREMENT_GROUP_COUNTER(thread_group, polls_by_listener);
if (cnt <=0)
{
DBUG_ASSERT(thread_group->shutdown);
break;
}
-
+
mysql_mutex_lock(&thread_group->mutex);
if (thread_group->shutdown)
@@ -851,7 +745,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
more workers.
*/
- bool listener_picks_event=is_queue_empty(thread_group);
+ bool listener_picks_event=is_queue_empty(thread_group) && !threadpool_dedicated_listener;
queue_put(thread_group, ev, cnt);
if (listener_picks_event)
{
@@ -864,7 +758,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
if(thread_group->active_thread_count==0)
{
/* We added some work items to queue, now wake a worker. */
- if(wake_thread(thread_group))
+ if(wake_thread(thread_group, false))
{
/*
Wake failed, hence groups has no idle threads. Now check if there are
@@ -882,7 +776,7 @@ static TP_connection_generic * listener(worker_thread_t *current_thread,
create thread, but waiting for timer would be an inefficient and
pointless delay.
*/
- create_worker(thread_group);
+ create_worker(thread_group, false);
}
}
}
@@ -919,7 +813,7 @@ static void add_thread_count(thread_group_t *thread_group, int32 count)
per group to prevent deadlocks (one listener + one worker)
*/
-static int create_worker(thread_group_t *thread_group)
+static int create_worker(thread_group_t *thread_group, bool due_to_stall)
{
pthread_t thread_id;
bool max_threads_reached= false;
@@ -942,6 +836,11 @@ static int create_worker(thread_group_t *thread_group)
thread_group->last_thread_creation_time=microsecond_interval_timer();
statistic_increment(thread_created,&LOCK_status);
add_thread_count(thread_group, 1);
+ TP_INCREMENT_GROUP_COUNTER(thread_group,thread_creations);
+ if(due_to_stall)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, thread_creations_due_to_stall);
+ }
}
else
{
@@ -967,23 +866,24 @@ end:
The actual values were not calculated using any scientific methods.
They just look right, and behave well in practice.
-
- TODO: Should throttling depend on thread_pool_stall_limit?
*/
+
+#define THROTTLING_FACTOR (threadpool_stall_limit/std::max(DEFAULT_THREADPOOL_STALL_LIMIT,threadpool_stall_limit))
+
static ulonglong microsecond_throttling_interval(thread_group_t *thread_group)
{
int count= thread_group->thread_count;
- if (count < 4)
+ if (count < 1+ (int)threadpool_oversubscribe)
return 0;
-
+
if (count < 8)
- return 50*1000;
-
+ return 50*1000*THROTTLING_FACTOR;
+
if(count < 16)
- return 100*1000;
-
- return 200*1000;
+ return 100*1000*THROTTLING_FACTOR;
+
+ return 200*100*THROTTLING_FACTOR;
}
@@ -993,15 +893,17 @@ static ulonglong microsecond_throttling_interval(thread_group_t *thread_group)
Worker creation is throttled, so we avoid too many threads
to be created during the short time.
*/
-static int wake_or_create_thread(thread_group_t *thread_group)
+static int wake_or_create_thread(thread_group_t *thread_group, bool due_to_stall)
{
DBUG_ENTER("wake_or_create_thread");
if (thread_group->shutdown)
DBUG_RETURN(0);
- if (wake_thread(thread_group) == 0)
+ if (wake_thread(thread_group, due_to_stall) == 0)
+ {
DBUG_RETURN(0);
+ }
if (thread_group->thread_count > thread_group->connection_count)
DBUG_RETURN(-1);
@@ -1015,7 +917,7 @@ static int wake_or_create_thread(thread_group_t *thread_group)
idle thread to wakeup. Smells like a potential deadlock or very slowly
executing requests, e.g sleeps or user locks.
*/
- DBUG_RETURN(create_worker(thread_group));
+ DBUG_RETURN(create_worker(thread_group, due_to_stall));
}
ulonglong now = microsecond_interval_timer();
@@ -1026,9 +928,10 @@ static int wake_or_create_thread(thread_group_t *thread_group)
if (time_since_last_thread_created >
microsecond_throttling_interval(thread_group))
{
- DBUG_RETURN(create_worker(thread_group));
+ DBUG_RETURN(create_worker(thread_group, due_to_stall));
}
-
+
+ TP_INCREMENT_GROUP_COUNTER(thread_group,throttles);
DBUG_RETURN(-1);
}
@@ -1074,7 +977,7 @@ void thread_group_destroy(thread_group_t *thread_group)
Wake sleeping thread from waiting list
*/
-static int wake_thread(thread_group_t *thread_group)
+static int wake_thread(thread_group_t *thread_group,bool due_to_stall)
{
DBUG_ENTER("wake_thread");
worker_thread_t *thread = thread_group->waiting_threads.front();
@@ -1083,6 +986,11 @@ static int wake_thread(thread_group_t *thread_group)
thread->woken= true;
thread_group->waiting_threads.remove(thread);
mysql_cond_signal(&thread->cond);
+ TP_INCREMENT_GROUP_COUNTER(thread_group, wakes);
+ if (due_to_stall)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, wakes_due_to_stall);
+ }
DBUG_RETURN(0);
}
DBUG_RETURN(1); /* no thread in waiter list => missed wakeup */
@@ -1140,7 +1048,7 @@ static void thread_group_close(thread_group_t *thread_group)
wake_listener(thread_group);
/* Wake all workers. */
- while(wake_thread(thread_group) == 0)
+ while(wake_thread(thread_group, false) == 0)
{
}
@@ -1162,7 +1070,7 @@ static void queue_put(thread_group_t *thread_group, TP_connection_generic *conne
{
DBUG_ENTER("queue_put");
- connection->dequeue_time= pool_timer.current_microtime;
+ connection->enqueue_time= threadpool_exact_stats?microsecond_interval_timer():pool_timer.current_microtime;
thread_group->queues[connection->priority].push_back(connection);
if (thread_group->active_thread_count == 0)
@@ -1224,7 +1132,10 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
{
connection = queue_get(thread_group);
if(connection)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group,dequeues_by_worker);
break;
+ }
}
/* If there is currently no listener in the group, become one. */
@@ -1235,7 +1146,10 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
mysql_mutex_unlock(&thread_group->mutex);
connection = listener(current_thread, thread_group);
-
+ if (connection)
+ {
+ TP_INCREMENT_GROUP_COUNTER(thread_group, dequeues_by_listener);
+ }
mysql_mutex_lock(&thread_group->mutex);
thread_group->active_thread_count++;
/* There is no listener anymore, it just returned. */
@@ -1251,9 +1165,9 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
*/
if (!oversubscribed)
{
-
native_event ev[MAX_EVENTS];
int cnt = io_poll_wait(thread_group->pollfd, ev, MAX_EVENTS, 0);
+ TP_INCREMENT_GROUP_COUNTER(thread_group, polls_by_worker);
if (cnt > 0)
{
queue_put(thread_group, ev, cnt);
@@ -1300,6 +1214,7 @@ TP_connection_generic *get_event(worker_thread_t *current_thread,
}
thread_group->stalled= false;
+
mysql_mutex_unlock(&thread_group->mutex);
DBUG_RETURN(connection);
@@ -1433,14 +1348,13 @@ TP_connection_generic::TP_connection_generic(CONNECT *c):
, overlapped()
#endif
{
- DBUG_ASSERT(c->vio);
+ DBUG_ASSERT(c->vio_type != VIO_CLOSED);
#ifdef _WIN32
- vio_type= c->vio->type;
- fd= (vio_type == VIO_TYPE_NAMEDPIPE) ?
- c->vio->hPipe: (TP_file_handle)mysql_socket_getfd(c->vio->mysql_socket);
+ fd= (c->vio_type == VIO_TYPE_NAMEDPIPE) ?
+ c->pipe: (TP_file_handle) mysql_socket_getfd(c->sock);
#else
- fd= mysql_socket_getfd(c->vio->mysql_socket);
+ fd= mysql_socket_getfd(c->sock);
#endif
/* Assign connection to a group. */
@@ -1516,7 +1430,7 @@ static int change_group(TP_connection_generic *c,
new_group->connection_count++;
/* Ensure that there is a listener in the new group. */
if (!new_group->thread_count)
- ret= create_worker(new_group);
+ ret= create_worker(new_group, false);
mysql_mutex_unlock(&new_group->mutex);
return ret;
}
@@ -1776,4 +1690,6 @@ static void print_pool_blocked_message(bool max_threads_reached)
}
}
+
+
#endif /* HAVE_POOL_OF_THREADS */
diff --git a/sql/threadpool_generic.h b/sql/threadpool_generic.h
new file mode 100644
index 00000000000..4b83e1d796f
--- /dev/null
+++ b/sql/threadpool_generic.h
@@ -0,0 +1,150 @@
+/* Copyright(C) 2019 MariaDB
+ *
+ * This program is free software; you can redistribute itand /or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 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 Street, Fifth Floor, Boston, MA 02111 - 1301 USA*/
+
+#if defined (HAVE_POOL_OF_THREADS)
+#include <my_global.h>
+#include <sql_plist.h>
+#include <my_pthread.h>
+#include <threadpool.h>
+#include <mysqld.h>
+#include <violite.h>
+
+#ifdef _WIN32
+#include <windows.h>
+/* AIX may define this, too ?*/
+#define HAVE_IOCP
+#endif
+
+
+#ifdef _WIN32
+typedef HANDLE TP_file_handle;
+#else
+typedef int TP_file_handle;
+#define INVALID_HANDLE_VALUE -1
+#endif
+
+#ifdef __linux__
+#include <sys/epoll.h>
+typedef struct epoll_event native_event;
+#elif defined(HAVE_KQUEUE)
+#include <sys/event.h>
+typedef struct kevent native_event;
+#elif defined (__sun)
+#include <port.h>
+typedef port_event_t native_event;
+#elif defined (HAVE_IOCP)
+typedef OVERLAPPED_ENTRY native_event;
+#else
+#error threadpool is not available on this platform
+#endif
+
+struct thread_group_t;
+
+/* Per-thread structure for workers */
+struct worker_thread_t
+{
+ ulonglong event_count; /* number of request handled by this thread */
+ thread_group_t* thread_group;
+ worker_thread_t* next_in_list;
+ worker_thread_t** prev_in_list;
+ mysql_cond_t cond;
+ bool woken;
+};
+
+typedef I_P_List<worker_thread_t, I_P_List_adapter<worker_thread_t,
+ & worker_thread_t::next_in_list,
+ & worker_thread_t::prev_in_list>,
+ I_P_List_counter
+>
+worker_list_t;
+
+struct TP_connection_generic :public TP_connection
+{
+ TP_connection_generic(CONNECT* c);
+ ~TP_connection_generic();
+
+ virtual int init() { return 0; };
+ virtual void set_io_timeout(int sec);
+ virtual int start_io();
+ virtual void wait_begin(int type);
+ virtual void wait_end();
+
+ thread_group_t* thread_group;
+ TP_connection_generic* next_in_queue;
+ TP_connection_generic** prev_in_queue;
+ ulonglong abs_wait_timeout;
+ ulonglong enqueue_time;
+ TP_file_handle fd;
+ bool bound_to_poll_descriptor;
+ int waiting;
+#ifdef HAVE_IOCP
+ OVERLAPPED overlapped;
+#endif
+#ifdef _WIN32
+ enum_vio_type vio_type;
+#endif
+};
+
+
+typedef I_P_List<TP_connection_generic,
+ I_P_List_adapter<TP_connection_generic,
+ & TP_connection_generic::next_in_queue,
+ & TP_connection_generic::prev_in_queue>,
+ I_P_List_counter,
+ I_P_List_fast_push_back<TP_connection_generic> >
+ connection_queue_t;
+
+const int NQUEUES = 2; /* We have high and low priority queues*/
+
+struct thread_group_counters_t
+{
+ ulonglong thread_creations;
+ ulonglong thread_creations_due_to_stall;
+ ulonglong wakes;
+ ulonglong wakes_due_to_stall;
+ ulonglong throttles;
+ ulonglong stalls;
+ ulonglong dequeues_by_worker;
+ ulonglong dequeues_by_listener;
+ ulonglong polls_by_listener;
+ ulonglong polls_by_worker;
+};
+
+struct MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) thread_group_t
+{
+ mysql_mutex_t mutex;
+ connection_queue_t queues[NQUEUES];
+ worker_list_t waiting_threads;
+ worker_thread_t* listener;
+ pthread_attr_t* pthread_attr;
+ TP_file_handle pollfd;
+ int thread_count;
+ int active_thread_count;
+ int connection_count;
+ /* Stats for the deadlock detection timer routine.*/
+ int io_event_count;
+ int queue_event_count;
+ ulonglong last_thread_creation_time;
+ int shutdown_pipe[2];
+ bool shutdown;
+ bool stalled;
+ thread_group_counters_t counters;
+};
+
+#define TP_INCREMENT_GROUP_COUNTER(group,var) group->counters.var++;
+
+extern thread_group_t* all_groups;
+#endif
+
diff --git a/sql/threadpool_win.cc b/sql/threadpool_win.cc
index bac4ab9f3b4..50fde8b52b3 100644
--- a/sql/threadpool_win.cc
+++ b/sql/threadpool_win.cc
@@ -31,31 +31,6 @@
#include <threadpool.h>
#include <windows.h>
-
-
-/*
- WEAK_SYMBOL(return_type, function_name, argument_type1,..,argument_typeN)
-
- Declare and load function pointer from kernel32. The name of the static
- variable that holds the function pointer is my_<original function name>
- This should be combined with
- #define <original function name> my_<original function name>
- so that one could use Widows APIs transparently, without worrying whether
- they are present in a particular version or not.
-
- Of course, prior to use of any function there should be a check for correct
- Windows version, or check whether function pointer is not NULL.
-*/
-#define WEAK_SYMBOL(return_type, function, ...) \
- typedef return_type (WINAPI *pFN_##function)(__VA_ARGS__); \
- static pFN_##function my_##function = (pFN_##function) \
- (GetProcAddress(GetModuleHandle("kernel32"),#function))
-
-
-WEAK_SYMBOL(BOOL, SetThreadpoolStackInformation, PTP_POOL,
- PTP_POOL_STACK_INFORMATION);
-#define SetThreadpoolStackInformation my_SetThreadpoolStackInformation
-
/* Log a warning */
static void tp_log_warning(const char *msg, const char *fct)
{
@@ -167,15 +142,14 @@ int TP_connection_win::init()
{
memset(&overlapped, 0, sizeof(OVERLAPPED));
- Vio *vio = connect->vio;
- switch ((vio_type = vio->type))
+ switch ((vio_type = connect->vio_type))
{
case VIO_TYPE_SSL:
case VIO_TYPE_TCPIP:
- handle= (HANDLE)mysql_socket_getfd(vio->mysql_socket);
+ handle= (HANDLE) mysql_socket_getfd(connect->sock);
break;
case VIO_TYPE_NAMEDPIPE:
- handle= (HANDLE)vio->hPipe;
+ handle= connect->pipe;
break;
default:
abort();
@@ -451,19 +425,13 @@ int TP_pool_win::init()
}
}
- /*
- Control stack size (OS must be Win7 or later)
- */
- if (SetThreadpoolStackInformation)
+ TP_POOL_STACK_INFORMATION stackinfo;
+ stackinfo.StackCommit = 0;
+ stackinfo.StackReserve = (SIZE_T)my_thread_stack_size;
+ if (!SetThreadpoolStackInformation(pool, &stackinfo))
{
- TP_POOL_STACK_INFORMATION stackinfo;
- stackinfo.StackCommit = 0;
- stackinfo.StackReserve = (SIZE_T)my_thread_stack_size;
- if (!SetThreadpoolStackInformation(pool, &stackinfo))
- {
- tp_log_warning("Can't set threadpool stack size",
- "SetThreadpoolStackInformation");
- }
+ tp_log_warning("Can't set threadpool stack size",
+ "SetThreadpoolStackInformation");
}
return 0;
}
diff --git a/sql/unireg.cc b/sql/unireg.cc
index d019b5f8a75..7130b3e5d8a 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -152,6 +152,80 @@ static size_t extra2_str_size(size_t len)
return (len > 255 ? 3 : 1) + len;
}
+
+static uint gis_field_options_image(uchar *buff,
+ List<Create_field> &create_fields)
+{
+ uint image_size= 0;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
+ while ((field= it++))
+ {
+ if (field->real_field_type() != MYSQL_TYPE_GEOMETRY)
+ continue;
+ uchar *cbuf= buff ? buff + image_size : NULL;
+ image_size+= field->type_handler()->
+ Column_definition_gis_options_image(cbuf, *field);
+ }
+ return image_size;
+}
+
+
+class Field_data_type_info_image: public BinaryStringBuffer<512>
+{
+ static uchar *store_length(uchar *pos, ulonglong length)
+ {
+ return net_store_length(pos, length);
+ }
+ static uchar *store_string(uchar *pos, const LEX_CSTRING &str)
+ {
+ pos= store_length(pos, str.length);
+ memcpy(pos, str.str, str.length);
+ return pos + str.length;
+ }
+ static uint store_length_required_length(ulonglong length)
+ {
+ return net_length_size(length);
+ }
+public:
+ Field_data_type_info_image() { }
+ bool append(uint fieldnr, const Column_definition &def)
+ {
+ BinaryStringBuffer<64> type_info;
+ if (def.type_handler()->
+ Column_definition_data_type_info_image(&type_info, def) ||
+ type_info.length() > 0xFFFF/*Some reasonable limit*/)
+ return true; // Error
+ if (!type_info.length())
+ return false;
+ size_t need_length= store_length_required_length(fieldnr) +
+ store_length_required_length(type_info.length()) +
+ type_info.length();
+ if (reserve(need_length))
+ return true; // Error
+ uchar *pos= (uchar *) end();
+ pos= store_length(pos, fieldnr);
+ pos= store_string(pos, type_info.lex_cstring());
+ size_t new_length= (const char *) pos - ptr();
+ DBUG_ASSERT(new_length < alloced_length());
+ length((uint32) new_length);
+ return false;
+ }
+ bool append(List<Create_field> &fields)
+ {
+ uint fieldnr= 0;
+ Create_field *field;
+ List_iterator<Create_field> it(fields);
+ for (field= it++; field; field= it++, fieldnr++)
+ {
+ if (append(fieldnr, *field))
+ return true; // Error
+ }
+ return false;
+ }
+};
+
+
/**
Create a frm (table definition) file
@@ -191,6 +265,7 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
uchar *frm_ptr, *pos;
LEX_CUSTRING frm= {0,0};
StringBuffer<MAX_FIELD_WIDTH> vcols;
+ Field_data_type_info_image field_data_type_info_image;
DBUG_ENTER("build_frm_image");
/* If fixed row records, we need one bit to check for deleted rows */
@@ -241,11 +316,25 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
options_len= engine_table_options_frm_length(create_info->option_list,
create_fields,
keys, key_info);
-#ifdef HAVE_SPATIAL
gis_extra2_len= gis_field_options_image(NULL, create_fields);
-#endif /*HAVE_SPATIAL*/
DBUG_PRINT("info", ("Options length: %u", options_len));
+ if (field_data_type_info_image.append(create_fields))
+ {
+ my_printf_error(ER_CANT_CREATE_TABLE,
+ "Cannot create table %`s: "
+ "Building the field data type info image failed.",
+ MYF(0), table.str);
+ DBUG_RETURN(frm);
+ }
+ DBUG_PRINT("info", ("Field data type info length: %u",
+ (uint) field_data_type_info_image.length()));
+ DBUG_EXECUTE_IF("frm_data_type_info",
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_UNKNOWN_ERROR,
+ "build_frm_image: Field data type info length: %u",
+ (uint) field_data_type_info_image.length()););
+
if (validate_comment_length(thd, &create_info->comment, TABLE_COMMENT_MAXLEN,
ER_TOO_LONG_TABLE_COMMENT, table.str))
DBUG_RETURN(frm);
@@ -291,6 +380,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
if (gis_extra2_len)
extra2_size+= 1 + extra2_str_size(gis_extra2_len);
+ if (field_data_type_info_image.length())
+ extra2_size+= 1 + extra2_str_size(field_data_type_info_image.length());
+
if (create_info->versioned())
{
extra2_size+= 1 + extra2_str_size(2 * frm_fieldno_size);
@@ -356,14 +448,28 @@ LEX_CUSTRING build_frm_image(THD *thd, const LEX_CSTRING &table,
create_fields, keys, key_info);
}
-#ifdef HAVE_SPATIAL
if (gis_extra2_len)
{
*pos= EXTRA2_GIS;
pos= extra2_write_len(pos+1, gis_extra2_len);
pos+= gis_field_options_image(pos, create_fields);
}
-#endif /*HAVE_SPATIAL*/
+
+ if (field_data_type_info_image.length())
+ {
+ if (field_data_type_info_image.length() > 0xFFFF)
+ {
+ my_printf_error(ER_CANT_CREATE_TABLE,
+ "Cannot create table %`s: "
+ "field data type info image is too large. "
+ "Decrease the number of columns with "
+ "extended data types.",
+ MYF(0), table.str);
+ goto err;
+ }
+ *pos= EXTRA2_FIELD_DATA_TYPE_INFO;
+ pos= extra2_write_str(pos + 1, field_data_type_info_image.lex_cstring());
+ }
// PERIOD
if (create_info->period_info.is_set())
@@ -722,6 +828,7 @@ static bool pack_header(THD *thd, uchar *forminfo,
if (field->charset->mbminlen > 1)
{
+ TYPELIB *tmpint;
/*
Escape UCS2 intervals using HEX notation to avoid
problems with delimiters between enum elements.
@@ -730,16 +837,17 @@ static bool pack_header(THD *thd, uchar *forminfo,
filled with default values it is saved in save_interval
The HEX representation is created from this copy.
*/
+ uint count= field->interval->count;
field->save_interval= field->interval;
- field->interval= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
- *field->interval= *field->save_interval;
- field->interval->type_names=
- (const char **) thd->alloc(sizeof(char*) *
- (field->interval->count+1));
- field->interval->type_names[field->interval->count]= 0;
- field->interval->type_lengths=
- (uint *) thd->alloc(sizeof(uint) * field->interval->count);
-
+ field->interval= tmpint= (TYPELIB*) thd->alloc(sizeof(TYPELIB));
+ *tmpint= *field->save_interval;
+ tmpint->type_names=
+ (const char **) thd->alloc(sizeof(char*) *
+ (count + 1));
+ tmpint->type_lengths= (uint *) thd->alloc(sizeof(uint) * (count + 1));
+ tmpint->type_names[count]= 0;
+ tmpint->type_lengths[count]= 0;
+
for (uint pos= 0; pos < field->interval->count; pos++)
{
char *dst;
@@ -747,9 +855,8 @@ static bool pack_header(THD *thd, uchar *forminfo,
size_t hex_length;
length= field->save_interval->type_lengths[pos];
hex_length= length * 2;
- field->interval->type_lengths[pos]= (uint)hex_length;
- field->interval->type_names[pos]= dst=
- (char*) thd->alloc(hex_length + 1);
+ tmpint->type_lengths[pos]= (uint) hex_length;
+ tmpint->type_names[pos]= dst= (char*) thd->alloc(hex_length + 1);
octet2hex(dst, src, length);
}
}
@@ -813,7 +920,7 @@ static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
{
List_iterator<Create_field> it(create_fields);
Create_field *field;
- TYPELIB *interval=last_field->interval;
+ const TYPELIB *interval= last_field->interval;
while ((field=it++) != last_field)
{
diff --git a/sql/unireg.h b/sql/unireg.h
index 8e9fa27ea6a..419fbc4bd80 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -176,7 +176,8 @@ enum extra2_frm_value_type {
#define EXTRA2_ENGINE_IMPORTANT 128
EXTRA2_ENGINE_TABLEOPTS=128,
- EXTRA2_FIELD_FLAGS=129
+ EXTRA2_FIELD_FLAGS=129,
+ EXTRA2_FIELD_DATA_TYPE_INFO=130
};
enum extra2_field_flags {
diff --git a/sql/vers_string.h b/sql/vers_string.h
index 2349cc0cac1..bde3f0dffed 100644
--- a/sql/vers_string.h
+++ b/sql/vers_string.h
@@ -17,6 +17,8 @@
#ifndef VERS_STRING_INCLUDED
#define VERS_STRING_INCLUDED
+#include "lex_string.h"
+
/*
LEX_CSTRING with comparison semantics.
*/
@@ -45,31 +47,6 @@ struct Compare_identifiers
}
};
-class Lex_cstring : public LEX_CSTRING
-{
- public:
- Lex_cstring()
- {
- str= NULL;
- length= 0;
- }
- Lex_cstring(const char *_str, size_t _len)
- {
- str= _str;
- length= _len;
- }
- Lex_cstring(const char *start, const char *end)
- {
- DBUG_ASSERT(start <= end);
- str= start;
- length= end - start;
- }
- void set(const char *_str, size_t _len)
- {
- str= _str;
- length= _len;
- }
-};
template <class Compare>
struct Lex_cstring_with_compare : public Lex_cstring
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index 74a28c4724f..128d80ad226 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -2636,13 +2636,6 @@ void* start_wsrep_THD(void *arg)
mysql_thread_set_psi_id(thd->thread_id);
thd->thr_create_utime= microsecond_interval_timer();
- if (MYSQL_CALLBACK_ELSE(thread_scheduler, init_new_connection_thread, (), 0))
- {
- close_connection(thd, ER_OUT_OF_RESOURCES);
- statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
- goto error;
- }
// </5.1.17>
/*
@@ -2662,7 +2655,7 @@ void* start_wsrep_THD(void *arg)
{
close_connection(thd, ER_OUT_OF_RESOURCES);
statistic_increment(aborted_connects,&LOCK_status);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 0));
+ unlink_thd(thd);
delete thd;
delete thd_args;
goto error;
@@ -2739,7 +2732,7 @@ void* start_wsrep_THD(void *arg)
if (plugins_are_initialized)
{
net_end(&thd->net);
- MYSQL_CALLBACK(thread_scheduler, end_thread, (thd, 1));
+ unlink_thd(thd);
}
else
{
@@ -2748,9 +2741,9 @@ void* start_wsrep_THD(void *arg)
'Error in my_thread_global_end(): 2 threads didn't exit'
at server shutdown
*/
+ server_threads.erase(thd);
}
- server_threads.erase(thd);
delete thd;
my_thread_end();
return(NULL);
diff --git a/sql/xa.cc b/sql/xa.cc
index c4b983aa4f5..e30c3bfadba 100644
--- a/sql/xa.cc
+++ b/sql/xa.cc
@@ -814,7 +814,7 @@ static my_bool xa_recover_callback_verbose(XID_cache_element *xs,
char buf[SQL_XIDSIZE];
uint len= get_sql_xid(&xs->xid, buf);
return xa_recover_callback(xs, protocol, buf, len,
- &my_charset_utf8_general_ci);
+ &my_charset_utf8mb3_general_ci);
}
@@ -842,7 +842,7 @@ bool mysql_xa_recover(THD *thd)
if (thd->lex->verbose)
{
len= SQL_XIDSIZE;
- cs= &my_charset_utf8_general_ci;
+ cs= &my_charset_utf8mb3_general_ci;
action= (my_hash_walk_action) xa_recover_callback_verbose;
}
else